From 7f6a53e746a91b7e8383021fef09d8a9fe5cdde8 Mon Sep 17 00:00:00 2001 From: Pramod Bisht Date: Sat, 27 Jan 2018 20:00:59 +0530 Subject: [PATCH 01/87] Changed color of struct link from #ff794d to #2dbfb8 --- src/librustdoc/html/static/themes/dark.css | 2 +- src/librustdoc/html/static/themes/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 4c6bcab72b7c..97a4dba6328f 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -127,7 +127,7 @@ pre { .content .highlighted.primitive { background-color: #00708a; } .content span.enum, .content a.enum, .block a.current.enum { color: #82b089; } -.content span.struct, .content a.struct, .block a.current.struct { color: #ff794d; } +.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ff7f00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; } .content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; } diff --git a/src/librustdoc/html/static/themes/main.css b/src/librustdoc/html/static/themes/main.css index e0764640e916..a346439da6e6 100644 --- a/src/librustdoc/html/static/themes/main.css +++ b/src/librustdoc/html/static/themes/main.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #9aecff; } .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #df3600; } +.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } From c01bfbd02b57a1aa9d8a39cd907f799d23c2a230 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 12 Dec 2017 14:50:09 -0200 Subject: [PATCH 02/87] refactor `structurally_resolve_type` the `or_else` part was dead code. --- src/librustc_typeck/check/mod.rs | 44 ++++++++++---------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6147743437b8..cb80498f3e20 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4954,39 +4954,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) - -> Ty<'tcx> - where F: Fn() -> Ty<'tcx> - { - let mut ty = self.resolve_type_vars_with_obligations(ty); - - if ty.is_ty_var() { - let alternative = f(); - - // If not, error. - if alternative.is_ty_var() || alternative.references_error() { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; - } else { - self.demand_suptype(sp, alternative, ty); - ty = alternative; - } - } - - ty - } - - // Resolves `typ` by a single level if `typ` is a type variable. If no + // Resolves `typ` by a single level if `typ` is a type variable. If no // resolution is possible, then an error is reported. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - self.structurally_resolve_type_or_else(sp, ty, || { - self.tcx.types.err - }) + let mut ty = self.resolve_type_vars_with_obligations(ty); + if ty.is_ty_var() { + // If not, error. + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + ty = self.tcx.types.err; + } + ty } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, From 3d83fc914a0f116ad0e4412d5ccc0be24b3b7af2 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 12:35:26 -0200 Subject: [PATCH 03/87] Lazy numeric fallback. This refactoring tries to make numeric fallback easier to reason about. Instead of applying all fallbacks at an arbitrary point in the middle of inference, we apply the fallback only when necessary and only for the variable that requires it, which for numeric fallback turns out to be just casts. The only visible consequence seems to be some error messages where instead of getting `i32` we get `{integer}` because we are less eager about fallback. The bigger goal is to make it easier to integrate user fallbacks into inference, if we ever figure that out. --- src/librustc/ty/sty.rs | 7 ++ src/librustc_typeck/check/cast.rs | 4 +- src/librustc_typeck/check/mod.rs | 110 +++++++++++------- .../derived-errors/issue-31997.rs | 4 +- .../interior-mutability.stderr | 12 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- 6 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index db7e4fe45ef7..d38ceb619e3c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1290,6 +1290,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_ty_infer(&self) -> bool { + match self.sty { + TyInfer(_) => true, + _ => false, + } + } + pub fn is_phantom_data(&self) -> bool { if let TyAdt(def, _) = self.sty { def.is_phantom_data() diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 48bd7b14fc96..bc157d6feeaf 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -392,8 +392,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); + self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cb80498f3e20..aff96e39cfc7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze(body); fcx.select_obligations_where_possible(); + fcx.closure_analyze(body); fcx.check_casts(); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2129,13 +2128,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether + /// unconstrained types get replaced with ! or () (depending on whether /// feature(never_type) is enabled), unconstrained ints with i32, and /// unconstrained floats with f64. fn default_type_parameters(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. Therefore, if we think we saw // some errors in this function, just resolve all uninstanted type @@ -2152,34 +2148,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for ty in &self.unsolved_variables() { let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - debug!("default_type_parameters: defaulting `{:?}` to `i32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - debug!("default_type_parameters: defaulting `{:?}` to `f32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64) - } - Neither => { } - } + if resolved.is_ty_infer() { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); } } } - // Implements type inference fallback algorithm - fn select_all_obligations_and_apply_defaults(&self) { - self.select_obligations_where_possible(); - self.default_type_parameters(); - self.select_obligations_where_possible(); + fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { + assert!(ty.is_ty_infer()); + if self.type_var_diverges(ty) { + debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); + } + } + + fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither => return, + }; + debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); } fn select_all_obligations_or_error(&self) { @@ -2189,7 +2184,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // resolutions are handled by now. assert!(self.deferred_call_resolutions.borrow().is_empty()); - self.select_all_obligations_and_apply_defaults(); + self.select_obligations_where_possible(); + self.default_type_parameters(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4954,21 +4950,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - // Resolves `typ` by a single level if `typ` is a type variable. If no - // resolution is possible, then an error is reported. + // Resolves `typ` by a single level if `typ` is a type variable. + // If no resolution is possible, then an error is reported. + // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_type_vars_with_obligations(ty); - if ty.is_ty_var() { - // If not, error. - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); + if !ty.is_ty_var() { + ty + } else { + // Try divering fallback. + self.apply_diverging_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; } - ty + } + + // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. + pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let mut ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + return ty; + } else { + // Try diverging or numeric fallback. + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) + } + } + } + + fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 2e1d3c55a8f4..0385e3b8365d 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,7 +20,9 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope + try!(closure(|| bar(0 as *mut _))); + //~^ ERROR cannot find function `bar` in this scope + //~^^ ERROR cannot cast to a pointer of an unknown kind Ok(()) } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index f4beb44b82dc..dca9ab1b5415 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` +error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` + = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` + = note: required because it appears within the type `std::cell::Cell<{integer}>` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 5d25cb2f93c1..1b056486ad95 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `{integer}` as `()` +error[E0605]: non-primitive cast: `i32` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast From f3cd4a7f64c50ff5935f4d507ae1103c93b8a2ad Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 13:56:57 -0200 Subject: [PATCH 04/87] Refactor away `fn default_type_parameters` It had only one caller. --- src/librustc_typeck/check/mod.rs | 46 ++++++++++++-------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aff96e39cfc7..666b8e06522e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,34 +2127,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether - /// feature(never_type) is enabled), unconstrained ints with i32, and - /// unconstrained floats with f64. - fn default_type_parameters(&self) { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. Therefore, if we think we saw - // some errors in this function, just resolve all uninstanted type - // varibles to TyError. - if self.is_tainted_by_errors() { - for ty in &self.unsolved_variables() { - if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } - } - return; - } - - for ty in &self.unsolved_variables() { - let resolved = self.resolve_type_vars_if_possible(ty); - if resolved.is_ty_infer() { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } - } - } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { assert!(ty.is_ty_infer()); if self.type_var_diverges(ty) { @@ -2185,7 +2157,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(self.deferred_call_resolutions.borrow().is_empty()); self.select_obligations_where_possible(); - self.default_type_parameters(); + + // Apply fallbacks to unsolved variables. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + for ty in &self.unsolved_variables() { + if self.is_tainted_by_errors() { + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, + // just resolve all uninstanted type variables to TyError. + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); + } else { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + } + } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); From 02084f3304acfa68e79d213a5ebd1c3478680741 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 18 Dec 2017 17:31:23 -0200 Subject: [PATCH 05/87] No fallback in `structurally_resolve_types`. Further refactoring. Put all fallback in `apply_fallback_if_possible`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 50 ++++++------------- .../{issue-26480.rs => issue-26480-1.rs} | 6 +-- .../ui/mismatched_types/issue-26480-1.stderr | 11 ++++ src/test/ui/mismatched_types/issue-26480-2.rs | 18 +++++++ .../ui/mismatched_types/issue-26480-2.stderr | 13 +++++ .../ui/mismatched_types/issue-26480.stderr | 13 +---- 7 files changed, 59 insertions(+), 54 deletions(-) rename src/test/ui/mismatched_types/{issue-26480.rs => issue-26480-1.rs} (91%) create mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr create mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs create mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bc157d6feeaf..631f7a740c4b 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -393,7 +393,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); + self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 666b8e06522e..610510c5c74e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,23 +2127,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { - assert!(ty.is_ty_infer()); - if self.type_var_diverges(ty) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); - } - } - - fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, fallback to TyError. + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; assert!(ty.is_ty_infer()); let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither => return, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); @@ -2158,21 +2158,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); - // Apply fallbacks to unsolved variables. - // Non-numerics get replaced with ! or () (depending on whether - // feature(never_type) is enabled), unconstrained ints with i32, - // unconstrained floats with f64. for ty in &self.unsolved_variables() { - if self.is_tainted_by_errors() { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, - // just resolve all uninstanted type variables to TyError. - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } else { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } + self.apply_fallback_if_possible(ty); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4942,18 +4929,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); + let ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_var() { ty } else { - // Try divering fallback. - self.apply_diverging_fallback_to_type(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } + self.must_be_known_in_context(sp, ty) } } @@ -4963,9 +4943,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_infer() { return ty; } else { - // Try diverging or numeric fallback. - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); + self.apply_fallback_if_possible(ty); ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_infer() { ty diff --git a/src/test/ui/mismatched_types/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480-1.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480.rs rename to src/test/ui/mismatched_types/issue-26480-1.rs index 33c5e74fafa1..36a30ccb0fc3 100644 --- a/src/test/ui/mismatched_types/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480-1.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -28,12 +29,7 @@ macro_rules! write { }} } -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - fn main() { let hello = ['H', 'e', 'y']; write!(hello); - cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr new file mode 100644 index 000000000000..326b427b0fbe --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-1.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-26480-1.rs:27:19 + | +27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize +... +34 | write!(hello); + | -------------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs new file mode 100644 index 000000000000..7015e5909e9b --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + +fn main() { + cast!(2); +} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr new file mode 100644 index 000000000000..3f6dcccdedb4 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.stderr @@ -0,0 +1,13 @@ +error[E0605]: non-primitive cast: `i32` as `()` + --> $DIR/issue-26480-2.rs:13:19 + | +13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +17 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 1b056486ad95..27698c864c3f 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,16 +7,5 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480.rs:32:19 - | -32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -38 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error From 4c0ff95e6ecd861741e868cc729afe0339a4b8c7 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 07:40:54 -0200 Subject: [PATCH 06/87] Be more explicit about how and why we need fallback in targets of casts --- src/librustc_typeck/check/cast.rs | 10 +++++++-- src/librustc_typeck/check/mod.rs | 29 +++++++++---------------- src/test/run-pass/cast-does-fallback.rs | 16 ++++++++++++++ 3 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/cast-does-fallback.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 631f7a740c4b..8dde3d7ab98a 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, FnCtxt}; +use super::{Diverges, Fallback, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -392,7 +392,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + // For backwards compatibility we apply numeric fallback here. This means that in: + // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. + if self.expr_ty.is_ty_infer() { + fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 610510c5c74e..e97de581173d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1724,6 +1724,12 @@ enum TupleArgumentsFlag { TupleArguments, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Fallback { + Full, + Numeric +} + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2133,7 +2139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2142,7 +2148,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) && fallback == Fallback::Full + => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); @@ -2159,7 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty); + self.apply_fallback_if_possible(ty, Fallback::Full); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4937,22 +4944,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. - pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - return ty; - } else { - self.apply_fallback_if_possible(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } - } - } - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { if !self.is_tainted_by_errors() { type_error_struct!(self.tcx.sess, sp, ty, E0619, diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs new file mode 100644 index 000000000000..86d6e387b255 --- /dev/null +++ b/src/test/run-pass/cast-does-fallback.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let cap = 512 * 512; + cap as u8; + // Assert `cap` did not get inferred to `u8` and overflowed. + assert_ne!(cap, 0); +} From cd4de4cece143e8dbaeeff93492afcbb356d3051 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 18 Jan 2018 10:38:33 -0200 Subject: [PATCH 07/87] Suppress unknown cast errors in the presence of other errors. --- src/librustc_typeck/check/cast.rs | 3 +++ src/librustc_typeck/check/mod.rs | 8 ++++++-- .../compile-fail/derived-errors/issue-31997.rs | 4 +--- src/test/ui/issue-45730.rs | 4 ++++ src/test/ui/issue-45730.stderr | 8 ++++---- .../ui/mismatched_types/issue-26480-1.stderr | 11 ----------- src/test/ui/mismatched_types/issue-26480-2.rs | 18 ------------------ .../ui/mismatched_types/issue-26480-2.stderr | 13 ------------- .../{issue-26480-1.rs => issue-26480.rs} | 6 +++++- .../ui/mismatched_types/issue-26480.stderr | 13 ++++++++++++- 10 files changed, 35 insertions(+), 53 deletions(-) delete mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr rename src/test/ui/mismatched_types/{issue-26480-1.rs => issue-26480.rs} (91%) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 8dde3d7ab98a..2978921fc620 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -290,6 +290,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { + if fcx.is_tainted_by_errors() { + return; + } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e97de581173d..57e40ec19af7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2148,8 +2148,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) && fallback == Fallback::Full - => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) => { + match fallback { + Fallback::Full => self.tcx.mk_diverging_default(), + Fallback::Numeric => return, + } + } Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 0385e3b8365d..2e1d3c55a8f4 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,9 +20,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); - //~^ ERROR cannot find function `bar` in this scope - //~^^ ERROR cannot cast to a pointer of an unknown kind + try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index d733c8e6de26..1fe0b1ae2d24 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,9 +11,13 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast +} +fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; +} +fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 94d39239117a..13205eead436 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:15:23 + --> $DIR/issue-45730.rs:17:23 | -15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:18:13 + --> $DIR/issue-45730.rs:22:13 | -18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr deleted file mode 100644 index 326b427b0fbe..000000000000 --- a/src/test/ui/mismatched_types/issue-26480-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-26480-1.rs:27:19 - | -27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -... -34 | write!(hello); - | -------------- in this macro invocation - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs deleted file mode 100644 index 7015e5909e9b..000000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// compile-flags: --error-format=human - -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - -fn main() { - cast!(2); -} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr deleted file mode 100644 index 3f6dcccdedb4..000000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480-2.rs:13:19 - | -13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -17 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-1.rs b/src/test/ui/mismatched_types/issue-26480.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480-1.rs rename to src/test/ui/mismatched_types/issue-26480.rs index 36a30ccb0fc3..33c5e74fafa1 100644 --- a/src/test/ui/mismatched_types/issue-26480-1.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -29,7 +28,12 @@ macro_rules! write { }} } +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + fn main() { let hello = ['H', 'e', 'y']; write!(hello); + cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 27698c864c3f..5d25cb2f93c1 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,5 +7,16 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error: aborting due to previous error +error[E0605]: non-primitive cast: `{integer}` as `()` + --> $DIR/issue-26480.rs:32:19 + | +32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +38 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to 2 previous errors From f8c140465f20217913f14b7423f7110d0cc7b57c Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 15:42:23 -0200 Subject: [PATCH 08/87] Only closure analysis should run after fallback. Move `check_casts` and `resolve_generator_interiors` to before fallback. Rename `apply_fallback_if_possible` to `fallback_if_possible`. Refactor `select_all_obligations_or_error`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 38 +++++++++---------- .../interior-mutability.stderr | 12 +++--- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2978921fc620..dae5ba14bfb5 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -399,7 +399,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // For backwards compatibility we apply numeric fallback here. This means that in: // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. if self.expr_ty.is_ty_infer() { - fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 57e40ec19af7..b1645ed92283 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_obligations_where_possible(); - fcx.closure_analyze(body); fcx.check_casts(); + + // All type checking constraints were added, try to fallback unsolved variables. + fcx.select_obligations_where_possible(); + for ty in &fcx.unsolved_variables() { + fcx.fallback_if_possible(ty, Fallback::Full); + } + fcx.select_obligations_where_possible(); + + // Closure and generater analysis may run after fallback + // because they doen't constrain other type variables. + fcx.closure_analyze(body); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2137,9 +2147,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Non-numerics get replaced with ! or () (depending on whether // feature(never_type) is enabled), unconstrained ints with i32, // unconstrained floats with f64. - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to TyError. + fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2162,22 +2172,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - - self.select_obligations_where_possible(); - - for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty, Fallback::Full); - } - - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); - - match fulfillment_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id); } } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index dca9ab1b5415..f4beb44b82dc 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` +error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` - = note: required because it appears within the type `std::cell::Cell<{integer}>` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` + = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` + = note: required because it appears within the type `std::cell::Cell` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error From b813718f6dff49b851fcd18a5674640554bda2e5 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 18:17:44 -0200 Subject: [PATCH 09/87] Refactor away `fn must_be_known_in_context` --- src/librustc_typeck/check/mod.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b1645ed92283..0395b3eb4aa2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4940,20 +4940,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_var() { ty } else { - self.must_be_known_in_context(sp, ty) + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } } - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - self.tcx.types.err - } - fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, ctxt: BreakableCtxt<'gcx, 'tcx>, f: F) -> (BreakableCtxt<'gcx, 'tcx>, R) { From c04d86deeb6d23d8ee4b31abda92bb84c1d17897 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 29 Jan 2018 11:07:11 +0100 Subject: [PATCH 10/87] Work around LLVM OCAML binding installation failure --- src/bootstrap/native.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 3f30756a568c..bb482813a23f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,6 +155,7 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); From 434bfb17b4286422b5e3177650aabfd2567b4a19 Mon Sep 17 00:00:00 2001 From: Pramod Bisht Date: Wed, 31 Jan 2018 21:51:27 +0530 Subject: [PATCH 11/87] Changed of `struct` url to `#ad448e` in rust docs --- src/librustdoc/html/static/themes/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/themes/main.css b/src/librustdoc/html/static/themes/main.css index a346439da6e6..2334a2728554 100644 --- a/src/librustdoc/html/static/themes/main.css +++ b/src/librustdoc/html/static/themes/main.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #9aecff; } .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } +.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } From b439632a759447eb56a0190f6c838934bad1e3c7 Mon Sep 17 00:00:00 2001 From: panicbit Date: Sun, 4 Feb 2018 20:40:39 +0100 Subject: [PATCH 12/87] Unimplement Send/Sync for ::env::{Args,ArgsOs,Vars,VarsOs} --- src/libstd/env.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27bf326631fb..c4946b6b2824 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,6 +723,12 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for Args {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for Args {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; @@ -754,6 +760,12 @@ impl fmt::Debug for Args { } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for ArgsOs {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for ArgsOs {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; From 9bc59865f1042b8c6f3a7c69f0d2643b37a41d75 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 08:56:27 +0000 Subject: [PATCH 13/87] 38880 don't compute hash when searching an empty HashMap This addresses issue #38880 --- src/libstd/collections/hash/map.rs | 42 +++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 82a687ae5e49..74c4382f16a5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,9 +397,21 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } -/// Search for a pre-hashed key. +/// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ + // Do not check the capacity as an extra branch could slow the lookup. + search_hashed_body(table, hash, is_match) +} + +/// Search for a pre-hashed key. +/// If you don't already know the hash, use search or search_mut instead +#[inline] +fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { @@ -410,6 +422,16 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } + search_hashed_body(table, hash, is_match) +} + +/// The body of the search_hashed[_nonempty] functions +#[inline] +fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; @@ -550,8 +572,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } #[inline] @@ -559,8 +585,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } // The caller should ensure that invariants by Robin Hood Hashing hold From dcdd2c42d3c7f6125583bcdf0c5ed7e1ef7086db Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 14:16:54 +0000 Subject: [PATCH 14/87] 38880 use search_mut function rather than search_hashed --- src/libstd/collections/hash/map.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 74c4382f16a5..04c9f617d019 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1039,9 +1039,7 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - let hash = self.make_hash(&key); - search_hashed(&mut self.table, hash, |q| q.eq(&key)) - .into_entry(key).expect("unreachable") + self.search_mut(&key).into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. From f5c55ff379913b7acca2ae032120e74aaa4dd822 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Thu, 12 Oct 2017 17:38:44 +0000 Subject: [PATCH 15/87] support `default impl` for specialization a `default impl` need not include all items from the trait a `default impl` alone does not mean that a type implements the trait --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/traits/select.rs | 36 +++++- src/librustc/traits/util.rs | 25 +++- src/librustc/ty/instance.rs | 121 +++++++++++++++++- src/librustc/ty/mod.rs | 39 +++++- src/librustc/ty/structural_impls.rs | 6 +- src/librustc/ty/sty.rs | 5 +- src/librustc/util/ppaux.rs | 8 +- src/librustc_mir/monomorphize/collector.rs | 17 ++- src/librustc_typeck/astconv.rs | 16 ++- src/librustc_typeck/check/dropck.rs | 12 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 31 ++++- src/librustc_typeck/collect.rs | 52 ++++++-- .../defaultimpl/auxiliary/foo_trait.rs | 16 +++ .../auxiliary/foo_trait_default_impl.rs | 22 ++++ ...method-not-implemented-cross-crate-impl.rs | 23 ++++ ...tion-method-not-implemented-cross-crate.rs | 30 +++++ .../specialization-method-not-implemented.rs | 30 +++++ .../specialization-trait-bounds-casting.rs | 47 +++++++ .../specialization-trait-bounds-fn.rs | 34 +++++ .../specialization-trait-bounds-impl-item.rs | 38 ++++++ ...specialization-trait-bounds-super-trait.rs | 40 ++++++ .../specialization-trait-bounds-trait-item.rs | 34 +++++ .../specialization-trait-bounds-vec.rs | 48 +++++++ .../defaultimpl/auxiliary/foo_trait.rs | 30 +++++ .../specialization-trait-bounds.rs | 40 ++++++ ...-traits-impl-default-method-cross-crate.rs | 25 ++++ ...ecialization-traits-impl-default-method.rs | 38 ++++++ .../defaultimpl/specialization-traits-impl.rs | 35 +++++ 30 files changed, 870 insertions(+), 33 deletions(-) create mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 107779ec3fa1..42724274eb70 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -218,7 +218,8 @@ impl_stable_hash_for!(enum ty::Visibility { }); impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); -impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(enum ty::DefaultImplCheck { Yes, No }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref, default_impl_check }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d436..ee6bf4180dda 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1083,12 +1083,39 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Treat negative impls as unimplemented - fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + fn filter_negative_and_default_impls<'o>(&self, + candidate: SelectionCandidate<'tcx>, + stack: &TraitObligationStack<'o, 'tcx>) + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let ImplCandidate(def_id) = candidate { if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } + + // if def_id is a default impl and it doesn't implement all the trait items, + // the impl doesn't implement the trait. + // An `Unimplemented` error is returned only if the default_impl_check is + // applicable to the trait predicate or the cause of the predicate is an + // `ObjectCastObligation` + if self.tcx().impl_is_default(def_id) && + !self.tcx().default_impl_implement_all_methods(def_id){ + match stack.obligation.cause.code { + ObligationCauseCode::ObjectCastObligation(_) => { + return Err(Unimplemented) + }, + ObligationCauseCode::ItemObligation(..) | + ObligationCauseCode::MiscObligation => { + if let ty::DefaultImplCheck::Yes = stack.obligation + .predicate + .skip_binder() + .default_impl_check { + return Err(Unimplemented) + } + }, + _ => {} + } + } } Ok(Some(candidate)) } @@ -1178,9 +1205,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Instead, we select the right impl now but report `Bar does // not implement Clone`. if candidates.len() == 1 { - return self.filter_negative_impls(candidates.pop().unwrap()); + return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack); } - // Winnow, but record the exact outcome of evaluation, which // is needed for specialization. let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { @@ -1239,7 +1265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Just one candidate left. - self.filter_negative_impls(candidates.pop().unwrap().candidate) + self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack) } fn is_knowable<'o>(&mut self, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 898accb90215..9e0859c67a0a 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -22,8 +22,11 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), + ty::Predicate::Trait(ref data) => { + let anonymized_pred = ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)); + anonymized_pred.change_default_impl_check(ty::DefaultImplCheck::No) + .unwrap_or(anonymized_pred) + } ty::Predicate::Equate(ref data) => ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), @@ -554,6 +557,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) } + + pub fn default_impl_implement_all_methods(self, node_item_def_id: DefId) -> bool { + if let Some(impl_trait_ref) = self.impl_trait_ref(node_item_def_id) { + let trait_def = self.trait_def(impl_trait_ref.def_id); + for trait_item in self.associated_items(impl_trait_ref.def_id) { + let is_implemented = trait_def.ancestors(self, node_item_def_id) + .defs(self, trait_item.name, trait_item.kind, impl_trait_ref.def_id) + .next() + .map(|node_item| !node_item.node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented { + return false; + } + } + } + true + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 63bf52a9bdf7..0bc092d99eba 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -9,14 +9,19 @@ // except according to those terms. use hir::def_id::DefId; -use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; -use ty::subst::Kind; +use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer}; +use ty::subst::{Kind, Subst}; use traits; use syntax::abi::Abi; use util::ppaux; use std::fmt; +use syntax_pos::{BytePos, Span}; +use syntax::ext::hygiene::SyntaxContext; +use hir::map::Node::NodeTraitItem; +use hir; + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { pub def: InstanceDef<'tcx>, @@ -260,6 +265,13 @@ fn resolve_associated_item<'a, 'tcx>( traits::VtableImpl(impl_data) => { let (def_id, substs) = traits::find_associated_item( tcx, trait_item, rcvr_substs, &impl_data); + + check_unimplemented_trait_item(tcx, + impl_data.impl_def_id, + def_id, + trait_id, + trait_item); + let substs = tcx.erase_regions(&substs); Some(ty::Instance::new(def_id, substs)) } @@ -363,3 +375,108 @@ fn fn_once_adapter_instance<'a, 'tcx>( debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); Instance { def, substs } } + +fn check_unimplemented_trait_item<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_def_id: DefId, + trait_item_def_id: DefId, + trait_id: DefId, + trait_item: &ty::AssociatedItem) +{ + // if trait_item_def_id is a trait item and it doesn't have a default trait implementation + // the resolution has found an unimplemented trait item inside a default impl + if tcx.impl_is_default(impl_def_id) { + let is_unimplemented_trait_item = match tcx.hir.as_local_node_id(trait_item_def_id) { + Some(node_id) => + match tcx.hir.find(node_id) { + Some(NodeTraitItem(item)) => { + if let hir::TraitItemKind::Method(_, + hir::TraitMethod::Provided(_)) + = item.node { + false + } else { + true + } + }, + _ => false + } + None => { + let item = tcx.global_tcx().associated_item(trait_item_def_id); + match item.kind { + AssociatedKind::Method => match item.container { + AssociatedItemContainer::TraitContainer(_) => { + !item.defaultness.has_value() + } + _ => false + } + _ => false + } + } + }; + + if is_unimplemented_trait_item { + let mut err = tcx.sess.struct_err(&format!("the trait method `{}` \ + is not implemented", + trait_item.name)); + + let mut help_messages = Vec::new(); + help_messages.push( + if impl_def_id.is_local() { + let item = tcx.hir + .expect_item( + tcx.hir + .as_local_node_id(impl_def_id).unwrap() + ); + (item.span, format!("implement it inside this `default impl`")) + } else { + (Span::new ( + BytePos(0), + BytePos(0), + SyntaxContext::empty() + ), + format!("implement it inside the {} `default impl`", + tcx.item_path_str(impl_def_id))) + } + ); + + help_messages.push( + if trait_id.is_local() { + let trait_item = tcx.hir + .expect_item( + tcx.hir + .as_local_node_id(trait_id).unwrap() + ); + (trait_item.span, format!("provide a default method implementation \ + inside this `trait`")) + } else { + (Span::new ( + BytePos(0), + BytePos(0), + SyntaxContext::empty() + ), + format!("provide a default method implementation \ + inside the {} `trait`", + tcx.item_path_str(trait_id))) + } + ); + + help_messages.sort_by(|&(a,_), &(b,_)| a.partial_cmp(&b).unwrap()); + + let mut cnjs = vec!["or ", "either "]; + help_messages.iter().for_each(|&(span, ref msg)| { + let mut help_msg = String::from(cnjs.pop().unwrap_or("")); + help_msg.push_str(&msg); + + if span.data().lo == BytePos(0) && span.data().hi == BytePos(0) { + err.help(&help_msg); + } else { + err.span_help(span, &help_msg); + } + }); + + err.note(&format!("a `default impl` doesn't need to include all \ + items from the trait")); + err.emit(); + } + } +} \ No newline at end of file diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc..31cb4a642869 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1070,9 +1070,13 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum DefaultImplCheck { Yes, No, } + #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx> + pub trait_ref: TraitRef<'tcx>, + pub default_impl_check: DefaultImplCheck } pub type PolyTraitPredicate<'tcx> = ty::Binder>; @@ -1180,7 +1184,8 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { assert!(!self.has_escaping_regions()); ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone() + trait_ref: self.clone(), + default_impl_check: DefaultImplCheck::No })) } } @@ -1298,6 +1303,36 @@ impl<'tcx> Predicate<'tcx> { } } } + + pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck) + -> Option> { + match *self { + Predicate::Trait(ref t) => { + if t.skip_binder().default_impl_check != default_impl_check { + Some( + Predicate::Trait(ty::Binder(ty::TraitPredicate { + trait_ref: t.skip_binder().trait_ref, + default_impl_check: default_impl_check + })) + ) + } else { + None + } + } + Predicate::Trait(..) | + Predicate::Projection(..) | + Predicate::Equate(..) | + Predicate::Subtype(..) | + Predicate::RegionOutlives(..) | + Predicate::WellFormed(..) | + Predicate::ObjectSafe(..) | + Predicate::ClosureKind(..) | + Predicate::TypeOutlives(..) | + Predicate::ConstEvaluatable(..) => { + None + } + } + } } /// Represents the bounds declared on a particular set of type diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0dc1338fff86..122a76ca6253 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -278,7 +278,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref, + trait_ref: trait_ref, + default_impl_check: self.default_impl_check }) } } @@ -1127,7 +1128,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { - trait_ref: self.trait_ref.fold_with(folder) + trait_ref: self.trait_ref.fold_with(folder), + default_impl_check: self.default_impl_check } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 1593b452cdff..542bf12ecddc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -582,7 +582,10 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) + Binder(ty::TraitPredicate { + trait_ref: self.0.clone(), + default_impl_check: ty::DefaultImplCheck::No + }) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515b..8b7c9d505bc5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1230,8 +1230,12 @@ define_print! { define_print! { ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { debug { - write!(f, "TraitPredicate({:?})", - self.trait_ref) + let default_impl_check_value = match self.default_impl_check { + ty::DefaultImplCheck::Yes => "default_impl_check: yes", + ty::DefaultImplCheck::No => "default_impl_check: no", + }; + write!(f, "TraitPredicate({:?}, {})", + self.trait_ref, default_impl_check_value) } display { print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f16187797d4e..0851075a0924 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -618,6 +618,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } else { visit_fn_use(self.tcx, callee_ty, true, &mut self.output); + + if tcx.sess.has_errors() { + match func { + &mir::Operand::Consume(_) => {} + &mir::Operand::Constant(ref cst) => { + tcx.sess + .span_note_without_error(cst.span, + "the function call is here"); + } + } + tcx.sess.abort_if_errors(); + } } } mir::TerminatorKind::Drop { ref location, .. } | @@ -678,7 +690,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap(); - visit_instance_use(tcx, instance, is_direct_call, output); + if !tcx.sess.has_errors() { + // continue only if no errors are encountered during monomorphization + visit_instance_use(tcx, instance, is_direct_call, output); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1139ea5fbd36..dc42aa8dc1a5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1378,7 +1378,10 @@ pub struct Bounds<'tcx> { } impl<'a, 'gcx, 'tcx> Bounds<'tcx> { - pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>) + pub fn predicates(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_ty: Ty<'tcx>, + default_impl_check: ty::DefaultImplCheck) -> Vec> { let mut vec = Vec::new(); @@ -1402,7 +1405,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { } for bound_trait_ref in &self.trait_bounds { - vec.push(bound_trait_ref.to_predicate()); + vec.push( + if bound_trait_ref.skip_binder().def_id != + tcx.lang_items().sized_trait().unwrap() { + bound_trait_ref.to_predicate() + .change_default_impl_check(default_impl_check) + .unwrap_or(bound_trait_ref.to_predicate()) + } else { + bound_trait_ref.to_predicate() + } + ); } for projection in &self.projection_bounds { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4aed688027f7..d4180183aeff 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -189,7 +189,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( let generic_assumptions = tcx.predicates_of(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); - let assumptions_in_impl_context = assumptions_in_impl_context.predicates; + let assumptions_in_impl_context: Vec = + assumptions_in_impl_context.predicates + .iter() + .map(|predicate| { + predicate.change_default_impl_check(ty::DefaultImplCheck::No) + .unwrap_or(predicate.clone()) + }).collect(); // An earlier version of this code attempted to do this checking // via the traits::fulfill machinery. However, it ran into trouble @@ -211,7 +217,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // the analysis together via the fulfill , rather than the // repeated `contains` calls. - if !assumptions_in_impl_context.contains(&predicate) { + if !assumptions_in_impl_context.contains( + &predicate.change_default_impl_check(ty::DefaultImplCheck::No) + .unwrap_or(predicate.clone())) { let item_span = tcx.hir.span(self_type_node_id); struct_span_err!(tcx.sess, drop_impl_span, E0367, "The requirement `{}` is added only by the Drop impl.", predicate) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f044b2c711e2..4fe2f5b574e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1395,7 +1395,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|node_item| !node_item.node.is_from_trait()) .unwrap_or(false); - if !is_implemented { + if !is_implemented && !tcx.impl_is_default(impl_id) { if !trait_item.defaultness.has_value() { missing_items.push(trait_item); } else if associated_type_overridden { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3668fc46ddc2..9c233a7a15d2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -25,6 +25,7 @@ use errors::{DiagnosticBuilder, DiagnosticId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; +use rustc::ty::TypeFoldable; pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -343,8 +344,36 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx.body_id, &trait_ref, ast_trait_ref.path.span); + + // not registering predicates associcated with a `default impl` + // that doesn't implement all the trait items. + // it's left to the trait selection to select those trait predicates + // and trigger an `Unimplemented` error in case the defaul_impl_check + // is applicable + let impl_not_implement_trait = + if fcx.tcx.impl_is_default(item_def_id) && + !fcx.tcx.default_impl_implement_all_methods(item_def_id) { + true + } else { + false + }; + for obligation in obligations { - fcx.register_predicate(obligation); + let register = match obligation.predicate { + ty::Predicate::Trait(..) => { + if impl_not_implement_trait && + !obligation.predicate.has_param_types() { + false + } else { + true + } + } + _ => true + }; + + if register { + fcx.register_predicate(obligation); + } } } None => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c224..40d69855c49a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -677,7 +677,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SizedByDefault::No, item.span); - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + let superbounds1 = superbounds1.predicates(tcx, self_param_ty, ty::DefaultImplCheck::No); // Convert any explicit superbounds in the where clause, // e.g. `trait Foo where Self : Bar`: @@ -694,7 +694,11 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::GenericPredicates { parent: None, - predicates: superbounds + predicates: superbounds.iter() + .map(|predicate| { + predicate.change_default_impl_check(ty::DefaultImplCheck::Yes) + .unwrap_or(predicate.clone()) + }).collect() } } @@ -1364,17 +1368,39 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; + let mut default_impl_check = ty::DefaultImplCheck::No; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); let ast_generics = match node { - NodeTraitItem(item) => &item.generics, - NodeImplItem(item) => &item.generics, + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => { + default_impl_check = ty::DefaultImplCheck::Yes; + &item.generics + }, + _ => &item.generics + } + } + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => { + default_impl_check = ty::DefaultImplCheck::Yes; + &item.generics + }, + _ => &item.generics + } + } NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | ItemImpl(_, _, _, ref generics, ..) | + ItemStruct(_, ref generics) => { + default_impl_check = ty::DefaultImplCheck::Yes; + generics + } + ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1415,7 +1441,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("explicit_predicates_of: bounds={:?}", bounds); - let predicates = bounds.predicates(tcx, anon_ty); + let predicates = bounds.predicates(tcx, anon_ty, ty::DefaultImplCheck::No); debug!("explicit_predicates_of: predicates={:?}", predicates); @@ -1476,7 +1502,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ¶m.bounds, SizedByDefault::Yes, param.span); - predicates.extend(bounds.predicates(tcx, param_ty)); + predicates.extend(bounds.predicates(tcx, param_ty, default_impl_check)); } // Add in the bounds that appear in the where-clause @@ -1496,8 +1522,16 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, poly_trait_ref, ty, &mut projections); - - predicates.push(trait_ref.to_predicate()); + predicates.push( + if trait_ref.skip_binder().def_id != + tcx.lang_items().sized_trait().unwrap() { + trait_ref.to_predicate() + .change_default_impl_check(default_impl_check) + .unwrap_or(trait_ref.to_predicate()) + } else { + trait_ref.to_predicate() + } + ); for projection in &projections { predicates.push(projection.to_predicate()); @@ -1552,7 +1586,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SizedByDefault::Yes, trait_item.span); - bounds.predicates(tcx, assoc_ty).into_iter() + bounds.predicates(tcx, assoc_ty, ty::DefaultImplCheck::No).into_iter() })) } diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs new file mode 100644 index 000000000000..263f316f3c8f --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs @@ -0,0 +1,16 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +pub trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs new file mode 100644 index 000000000000..cee6fcf7d9ad --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +pub trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs new file mode 100644 index 000000000000..54f6690aa9f1 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs @@ -0,0 +1,23 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:foo_trait_default_impl.rs + +#![feature(specialization)] + +extern crate foo_trait_default_impl; + +use foo_trait_default_impl::*; + +struct MyStruct; + +fn main() { + MyStruct.foo_two(); //~ NOTE the function call is here +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs new file mode 100644 index 000000000000..8e2de42a0995 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:foo_trait.rs + +#![feature(specialization)] + +extern crate foo_trait; + +use foo_trait::{Foo}; + +struct MyStruct; + +default impl Foo for MyStruct { + fn foo_one(&self) -> &'static str { + "generic" + } +} +//~^^^^^ HELP implement it inside this `default impl` + +fn main() { + MyStruct.foo_two(); //~ NOTE the function call is here +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs new file mode 100644 index 000000000000..d0db6e996d81 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} +//~^^^^ HELP provide a default method implementation inside this `trait` + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} +//~^^^^^ HELP implement it inside this `default impl` + +struct MyStruct; + +fn main() { + MyStruct.foo_two(); //~ NOTE the function call is here +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs new file mode 100644 index 000000000000..81b85f58998c --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs @@ -0,0 +1,47 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the trait bound `MyStruct: Draw` is not satisfied + +#![feature(specialization)] + +trait Draw { + fn draw(&self); + fn draw2(&self); +} + +struct Screen { + pub components: Vec>, +} + +impl Screen { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} + +default impl Draw for T { + fn draw(&self) { + println!("draw"); + } +} + +struct MyStruct; + +fn main() { + let screen = Screen { + components: vec![ + Box::new(MyStruct) + ] + }; + screen.run(); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs new file mode 100644 index 000000000000..00cceeb4db3e --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the trait bound `MyStruct: Foo` is not satisfied + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +fn foo(x: T) -> &'static str { + x.foo_one() +} + +struct MyStruct; + +fn main() { + println!("{:?}", foo(MyStruct)); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs new file mode 100644 index 000000000000..51a6a9e2c6bf --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs @@ -0,0 +1,38 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the trait bound `MyStruct: Foo` is not satisfied + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +struct FooS; + +impl FooS{ + fn foo(&self, x: T) -> &'static str{ + x.foo_one() + } +} + +struct MyStruct; + +fn main() { + println!("{:?}", FooS.foo(MyStruct)); +} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs new file mode 100644 index 000000000000..3444dea39c20 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs @@ -0,0 +1,40 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the trait bound `MyStruct: SuperFoo` is not satisfied + +#![feature(specialization)] + +trait SuperFoo { + fn super_foo_one(&self) -> &'static str; + fn super_foo_two(&self) -> &'static str; +} + +trait Foo: SuperFoo { + fn foo(&self) -> &'static str; +} + +default impl SuperFoo for T { + fn super_foo_one(&self) -> &'static str { + "generic" + } +} + +struct MyStruct; + +impl Foo for MyStruct { + fn foo(&self) -> &'static str { + "foo" + } +} + +fn main() { + println!("{:?}", MyStruct.foo()); +} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs new file mode 100644 index 000000000000..6af69e89316a --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn dummy(&self, t: T); +} + +trait Bar { + fn method(&self) where A: Foo; +} + +struct S; +struct X; + +default impl Foo for X {} + +impl Bar for isize { + fn method(&self) where X: Foo { + } +} + +fn main() { + 1.method::(); + //~^ ERROR the trait bound `X: Foo` is not satisfied +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs new file mode 100644 index 000000000000..a2ea087220fb --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs @@ -0,0 +1,48 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: the trait bound `MyStruct: Draw` is not satisfied + +#![feature(specialization)] + +trait Draw { + fn draw(&self); + fn draw2(&self); +} + +struct Screen { + pub components: Vec, +} + +impl Screen + where T: Draw { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} + +default impl Draw for MyStruct { + fn draw(&self) { + println!("draw"); + } +} + +struct MyStruct; + +fn main() { + let screen = Screen { + components: vec![ + MyStruct + ] + }; + screen.run(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs new file mode 100644 index 000000000000..752b0190ea6c --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +pub trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str { + "generic Trait" + } +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo_two(&self) -> &'static str { + "generic Clone" + } +} \ No newline at end of file diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs new file mode 100644 index 000000000000..4ed37b311ef0 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs @@ -0,0 +1,40 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic one" + } + fn foo_two(&self) -> &'static str { + "generic two" + } +} + +fn foo_one(x: T) -> &'static str { + x.foo_one() +} + +fn foo_two(x: T) -> &'static str { + x.foo_two() +} + +struct MyStruct; + +fn main() { + assert!(foo_one(MyStruct) == "generic one"); + assert!(foo_two(MyStruct) == "generic two"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs new file mode 100644 index 000000000000..5c0547b03414 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:foo_trait.rs + +#![feature(specialization)] + +extern crate foo_trait; + +use foo_trait::*; + +struct MyStruct; + +fn main() { + assert!(MyStruct.foo_one() == "generic"); + assert!(0u8.foo_two() == "generic Clone"); + assert!(MyStruct.foo_two() == "generic Trait"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs new file mode 100644 index 000000000000..254d3bebb903 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs @@ -0,0 +1,38 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str { + "generic Trait" + } +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo_two(&self) -> &'static str { + "generic Clone" + } +} + +struct MyStruct; + +fn main() { + assert!(MyStruct.foo_one() == "generic"); + assert!(0u8.foo_two() == "generic Clone"); + assert!(MyStruct.foo_two() == "generic Trait"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs new file mode 100644 index 000000000000..409d2c78e775 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn foo_one(&self) -> &'static str; + fn foo_two(&self) -> &'static str; +} + +default impl Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo_two(&self) -> &'static str { + "generic Clone" + } +} + +struct MyStruct; + +fn main() { + assert!(MyStruct.foo_one() == "generic"); + assert!(0u8.foo_two() == "generic Clone"); +} From 13e80af159a709e5bb9a178b19b4319716261661 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Tue, 24 Oct 2017 09:55:57 +0000 Subject: [PATCH 16/87] support `default impl` for specialization a default impl should never be considered as implementing the trait on its own -- regardless of whether it contains all items or not --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/traits/select.rs | 36 +----- src/librustc/traits/util.rs | 25 +--- src/librustc/ty/instance.rs | 119 +----------------- src/librustc/ty/mod.rs | 39 +----- src/librustc/ty/structural_impls.rs | 6 +- src/librustc/ty/sty.rs | 5 +- src/librustc/ty/trait_def.rs | 12 +- src/librustc/util/ppaux.rs | 8 +- src/librustc_mir/monomorphize/collector.rs | 17 +-- src/librustc_typeck/astconv.rs | 16 +-- src/librustc_typeck/check/dropck.rs | 12 +- src/librustc_typeck/check/wfcheck.rs | 23 +--- src/librustc_typeck/collect.rs | 52 ++------ .../defaultimpl/auxiliary/foo_trait.rs | 16 --- .../specialization-default-projection.rs | 46 ------- .../specialization-default-types.rs | 45 ------- ...method-not-implemented-cross-crate-impl.rs | 23 ---- ...tion-method-not-implemented-cross-crate.rs | 30 ----- .../specialization-method-not-implemented.rs | 30 ----- .../specialization-trait-bounds-casting.rs | 47 ------- .../specialization-trait-bounds-impl-item.rs | 38 ------ ...specialization-trait-bounds-super-trait.rs | 40 ------ .../specialization-trait-bounds-trait-item.rs | 34 ----- .../specialization-trait-bounds-vec.rs | 48 ------- ...cialization-trait-item-not-implemented.rs} | 17 ++- ...> specialization-trait-not-implemented.rs} | 12 +- .../specialization/defaultimpl/assoc-fns.rs | 37 ------ .../defaultimpl/auxiliary/cross_crate.rs | 82 ------------ .../auxiliary/cross_crate_defaults.rs | 49 -------- .../defaultimpl/auxiliary/foo_trait.rs | 30 ----- .../defaultimpl/basics-unsafe.rs | 106 ---------------- .../specialization/defaultimpl/basics.rs | 106 ---------------- .../defaultimpl/cross-crate-defaults.rs | 49 -------- .../defaultimpl/cross-crate-no-gate.rs | 29 ----- .../specialization/defaultimpl/cross-crate.rs | 58 --------- .../defaultimpl/default-methods.rs | 94 -------------- .../defaultimpl/projection-alias.rs | 32 ----- .../specialization-trait-bounds.rs | 40 ------ ...cialization-trait-item-not-implemented.rs} | 17 ++- ...-traits-impl-default-method-cross-crate.rs | 25 ---- ...ecialization-traits-impl-default-method.rs | 38 ------ 42 files changed, 66 insertions(+), 1525 deletions(-) delete mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs rename src/test/compile-fail/specialization/defaultimpl/{specialization-trait-bounds-fn.rs => specialization-trait-item-not-implemented.rs} (74%) rename src/test/compile-fail/specialization/defaultimpl/{auxiliary/foo_trait_default_impl.rs => specialization-trait-not-implemented.rs} (71%) delete mode 100644 src/test/run-pass/specialization/defaultimpl/assoc-fns.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/basics.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/default-methods.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/projection-alias.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs rename src/test/run-pass/specialization/defaultimpl/{specialization-traits-impl.rs => specialization-trait-item-not-implemented.rs} (74%) delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 42724274eb70..107779ec3fa1 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -218,8 +218,7 @@ impl_stable_hash_for!(enum ty::Visibility { }); impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); -impl_stable_hash_for!(enum ty::DefaultImplCheck { Yes, No }); -impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref, default_impl_check }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index ee6bf4180dda..4ed25646d436 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1083,39 +1083,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Treat negative impls as unimplemented - fn filter_negative_and_default_impls<'o>(&self, - candidate: SelectionCandidate<'tcx>, - stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - + fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } - - // if def_id is a default impl and it doesn't implement all the trait items, - // the impl doesn't implement the trait. - // An `Unimplemented` error is returned only if the default_impl_check is - // applicable to the trait predicate or the cause of the predicate is an - // `ObjectCastObligation` - if self.tcx().impl_is_default(def_id) && - !self.tcx().default_impl_implement_all_methods(def_id){ - match stack.obligation.cause.code { - ObligationCauseCode::ObjectCastObligation(_) => { - return Err(Unimplemented) - }, - ObligationCauseCode::ItemObligation(..) | - ObligationCauseCode::MiscObligation => { - if let ty::DefaultImplCheck::Yes = stack.obligation - .predicate - .skip_binder() - .default_impl_check { - return Err(Unimplemented) - } - }, - _ => {} - } - } } Ok(Some(candidate)) } @@ -1205,8 +1178,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Instead, we select the right impl now but report `Bar does // not implement Clone`. if candidates.len() == 1 { - return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack); + return self.filter_negative_impls(candidates.pop().unwrap()); } + // Winnow, but record the exact outcome of evaluation, which // is needed for specialization. let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { @@ -1265,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Just one candidate left. - self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack) + self.filter_negative_impls(candidates.pop().unwrap().candidate) } fn is_knowable<'o>(&mut self, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 9e0859c67a0a..898accb90215 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -22,11 +22,8 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => { - let anonymized_pred = ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)); - anonymized_pred.change_default_impl_check(ty::DefaultImplCheck::No) - .unwrap_or(anonymized_pred) - } + ty::Predicate::Trait(ref data) => + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), ty::Predicate::Equate(ref data) => ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), @@ -557,24 +554,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) } - - pub fn default_impl_implement_all_methods(self, node_item_def_id: DefId) -> bool { - if let Some(impl_trait_ref) = self.impl_trait_ref(node_item_def_id) { - let trait_def = self.trait_def(impl_trait_ref.def_id); - for trait_item in self.associated_items(impl_trait_ref.def_id) { - let is_implemented = trait_def.ancestors(self, node_item_def_id) - .defs(self, trait_item.name, trait_item.kind, impl_trait_ref.def_id) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented { - return false; - } - } - } - true - } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 0bc092d99eba..6c727c94f58c 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer}; +use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; use ty::subst::{Kind, Subst}; use traits; use syntax::abi::Abi; @@ -17,11 +17,6 @@ use util::ppaux; use std::fmt; -use syntax_pos::{BytePos, Span}; -use syntax::ext::hygiene::SyntaxContext; -use hir::map::Node::NodeTraitItem; -use hir; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { pub def: InstanceDef<'tcx>, @@ -265,13 +260,6 @@ fn resolve_associated_item<'a, 'tcx>( traits::VtableImpl(impl_data) => { let (def_id, substs) = traits::find_associated_item( tcx, trait_item, rcvr_substs, &impl_data); - - check_unimplemented_trait_item(tcx, - impl_data.impl_def_id, - def_id, - trait_id, - trait_item); - let substs = tcx.erase_regions(&substs); Some(ty::Instance::new(def_id, substs)) } @@ -375,108 +363,3 @@ fn fn_once_adapter_instance<'a, 'tcx>( debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); Instance { def, substs } } - -fn check_unimplemented_trait_item<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_def_id: DefId, - trait_item_def_id: DefId, - trait_id: DefId, - trait_item: &ty::AssociatedItem) -{ - // if trait_item_def_id is a trait item and it doesn't have a default trait implementation - // the resolution has found an unimplemented trait item inside a default impl - if tcx.impl_is_default(impl_def_id) { - let is_unimplemented_trait_item = match tcx.hir.as_local_node_id(trait_item_def_id) { - Some(node_id) => - match tcx.hir.find(node_id) { - Some(NodeTraitItem(item)) => { - if let hir::TraitItemKind::Method(_, - hir::TraitMethod::Provided(_)) - = item.node { - false - } else { - true - } - }, - _ => false - } - None => { - let item = tcx.global_tcx().associated_item(trait_item_def_id); - match item.kind { - AssociatedKind::Method => match item.container { - AssociatedItemContainer::TraitContainer(_) => { - !item.defaultness.has_value() - } - _ => false - } - _ => false - } - } - }; - - if is_unimplemented_trait_item { - let mut err = tcx.sess.struct_err(&format!("the trait method `{}` \ - is not implemented", - trait_item.name)); - - let mut help_messages = Vec::new(); - help_messages.push( - if impl_def_id.is_local() { - let item = tcx.hir - .expect_item( - tcx.hir - .as_local_node_id(impl_def_id).unwrap() - ); - (item.span, format!("implement it inside this `default impl`")) - } else { - (Span::new ( - BytePos(0), - BytePos(0), - SyntaxContext::empty() - ), - format!("implement it inside the {} `default impl`", - tcx.item_path_str(impl_def_id))) - } - ); - - help_messages.push( - if trait_id.is_local() { - let trait_item = tcx.hir - .expect_item( - tcx.hir - .as_local_node_id(trait_id).unwrap() - ); - (trait_item.span, format!("provide a default method implementation \ - inside this `trait`")) - } else { - (Span::new ( - BytePos(0), - BytePos(0), - SyntaxContext::empty() - ), - format!("provide a default method implementation \ - inside the {} `trait`", - tcx.item_path_str(trait_id))) - } - ); - - help_messages.sort_by(|&(a,_), &(b,_)| a.partial_cmp(&b).unwrap()); - - let mut cnjs = vec!["or ", "either "]; - help_messages.iter().for_each(|&(span, ref msg)| { - let mut help_msg = String::from(cnjs.pop().unwrap_or("")); - help_msg.push_str(&msg); - - if span.data().lo == BytePos(0) && span.data().hi == BytePos(0) { - err.help(&help_msg); - } else { - err.span_help(span, &help_msg); - } - }); - - err.note(&format!("a `default impl` doesn't need to include all \ - items from the trait")); - err.emit(); - } - } -} \ No newline at end of file diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 31cb4a642869..f52f2ea0f9fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1070,13 +1070,9 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub enum DefaultImplCheck { Yes, No, } - #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx>, - pub default_impl_check: DefaultImplCheck + pub trait_ref: TraitRef<'tcx> } pub type PolyTraitPredicate<'tcx> = ty::Binder>; @@ -1184,8 +1180,7 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { assert!(!self.has_escaping_regions()); ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone(), - default_impl_check: DefaultImplCheck::No + trait_ref: self.clone() })) } } @@ -1303,36 +1298,6 @@ impl<'tcx> Predicate<'tcx> { } } } - - pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck) - -> Option> { - match *self { - Predicate::Trait(ref t) => { - if t.skip_binder().default_impl_check != default_impl_check { - Some( - Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: t.skip_binder().trait_ref, - default_impl_check: default_impl_check - })) - ) - } else { - None - } - } - Predicate::Trait(..) | - Predicate::Projection(..) | - Predicate::Equate(..) | - Predicate::Subtype(..) | - Predicate::RegionOutlives(..) | - Predicate::WellFormed(..) | - Predicate::ObjectSafe(..) | - Predicate::ClosureKind(..) | - Predicate::TypeOutlives(..) | - Predicate::ConstEvaluatable(..) => { - None - } - } - } } /// Represents the bounds declared on a particular set of type diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 122a76ca6253..0dc1338fff86 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -278,8 +278,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref: trait_ref, - default_impl_check: self.default_impl_check + trait_ref, }) } } @@ -1128,8 +1127,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { - trait_ref: self.trait_ref.fold_with(folder), - default_impl_check: self.default_impl_check + trait_ref: self.trait_ref.fold_with(folder) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 542bf12ecddc..1593b452cdff 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -582,10 +582,7 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { // Note that we preserve binding levels - Binder(ty::TraitPredicate { - trait_ref: self.0.clone(), - default_impl_check: ty::DefaultImplCheck::No - }) + Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 0fbf9f1bd587..33972df97fb6 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -92,10 +92,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self_ty: Ty<'tcx>, mut f: F) { + let mut emit_impl = |impl_def_id: DefId| { + if !self.impl_is_default(impl_def_id) { + f(impl_def_id); + } + }; + let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); + emit_impl(impl_def_id); } // simplify_type(.., false) basically replaces type parameters and @@ -126,13 +132,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - f(impl_def_id); + emit_impl(impl_def_id); } } } else { for v in impls.non_blanket_impls.values() { for &impl_def_id in v { - f(impl_def_id); + emit_impl(impl_def_id); } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8b7c9d505bc5..37d1c568515b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1230,12 +1230,8 @@ define_print! { define_print! { ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { debug { - let default_impl_check_value = match self.default_impl_check { - ty::DefaultImplCheck::Yes => "default_impl_check: yes", - ty::DefaultImplCheck::No => "default_impl_check: no", - }; - write!(f, "TraitPredicate({:?}, {})", - self.trait_ref, default_impl_check_value) + write!(f, "TraitPredicate({:?})", + self.trait_ref) } display { print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 0851075a0924..f16187797d4e 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -618,18 +618,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } else { visit_fn_use(self.tcx, callee_ty, true, &mut self.output); - - if tcx.sess.has_errors() { - match func { - &mir::Operand::Consume(_) => {} - &mir::Operand::Constant(ref cst) => { - tcx.sess - .span_note_without_error(cst.span, - "the function call is here"); - } - } - tcx.sess.abort_if_errors(); - } } } mir::TerminatorKind::Drop { ref location, .. } | @@ -690,10 +678,7 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap(); - if !tcx.sess.has_errors() { - // continue only if no errors are encountered during monomorphization - visit_instance_use(tcx, instance, is_direct_call, output); - } + visit_instance_use(tcx, instance, is_direct_call, output); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index dc42aa8dc1a5..1139ea5fbd36 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1378,10 +1378,7 @@ pub struct Bounds<'tcx> { } impl<'a, 'gcx, 'tcx> Bounds<'tcx> { - pub fn predicates(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_ty: Ty<'tcx>, - default_impl_check: ty::DefaultImplCheck) + pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>) -> Vec> { let mut vec = Vec::new(); @@ -1405,16 +1402,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { } for bound_trait_ref in &self.trait_bounds { - vec.push( - if bound_trait_ref.skip_binder().def_id != - tcx.lang_items().sized_trait().unwrap() { - bound_trait_ref.to_predicate() - .change_default_impl_check(default_impl_check) - .unwrap_or(bound_trait_ref.to_predicate()) - } else { - bound_trait_ref.to_predicate() - } - ); + vec.push(bound_trait_ref.to_predicate()); } for projection in &self.projection_bounds { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d4180183aeff..4aed688027f7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -189,13 +189,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( let generic_assumptions = tcx.predicates_of(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); - let assumptions_in_impl_context: Vec = - assumptions_in_impl_context.predicates - .iter() - .map(|predicate| { - predicate.change_default_impl_check(ty::DefaultImplCheck::No) - .unwrap_or(predicate.clone()) - }).collect(); + let assumptions_in_impl_context = assumptions_in_impl_context.predicates; // An earlier version of this code attempted to do this checking // via the traits::fulfill machinery. However, it ran into trouble @@ -217,9 +211,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // the analysis together via the fulfill , rather than the // repeated `contains` calls. - if !assumptions_in_impl_context.contains( - &predicate.change_default_impl_check(ty::DefaultImplCheck::No) - .unwrap_or(predicate.clone())) { + if !assumptions_in_impl_context.contains(&predicate) { let item_span = tcx.hir.span(self_type_node_id); struct_span_err!(tcx.sess, drop_impl_span, E0367, "The requirement `{}` is added only by the Drop impl.", predicate) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9c233a7a15d2..78113bdcc0e4 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -25,7 +25,6 @@ use errors::{DiagnosticBuilder, DiagnosticId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; -use rustc::ty::TypeFoldable; pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -346,28 +345,10 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ast_trait_ref.path.span); // not registering predicates associcated with a `default impl` - // that doesn't implement all the trait items. - // it's left to the trait selection to select those trait predicates - // and trigger an `Unimplemented` error in case the defaul_impl_check - // is applicable - let impl_not_implement_trait = - if fcx.tcx.impl_is_default(item_def_id) && - !fcx.tcx.default_impl_implement_all_methods(item_def_id) { - true - } else { - false - }; - + let impl_is_default = fcx.tcx.impl_is_default(item_def_id); for obligation in obligations { let register = match obligation.predicate { - ty::Predicate::Trait(..) => { - if impl_not_implement_trait && - !obligation.predicate.has_param_types() { - false - } else { - true - } - } + ty::Predicate::Trait(..) => !impl_is_default, _ => true }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 40d69855c49a..d5328a18c224 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -677,7 +677,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SizedByDefault::No, item.span); - let superbounds1 = superbounds1.predicates(tcx, self_param_ty, ty::DefaultImplCheck::No); + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); // Convert any explicit superbounds in the where clause, // e.g. `trait Foo where Self : Bar`: @@ -694,11 +694,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::GenericPredicates { parent: None, - predicates: superbounds.iter() - .map(|predicate| { - predicate.change_default_impl_check(ty::DefaultImplCheck::Yes) - .unwrap_or(predicate.clone()) - }).collect() + predicates: superbounds } } @@ -1368,39 +1364,17 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; - let mut default_impl_check = ty::DefaultImplCheck::No; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); let ast_generics = match node { - NodeTraitItem(item) => { - match item.node { - TraitItemKind::Method(ref sig, _) => { - default_impl_check = ty::DefaultImplCheck::Yes; - &item.generics - }, - _ => &item.generics - } - } - NodeImplItem(item) => { - match item.node { - ImplItemKind::Method(ref sig, _) => { - default_impl_check = ty::DefaultImplCheck::Yes; - &item.generics - }, - _ => &item.generics - } - } + NodeTraitItem(item) => &item.generics, + NodeImplItem(item) => &item.generics, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | ItemImpl(_, _, _, ref generics, ..) | - ItemStruct(_, ref generics) => { - default_impl_check = ty::DefaultImplCheck::Yes; - generics - } - ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1441,7 +1415,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("explicit_predicates_of: bounds={:?}", bounds); - let predicates = bounds.predicates(tcx, anon_ty, ty::DefaultImplCheck::No); + let predicates = bounds.predicates(tcx, anon_ty); debug!("explicit_predicates_of: predicates={:?}", predicates); @@ -1502,7 +1476,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ¶m.bounds, SizedByDefault::Yes, param.span); - predicates.extend(bounds.predicates(tcx, param_ty, default_impl_check)); + predicates.extend(bounds.predicates(tcx, param_ty)); } // Add in the bounds that appear in the where-clause @@ -1522,16 +1496,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, poly_trait_ref, ty, &mut projections); - predicates.push( - if trait_ref.skip_binder().def_id != - tcx.lang_items().sized_trait().unwrap() { - trait_ref.to_predicate() - .change_default_impl_check(default_impl_check) - .unwrap_or(trait_ref.to_predicate()) - } else { - trait_ref.to_predicate() - } - ); + + predicates.push(trait_ref.to_predicate()); for projection in &projections { predicates.push(projection.to_predicate()); @@ -1586,7 +1552,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SizedByDefault::Yes, trait_item.span); - bounds.predicates(tcx, assoc_ty, ty::DefaultImplCheck::No).into_iter() + bounds.predicates(tcx, assoc_ty).into_iter() })) } diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs deleted file mode 100644 index 263f316f3c8f..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -pub trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str; -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs deleted file mode 100644 index ad55f44255b4..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Make sure we can't project defaulted associated types - -trait Foo { - type Assoc; -} - -default impl Foo for T { - type Assoc = (); -} - -impl Foo for u8 { - type Assoc = String; -} - -fn generic() -> ::Assoc { - // `T` could be some downstream crate type that specializes (or, - // for that matter, `u8`). - - () //~ ERROR mismatched types -} - -fn monomorphic() -> () { - // Even though we know that `()` is not specialized in a - // downstream crate, typeck refuses to project here. - - generic::<()>() //~ ERROR mismatched types -} - -fn main() { - // No error here, we CAN project from `u8`, as there is no `default` - // in that impl. - let s: String = generic::(); - println!("{}", s); // bad news if this all compiles -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs deleted file mode 100644 index 7353f7ac8c5c..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// It should not be possible to use the concrete value of a defaulted -// associated type in the impl defining it -- otherwise, what happens -// if it's overridden? - -#![feature(specialization)] - -trait Example { - type Output; - fn generate(self) -> Self::Output; -} - -default impl Example for T { - type Output = Box; - fn generate(self) -> Self::Output { - Box::new(self) //~ ERROR mismatched types - } -} - -impl Example for bool { - type Output = bool; - fn generate(self) -> bool { self } -} - -fn trouble(t: T) -> Box { - Example::generate(t) //~ ERROR mismatched types -} - -fn weaponize() -> bool { - let b: Box = trouble(true); - *b -} - -fn main() { - weaponize(); -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs deleted file mode 100644 index 54f6690aa9f1..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:foo_trait_default_impl.rs - -#![feature(specialization)] - -extern crate foo_trait_default_impl; - -use foo_trait_default_impl::*; - -struct MyStruct; - -fn main() { - MyStruct.foo_two(); //~ NOTE the function call is here -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs deleted file mode 100644 index 8e2de42a0995..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:foo_trait.rs - -#![feature(specialization)] - -extern crate foo_trait; - -use foo_trait::{Foo}; - -struct MyStruct; - -default impl Foo for MyStruct { - fn foo_one(&self) -> &'static str { - "generic" - } -} -//~^^^^^ HELP implement it inside this `default impl` - -fn main() { - MyStruct.foo_two(); //~ NOTE the function call is here -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs deleted file mode 100644 index d0db6e996d81..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str; -} -//~^^^^ HELP provide a default method implementation inside this `trait` - -default impl Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} -//~^^^^^ HELP implement it inside this `default impl` - -struct MyStruct; - -fn main() { - MyStruct.foo_two(); //~ NOTE the function call is here -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs deleted file mode 100644 index 81b85f58998c..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: the trait bound `MyStruct: Draw` is not satisfied - -#![feature(specialization)] - -trait Draw { - fn draw(&self); - fn draw2(&self); -} - -struct Screen { - pub components: Vec>, -} - -impl Screen { - pub fn run(&self) { - for component in self.components.iter() { - component.draw(); - } - } -} - -default impl Draw for T { - fn draw(&self) { - println!("draw"); - } -} - -struct MyStruct; - -fn main() { - let screen = Screen { - components: vec![ - Box::new(MyStruct) - ] - }; - screen.run(); -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs deleted file mode 100644 index 51a6a9e2c6bf..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: the trait bound `MyStruct: Foo` is not satisfied - -#![feature(specialization)] - -trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str; -} - -default impl Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -struct FooS; - -impl FooS{ - fn foo(&self, x: T) -> &'static str{ - x.foo_one() - } -} - -struct MyStruct; - -fn main() { - println!("{:?}", FooS.foo(MyStruct)); -} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs deleted file mode 100644 index 3444dea39c20..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: the trait bound `MyStruct: SuperFoo` is not satisfied - -#![feature(specialization)] - -trait SuperFoo { - fn super_foo_one(&self) -> &'static str; - fn super_foo_two(&self) -> &'static str; -} - -trait Foo: SuperFoo { - fn foo(&self) -> &'static str; -} - -default impl SuperFoo for T { - fn super_foo_one(&self) -> &'static str { - "generic" - } -} - -struct MyStruct; - -impl Foo for MyStruct { - fn foo(&self) -> &'static str { - "foo" - } -} - -fn main() { - println!("{:?}", MyStruct.foo()); -} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs deleted file mode 100644 index 6af69e89316a..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -trait Foo { - fn dummy(&self, t: T); -} - -trait Bar { - fn method(&self) where A: Foo; -} - -struct S; -struct X; - -default impl Foo for X {} - -impl Bar for isize { - fn method(&self) where X: Foo { - } -} - -fn main() { - 1.method::(); - //~^ ERROR the trait bound `X: Foo` is not satisfied -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs deleted file mode 100644 index a2ea087220fb..000000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: the trait bound `MyStruct: Draw` is not satisfied - -#![feature(specialization)] - -trait Draw { - fn draw(&self); - fn draw2(&self); -} - -struct Screen { - pub components: Vec, -} - -impl Screen - where T: Draw { - pub fn run(&self) { - for component in self.components.iter() { - component.draw(); - } - } -} - -default impl Draw for MyStruct { - fn draw(&self) { - println!("draw"); - } -} - -struct MyStruct; - -fn main() { - let screen = Screen { - components: vec![ - MyStruct - ] - }; - screen.run(); -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs similarity index 74% rename from src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 00cceeb4db3e..323ff7b2db9d 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: the trait bound `MyStruct: Foo` is not satisfied - #![feature(specialization)] trait Foo { @@ -17,18 +15,17 @@ trait Foo { fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } -fn foo(x: T) -> &'static str { - x.foo_one() -} - -struct MyStruct; +impl Foo for MyStruct {} +//~^ ERROR not all trait items implemented, missing: `foo_two` [E0046] fn main() { - println!("{:?}", foo(MyStruct)); -} + println!("{}", MyStruct.foo_one()); +} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs similarity index 71% rename from src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index cee6fcf7d9ad..36945e98b088 100644 --- a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,13 +10,21 @@ #![feature(specialization)] -pub trait Foo { +trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } + + +fn main() { + println!("{}", MyStruct.foo_one()); + //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope +} \ No newline at end of file diff --git a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs deleted file mode 100644 index b99ba3d0f1c9..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that non-method associated functions can be specialized - -#![feature(specialization)] - -trait Foo { - fn mk() -> Self; -} - -default impl Foo for T { - fn mk() -> T { - T::default() - } -} - -impl Foo for Vec { - fn mk() -> Vec { - vec![0] - } -} - -fn main() { - let v1: Vec = Foo::mk(); - let v2: Vec = Foo::mk(); - - assert!(v1.len() == 0); - assert!(v2.len() == 1); -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs deleted file mode 100644 index 71dd7c99009e..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -pub trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -pub trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs deleted file mode 100644 index 9d0ea64fed42..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#![feature(specialization)] - -// First, test only use of explicit `default` items: - -pub trait Foo { - fn foo(&self) -> bool; -} - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -// Next, test mixture of explicit `default` and provided methods: - -pub trait Bar { - fn bar(&self) -> i32 { 0 } -} - -impl Bar for T {} // use the provided method - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs deleted file mode 100644 index 752b0190ea6c..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -pub trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str { - "generic Trait" - } -} - -default impl Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo_two(&self) -> &'static str { - "generic Clone" - } -} \ No newline at end of file diff --git a/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs deleted file mode 100644 index 7daecc842f3f..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -unsafe trait Foo { - fn foo(&self) -> &'static str; -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default unsafe impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default unsafe impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default unsafe impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default unsafe impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -default unsafe impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -default unsafe impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -unsafe trait MyMarker {} -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -unsafe impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/basics.rs b/src/test/run-pass/specialization/defaultimpl/basics.rs deleted file mode 100644 index 594f1e4fcdfc..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs deleted file mode 100644 index 19e1af15bdd5..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:cross_crate_defaults.rs - -#![feature(specialization)] - -extern crate cross_crate_defaults; - -use cross_crate_defaults::*; - -struct LocalDefault; -struct LocalOverride; - -impl Foo for LocalDefault {} - -impl Foo for LocalOverride { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); - - assert!(!LocalDefault.foo()); - assert!(LocalOverride.foo()); -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs deleted file mode 100644 index 67cc694ae12c..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that specialization works even if only the upstream crate enables it - -// aux-build:cross_crate.rs - -extern crate cross_crate; - -use cross_crate::*; - -fn main() { - assert!(0u8.foo() == "generic Clone"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs deleted file mode 100644 index f1ad105db8f7..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:cross_crate.rs - -#![feature(specialization)] - -extern crate cross_crate; - -use cross_crate::*; - -struct NotClone; - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -struct MyType(T); -default impl Foo for MyType { - fn foo(&self) -> &'static str { - "generic MyType" - } -} - -impl Foo for MyType { - fn foo(&self) -> &'static str { - "MyType" - } -} - -struct MyOtherType; -impl Foo for MyOtherType {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); - - assert!(MyType(()).foo() == "generic MyType"); - assert!(MyType(0u8).foo() == "MyType"); - assert!(MyOtherType.foo() == "generic"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/default-methods.rs b/src/test/run-pass/specialization/defaultimpl/default-methods.rs deleted file mode 100644 index 4ac9afc1c897..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/default-methods.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Test that default methods are cascaded correctly - -// First, test only use of explicit `default` items: - -trait Foo { - fn foo(&self) -> bool; -} - -// Specialization tree for Foo: -// -// T -// / \ -// i32 i64 - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); -} - -// Next, test mixture of explicit `default` and provided methods: - -trait Bar { - fn bar(&self) -> i32 { 0 } -} - -// Specialization tree for Bar. -// Uses of $ designate that method is provided -// -// $Bar (the trait) -// | -// T -// /|\ -// / | \ -// / | \ -// / | \ -// / | \ -// / | \ -// $i32 &str $Vec -// /\ -// / \ -// Vec $Vec - -// use the provided method -impl Bar for T {} - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/projection-alias.rs deleted file mode 100644 index 2397c3e2bff5..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Regression test for ICE when combining specialized associated types and type -// aliases - -trait Id_ { - type Out; -} - -type Id = ::Out; - -default impl Id_ for T { - type Out = T; -} - -fn test_proection() { - let x: Id = panic!(); -} - -fn main() { - -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs deleted file mode 100644 index 4ed37b311ef0..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str; -} - -default impl Foo for T { - fn foo_one(&self) -> &'static str { - "generic one" - } - fn foo_two(&self) -> &'static str { - "generic two" - } -} - -fn foo_one(x: T) -> &'static str { - x.foo_one() -} - -fn foo_two(x: T) -> &'static str { - x.foo_two() -} - -struct MyStruct; - -fn main() { - assert!(foo_one(MyStruct) == "generic one"); - assert!(foo_two(MyStruct) == "generic two"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs similarity index 74% rename from src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs rename to src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 409d2c78e775..f8eb57bad770 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,21 +15,20 @@ trait Foo { fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } -default impl Foo for T { +impl Foo for MyStruct { fn foo_two(&self) -> &'static str { - "generic Clone" + self.foo_one() } } -struct MyStruct; - -fn main() { - assert!(MyStruct.foo_one() == "generic"); - assert!(0u8.foo_two() == "generic Clone"); -} +fn main() { + assert!(MyStruct.foo_two() == "generic"); +} \ No newline at end of file diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs deleted file mode 100644 index 5c0547b03414..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:foo_trait.rs - -#![feature(specialization)] - -extern crate foo_trait; - -use foo_trait::*; - -struct MyStruct; - -fn main() { - assert!(MyStruct.foo_one() == "generic"); - assert!(0u8.foo_two() == "generic Clone"); - assert!(MyStruct.foo_two() == "generic Trait"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs deleted file mode 100644 index 254d3bebb903..000000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -trait Foo { - fn foo_one(&self) -> &'static str; - fn foo_two(&self) -> &'static str { - "generic Trait" - } -} - -default impl Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo_two(&self) -> &'static str { - "generic Clone" - } -} - -struct MyStruct; - -fn main() { - assert!(MyStruct.foo_one() == "generic"); - assert!(0u8.foo_two() == "generic Clone"); - assert!(MyStruct.foo_two() == "generic Trait"); -} From b20bfb1fc283ae3b0c4f3d712919f4fc3522517b Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Tue, 21 Nov 2017 07:27:20 +0000 Subject: [PATCH 17/87] support `default impl` for specialization not skipping any wfchecks on default impls --- src/librustc/infer/mod.rs | 4 +++ src/librustc/traits/select.rs | 29 ++++++++++++------- src/librustc/ty/trait_def.rs | 12 ++------ src/librustc_typeck/check/mod.rs | 18 ++++++++++++ src/librustc_typeck/check/wfcheck.rs | 12 +------- .../defaultimpl/specialization-wfcheck.rs | 18 ++++++++++++ 6 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 07c5b319970f..a2d5af675160 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -181,6 +181,9 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. region_obligations: RefCell)>>, + + // true if trait selection in this context should emit `default impl` candiates + pub emit_defaul_impl_candidates: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -452,6 +455,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), + emit_defaul_impl_candidates: Cell::new(false) })) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d436..b58a154275ca 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1296,6 +1296,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } + // Using local cache if the infcx can emit `default impls` + if self.infcx.emit_defaul_impl_candidates.get() { + return false; + } + + // Otherwise, we can use the global cache. true } @@ -1714,18 +1720,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + if self.infcx().emit_defaul_impl_candidates.get() || + !self.tcx().impl_is_default(impl_def_id) { + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); + } + Err(_) => { } } - Err(_) => { } - } - }); + }); + } } ); diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 33972df97fb6..0fbf9f1bd587 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -92,16 +92,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self_ty: Ty<'tcx>, mut f: F) { - let mut emit_impl = |impl_def_id: DefId| { - if !self.impl_is_default(impl_def_id) { - f(impl_def_id); - } - }; - let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - emit_impl(impl_def_id); + f(impl_def_id); } // simplify_type(.., false) basically replaces type parameters and @@ -132,13 +126,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - emit_impl(impl_def_id); + f(impl_def_id); } } } else { for v in impls.non_blanket_impls.values() { for &impl_def_id in v { - emit_impl(impl_def_id); + f(impl_def_id); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4fe2f5b574e6..a622f0b67322 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1745,6 +1745,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { + FnCtxt::set_emit_default_impl_candidates(inh, body_id); + FnCtxt { body_id, param_env, @@ -1763,6 +1765,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + fn set_emit_default_impl_candidates(inh: &'a Inherited<'a, 'gcx, 'tcx>, + body_id: ast::NodeId) { + inh.infcx.emit_defaul_impl_candidates.set( + match inh.tcx.hir.find(body_id) { + Some(Node::NodeItem(..)) => { + if inh.tcx.impl_is_default(inh.tcx.hir.local_def_id(body_id)) { + true + } else { + false + } + }, + _ => false + } + ); + } + pub fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 78113bdcc0e4..3668fc46ddc2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -343,18 +343,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx.body_id, &trait_ref, ast_trait_ref.path.span); - - // not registering predicates associcated with a `default impl` - let impl_is_default = fcx.tcx.impl_is_default(item_def_id); for obligation in obligations { - let register = match obligation.predicate { - ty::Predicate::Trait(..) => !impl_is_default, - _ => true - }; - - if register { - fcx.register_predicate(obligation); - } + fcx.register_predicate(obligation); } } None => { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs new file mode 100644 index 000000000000..5f6844d0c828 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo<'a, T: Eq + 'a> { } + +default impl Foo<'static, U> for () {} +//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied + +fn main(){} \ No newline at end of file From 2a4c0185187dd40683697932c57af608062cb320 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 7 Feb 2018 12:35:52 -0700 Subject: [PATCH 18/87] Apply optimization from #44355 to retain --- src/liballoc/vec.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b26979c7f6d8..a906628dbc73 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -813,14 +813,19 @@ impl Vec { for i in 0..len { if !f(&v[i]) { del += 1; + unsafe { + ptr::read(&v[i]); + } } else if del > 0 { - v.swap(i - del, i); + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + unsafe { + ptr::copy_nonoverlapping(src, dst, 1); + } } } } - if del > 0 { - self.truncate(len - del); - } + self.len = len - del; } /// Removes all but the first of consecutive elements in the vector that resolve to the same From 31253d5557f8c161ac97028a3966d617491b86a6 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Wed, 31 Jan 2018 23:34:13 +0300 Subject: [PATCH 19/87] add transform for uniform array move out --- src/librustc_mir/transform/mod.rs | 3 + .../transform/uniform_array_move_out.rs | 153 ++++++++++++++++++ src/librustc_mir/util/patch.rs | 12 +- .../borrowck/borrowck-move-out-from-array.rs | 30 ++++ src/test/mir-opt/uniform_array_move_out.rs | 59 +++++++ src/test/run-pass/dynamic-drop.rs | 46 ++++++ 6 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 src/librustc_mir/transform/uniform_array_move_out.rs create mode 100644 src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs create mode 100644 src/test/mir-opt/uniform_array_move_out.rs diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 563405fccc97..7ed250e94c52 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -44,6 +44,7 @@ pub mod copy_prop; pub mod generator; pub mod inline; pub mod lower_128bit; +pub mod uniform_array_move_out; pub(crate) fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); @@ -197,6 +198,7 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea simplify::SimplifyCfg::new("initial"), type_check::TypeckMir, rustc_peek::SanityCheck, + uniform_array_move_out::UniformArrayMoveOut, ]; tcx.alloc_steal_mir(mir) } @@ -253,6 +255,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx lower_128bit::Lower128Bit, + // Optimizations begin. inline::Inline, instcombine::InstCombine, diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs new file mode 100644 index 000000000000..0db5ecf0eb27 --- /dev/null +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -0,0 +1,153 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This pass converts move out from array by Subslice and +// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin +// of array. It allows detect error by mir borrowck and elaborate +// drops for array without additional work. +// +// Example: +// +// let a = [ box 1,box 2, box 3]; +// if b { +// let [_a.., _] = a; +// } else { +// let [.., _b] = a; +// } +// +// mir statement _10 = move _2[:-1]; replaced by: +// StorageLive(_12); +// _12 = move _2[0 of 3]; +// StorageLive(_13); +// _13 = move _2[1 of 3]; +// _10 = [move _12, move _13] +// StorageDead(_12); +// StorageDead(_13); +// +// and mir statement _11 = move _2[-1 of 1]; replaced by: +// _11 = move _2[2 of 3]; +// +// FIXME: convert to Subslice back for performance reason +// FIXME: integrate this transformation to the mir build + +use rustc::ty; +use rustc::ty::TyCtxt; +use rustc::mir::*; +use rustc::mir::visit::Visitor; +use transform::{MirPass, MirSource}; +use util::patch::MirPatch; + +pub struct UniformArrayMoveOut; + +impl MirPass for UniformArrayMoveOut { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _src: MirSource, + mir: &mut Mir<'tcx>) { + let mut patch = MirPatch::new(mir); + { + let mut visitor = UniformArrayMoveOutVisitor{mir, patch: &mut patch, tcx}; + visitor.visit_mir(mir); + } + patch.apply(mir); + } +} + +struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + patch: &'a mut MirPatch<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location) { + if let StatementKind::Assign(ref dst_place, + Rvalue::Use(Operand::Move(ref src_place))) = statement.kind { + if let Place::Projection(ref proj) = *src_place { + if let ProjectionElem::ConstantIndex{offset: _, + min_length: _, + from_end: false} = proj.elem { + // no need to transformation + } else { + let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + if let ty::TyArray(item_ty, const_size) = place_ty.sty { + if let Some(size) = const_size.val.to_const_int().and_then(|v| v.to_u64()) { + assert!(size <= (u32::max_value() as u64), + "unform array move out doesn't supported + for array bigger then u32"); + self.uniform(location, dst_place, proj, item_ty, size as u32); + } + } + + } + } + } + return self.super_statement(block, statement, location); + } +} + +impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { + fn uniform(&mut self, + location: Location, + dst_place: &Place<'tcx>, + proj: &PlaceProjection<'tcx>, + item_ty: &'tcx ty::TyS<'tcx>, + size: u32) { + match proj.elem { + // uniform _10 = move _2[:-1]; + ProjectionElem::Subslice{from, to} => { + self.patch.make_nop(location); + let temps : Vec<_> = (from..(size-to)).map(|i| { + let temp = self.patch.new_temp(item_ty, self.mir.source_info(location).span); + self.patch.add_statement(location, StatementKind::StorageLive(temp)); + self.patch.add_assign(location, + Place::Local(temp), + Rvalue::Use( + Operand::Move( + Place::Projection(box PlaceProjection{ + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex{ + offset: i, + min_length: size, + from_end: false} + })))); + temp + }).collect(); + self.patch.add_assign(location, + dst_place.clone(), + Rvalue::Aggregate(box AggregateKind::Array(item_ty), + temps.iter().map( + |x| Operand::Move(Place::Local(*x))).collect() + )); + for temp in temps { + self.patch.add_statement(location, StatementKind::StorageDead(temp)); + } + } + // _11 = move _2[-1 of 1]; + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { + self.patch.make_nop(location); + self.patch.add_assign(location, + dst_place.clone(), + Rvalue::Use( + Operand::Move( + Place::Projection(box PlaceProjection{ + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex{ + offset: size - offset, + min_length: size, + from_end: false }})))); + } + _ => {} + } + } +} diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 9da593fb48e3..f1bdcfcd22f9 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -23,6 +23,7 @@ pub struct MirPatch<'tcx> { new_locals: Vec>, resume_block: BasicBlock, next_local: usize, + make_nop: Vec, } impl<'tcx> MirPatch<'tcx> { @@ -33,7 +34,8 @@ impl<'tcx> MirPatch<'tcx> { new_statements: vec![], new_locals: vec![], next_local: mir.local_decls.len(), - resume_block: START_BLOCK + resume_block: START_BLOCK, + make_nop: vec![] }; // make sure the MIR we create has a resume block. It is @@ -131,7 +133,15 @@ impl<'tcx> MirPatch<'tcx> { self.add_statement(loc, StatementKind::Assign(place, rv)); } + pub fn make_nop(&mut self, loc: Location) { + self.make_nop.push(loc); + } + pub fn apply(self, mir: &mut Mir<'tcx>) { + debug!("MirPatch: make nops at: {:?}", self.make_nop); + for loc in self.make_nop { + mir.make_statement_nop(loc); + } debug!("MirPatch: {:?} new temps, starting from index {}: {:?}", self.new_locals.len(), mir.local_decls.len(), self.new_locals); debug!("MirPatch: {} new blocks, starting from index {}", diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs new file mode 100644 index 000000000000..e01161734623 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(box_syntax, slice_patterns, advanced_slice_patterns)] + +fn move_out_from_begin_and_end() { + let a = [box 1, box 2]; + let [_, _x] = a; + let [.., _y] = a; //[ast]~ ERROR [E0382] + //[mir]~^ ERROR [E0382] +} + +fn move_out_by_const_index_and_subslice() { + let a = [box 1, box 2]; + let [_x, _] = a; + let [_y..] = a; //[ast]~ ERROR [E0382] + //[mir]~^ ERROR [E0382] +} + +fn main() {} diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs new file mode 100644 index 000000000000..4a310255aac5 --- /dev/null +++ b/src/test/mir-opt/uniform_array_move_out.rs @@ -0,0 +1,59 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax, slice_patterns, advanced_slice_patterns)] + +fn move_out_from_end() { + let a = [box 1, box 2]; + let [.., _y] = a; +} + +fn move_out_by_subslice() { + let a = [box 1, box 2]; + let [_y..] = a; +} + +fn main() { + move_out_by_subslice(); + move_out_from_end(); +} + +// END RUST SOURCE + +// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir +// StorageLive(_6); +// _6 = move _1[-1 of 1]; +// _0 = (); +// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir + +// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir +// StorageLive(_6); +// _6 = move _1[1 of 2]; +// nop; +// _0 = (); +// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir + +// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir +// StorageLive(_6); +// _6 = move _1[0:]; +// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir + +// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir +// StorageLive(_6); +// StorageLive(_7); +// _7 = move _1[0 of 2]; +// StorageLive(_8); +// _8 = move _1[1 of 2]; +// _6 = [move _7, move _8]; +// StorageDead(_7); +// StorageDead(_8); +// nop; +// _0 = (); +// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 09318e7256fd..6a1078caec0f 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -222,6 +222,43 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { }; } +fn subslice_pattern_from_end(a: &Allocator, arg: bool) { + let a = [a.alloc(), a.alloc(), a.alloc()]; + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + +fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { + let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + if arg2 { + drop(a); + return; + } + + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + +fn slice_pattern_reassign(a: &Allocator) { + let mut ar = [a.alloc(), a.alloc()]; + let[_, _x] = ar; + ar = [a.alloc(), a.alloc()]; + let[.., _y] = ar; +} + +fn subslice_pattern_reassign(a: &Allocator) { + let mut ar = [a.alloc(), a.alloc(), a.alloc()]; + let[_, _, _x] = ar; + ar = [a.alloc(), a.alloc(), a.alloc()]; + let[_, _y..] = ar; +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -300,5 +337,14 @@ fn main() { run_test(|a| slice_pattern_one_of(a, 2)); run_test(|a| slice_pattern_one_of(a, 3)); + run_test(|a| subslice_pattern_from_end(a, true)); + run_test(|a| subslice_pattern_from_end(a, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test(|a| slice_pattern_reassign(a)); + run_test(|a| subslice_pattern_reassign(a)); + run_test_nopanic(|a| union1(a)); } From a67749ae87b1c873ed09fca2a204beff2fe5e7ea Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 8 Feb 2018 08:27:53 -0700 Subject: [PATCH 20/87] Swap `ptr::read` for `ptr::drop_in_place` --- src/liballoc/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index a906628dbc73..41ba8e12105b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -814,7 +814,7 @@ impl Vec { if !f(&v[i]) { del += 1; unsafe { - ptr::read(&v[i]); + ptr::drop_in_place(&mut v[i]); } } else if del > 0 { let src: *const T = &v[i]; From d49d428f791b97c476c066deb9c2b3c20165199f Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 8 Feb 2018 17:36:17 -0200 Subject: [PATCH 21/87] Revert checking casts before fallback. This turns out to not be backwards compatible. --- src/librustc_typeck/check/cast.rs | 11 +---------- src/librustc_typeck/check/mod.rs | 25 ++++++++----------------- src/test/run-pass/cast-does-fallback.rs | 4 ++++ src/test/ui/issue-45730.rs | 4 ---- src/test/ui/issue-45730.stderr | 8 ++++---- 5 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index dae5ba14bfb5..48bd7b14fc96 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, Fallback, FnCtxt}; +use super::{Diverges, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -290,9 +290,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { - if fcx.is_tainted_by_errors() { - return; - } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, @@ -396,12 +393,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - // For backwards compatibility we apply numeric fallback here. This means that in: - // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. - if self.expr_ty.is_ty_infer() { - fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0395b3eb4aa2..f50bd03a9e07 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,17 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.check_casts(); - // All type checking constraints were added, try to fallback unsolved variables. fcx.select_obligations_where_possible(); for ty in &fcx.unsolved_variables() { - fcx.fallback_if_possible(ty, Fallback::Full); + fcx.fallback_if_possible(ty); } fcx.select_obligations_where_possible(); + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + // Closure and generater analysis may run after fallback - // because they doen't constrain other type variables. + // because they don't constrain other type variables. fcx.closure_analyze(body); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); @@ -1734,12 +1736,6 @@ enum TupleArgumentsFlag { TupleArguments, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Fallback { - Full, - Numeric -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2149,7 +2145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to TyError. - fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + fn fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2158,12 +2154,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => { - match fallback { - Fallback::Full => self.tcx.mk_diverging_default(), - Fallback::Numeric => return, - } - } + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs index 86d6e387b255..aa6752ffc35b 100644 --- a/src/test/run-pass/cast-does-fallback.rs +++ b/src/test/run-pass/cast-does-fallback.rs @@ -9,6 +9,10 @@ // except according to those terms. pub fn main() { + // Test that these type check correctly. + (&42u8 >> 4) as usize; + (&42u8 << 4) as usize; + let cap = 512 * 512; cap as u8; // Assert `cap` did not get inferred to `u8` and overflowed. diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index 1fe0b1ae2d24..d733c8e6de26 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,13 +11,9 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast -} -fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; -} -fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 13205eead436..94d39239117a 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:17:23 + --> $DIR/issue-45730.rs:15:23 | -17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:22:13 + --> $DIR/issue-45730.rs:18:13 | -22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information From 4f8049a2b00c46cb1ac77cabaaf716895f185afe Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 01:47:18 -0800 Subject: [PATCH 22/87] Add Range[Inclusive]::is_empty During the RFC, it was discussed that figuring out whether a range is empty was subtle, and thus there should be a clear and obvious way to do it. It can't just be ExactSizeIterator::is_empty (also unstable) because not all ranges are ExactSize -- not even Range or RangeInclusive. --- src/libcore/iter/traits.rs | 2 +- src/libcore/ops/range.rs | 36 ++++++++++++++++++++++++++++++++++-- src/libcore/tests/iter.rs | 4 ++-- src/libcore/tests/lib.rs | 1 + src/libcore/tests/ops.rs | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index be4889f24877..860742d9eab6 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator { /// ``` /// #![feature(exact_size_is_empty)] /// - /// let mut one_element = 0..1; + /// let mut one_element = std::iter::once(0); /// assert!(!one_element.is_empty()); /// /// assert_eq!(one_element.next(), Some(0)); diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb6..102e08362cb4 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -92,7 +92,6 @@ impl fmt::Debug for Range { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { /// Returns `true` if `item` is contained in the range. /// @@ -109,9 +108,26 @@ impl> Range { /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty)] + /// + /// assert!(!(3..5).is_empty()); + /// assert!( (3..3).is_empty()); + /// assert!( (3..2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start < self.end) + } } /// A range only bounded inclusively below (`start..`). @@ -280,7 +296,6 @@ impl fmt::Debug for RangeInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// @@ -298,9 +313,26 @@ impl> RangeInclusive { /// assert!( (3..=3).contains(3)); /// assert!(!(3..=2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// assert!(!(3..=5).is_empty()); + /// assert!(!(3..=3).is_empty()); + /// assert!( (3..=2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start <= self.end) + } } /// A range only bounded inclusively above (`..=end`). diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67..062b6d4126e2 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1427,9 +1427,9 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); assert_eq!(r, 1..=0); // We may not want to document/promise this detail } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c32452f8463..91b4f02594bc 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(iter_rfold)] #![feature(nonzero)] #![feature(pattern)] +#![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 9d2fa1abff65..68a692b24a3f 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -68,3 +68,27 @@ fn test_range_inclusive() { assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } + + +#[test] +fn test_range_is_empty() { + use core::f32::*; + + assert!(!(0.0 .. 10.0).is_empty()); + assert!( (-0.0 .. 0.0).is_empty()); + assert!( (10.0 .. 0.0).is_empty()); + + assert!(!(NEG_INFINITY .. INFINITY).is_empty()); + assert!( (EPSILON .. NAN).is_empty()); + assert!( (NAN .. EPSILON).is_empty()); + assert!( (NAN .. NAN).is_empty()); + + assert!(!(0.0 ..= 10.0).is_empty()); + assert!(!(-0.0 ..= 0.0).is_empty()); + assert!( (10.0 ..= 0.0).is_empty()); + + assert!(!(NEG_INFINITY ..= INFINITY).is_empty()); + assert!( (EPSILON ..= NAN).is_empty()); + assert!( (NAN ..= EPSILON).is_empty()); + assert!( (NAN ..= NAN).is_empty()); +} \ No newline at end of file From 7fe182fdfe01e01dd899962cc8dbaea63f422c9c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 02:11:04 -0800 Subject: [PATCH 23/87] Fix tidy --- src/libcore/tests/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 68a692b24a3f..bed08f86d72c 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -91,4 +91,4 @@ fn test_range_is_empty() { assert!( (EPSILON ..= NAN).is_empty()); assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); -} \ No newline at end of file +} From 2f22a929c6d231d9a9d872ac40b5c9e36daabe38 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 7 Feb 2018 06:58:01 +0000 Subject: [PATCH 24/87] add Self: Trait<..> inside the param_env of a default impl --- src/librustc/infer/mod.rs | 4 --- src/librustc/traits/select.rs | 27 ++++++++++++++----- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/mod.rs | 25 ++++++++++++++++- src/librustc_typeck/check/mod.rs | 18 ------------- ...ecialization-trait-item-not-implemented.rs | 2 +- .../specialization-trait-not-implemented.rs | 2 +- .../defaultimpl/specialization-wfcheck.rs | 2 +- ...ecialization-trait-item-not-implemented.rs | 2 +- 9 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a2d5af675160..07c5b319970f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -181,9 +181,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. region_obligations: RefCell)>>, - - // true if trait selection in this context should emit `default impl` candiates - pub emit_defaul_impl_candidates: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -455,7 +452,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), - emit_defaul_impl_candidates: Cell::new(false) })) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index b58a154275ca..aa43bf8ca2ef 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1296,12 +1296,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } - // Using local cache if the infcx can emit `default impls` - if self.infcx.emit_defaul_impl_candidates.get() { - return false; - } - - // Otherwise, we can use the global cache. true } @@ -1716,11 +1710,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + // Check if default impls should be emitted. + // default impls are emitted if the param_env is refered to a default impl. + // The param_env should contain a Self: Trait<..> predicate in those cases + let self_trait_is_present:Vec<&ty::Predicate<'tcx>> = + obligation.param_env + .caller_bounds + .iter() + .filter(|predicate| { + match **predicate { + ty::Predicate::Trait(ref trait_predicate) => { + trait_predicate.def_id() == + obligation.predicate.def_id() && + obligation.predicate.0.trait_ref.self_ty() == + trait_predicate.skip_binder().self_ty() + } + _ => false + } + }).collect::>>(); + self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self.infcx().emit_defaul_impl_candidates.get() || + if self_trait_is_present.len() > 0 || !self.tcx().impl_is_default(impl_def_id) { self.probe(|this, snapshot| { /* [1] */ match this.match_impl(impl_def_id, obligation, snapshot) { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 6c727c94f58c..63bf52a9bdf7 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; -use ty::subst::{Kind, Subst}; +use ty::subst::Kind; use traits; use syntax::abi::Abi; use util::ppaux; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc..52d33c750f86 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,8 +2606,31 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. + let mut predicates = tcx.predicates_of(def_id); + match tcx.hir.as_local_node_id(def_id) + .and_then(|node_id| tcx.hir.find(node_id)) + .and_then(|item| { + match item { + hir::map::NodeItem(..) => { + if tcx.impl_is_default(def_id) { + tcx.impl_trait_ref(def_id) + } else { + None + } + } + _ => None + } + }) { + Some(trait_ref) => + predicates.predicates + .push( + trait_ref.to_poly_trait_ref() + .to_predicate() + ), + None => {} + } - let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); + let bounds = predicates.instantiate_identity(tcx); let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a622f0b67322..4fe2f5b574e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1745,8 +1745,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { - FnCtxt::set_emit_default_impl_candidates(inh, body_id); - FnCtxt { body_id, param_env, @@ -1765,22 +1763,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn set_emit_default_impl_candidates(inh: &'a Inherited<'a, 'gcx, 'tcx>, - body_id: ast::NodeId) { - inh.infcx.emit_defaul_impl_candidates.set( - match inh.tcx.hir.find(body_id) { - Some(Node::NodeItem(..)) => { - if inh.tcx.impl_is_default(inh.tcx.hir.local_def_id(body_id)) { - true - } else { - false - } - }, - _ => false - } - ); - } - pub fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 323ff7b2db9d..072507851d79 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -28,4 +28,4 @@ impl Foo for MyStruct {} fn main() { println!("{}", MyStruct.foo_one()); -} \ No newline at end of file +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index 36945e98b088..d020a6775772 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -27,4 +27,4 @@ default impl Foo for T { fn main() { println!("{}", MyStruct.foo_one()); //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope -} \ No newline at end of file +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 5f6844d0c828..342297379928 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -15,4 +15,4 @@ trait Foo<'a, T: Eq + 'a> { } default impl Foo<'static, U> for () {} //~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied -fn main(){} \ No newline at end of file +fn main(){} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index f8eb57bad770..e11a30214974 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -31,4 +31,4 @@ impl Foo for MyStruct { fn main() { assert!(MyStruct.foo_two() == "generic"); -} \ No newline at end of file +} From b5cb393cf5b4a65fb99d8b1e43450fb87567788b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 17:54:27 -0800 Subject: [PATCH 25/87] Use is_empty in range iteration exhaustion tests --- src/libcore/ops/range.rs | 18 ++++++++++++ src/libcore/tests/iter.rs | 61 +++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 102e08362cb4..cce593ee208b 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -262,6 +262,13 @@ impl> RangeTo { /// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. /// +/// This iterator is [fused], but the specific values of `start` and `end` after +/// iteration has finished are **unspecified** other than that [`.is_empty()`] +/// will return `true` once no more values will be produced. +/// +/// [fused]: ../iter/trait.FusedIterator.html +/// [`.is_empty()`]: #method.is_empty +/// /// # Examples /// /// ``` @@ -329,6 +336,17 @@ impl> RangeInclusive { /// assert!(!(3..=3).is_empty()); /// assert!( (3..=2).is_empty()); /// ``` + /// + /// This method returns `true` after iteration has finished: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// let mut r = 3..=5; + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(r.is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 062b6d4126e2..d8c9dcd86648 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1322,42 +1322,84 @@ fn test_range() { (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))); } +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + #[test] fn test_range_inclusive_exhaustion() { let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); assert_eq!(r.next(), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.next_back(), Some(12)); assert_eq!(r.next_back(), Some(11)); assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 100..=10; assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); assert_eq!(r, 100..=10); let mut r = 100..=10; assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); assert_eq!(r, 100..=10); } @@ -1427,10 +1469,11 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); assert_eq!(ExactSizeIterator::is_empty(&r), true); - assert_eq!(r, 1..=0); // We may not want to document/promise this detail } #[test] @@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() { let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); } #[test] From 6f70a11a831992fe86a935a0d649d3aa6b16dc50 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 18:01:12 -0800 Subject: [PATCH 26/87] range_is_empty tracking issue is #48111 --- src/libcore/ops/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index cce593ee208b..4e4d33475237 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -124,7 +124,7 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) } @@ -347,7 +347,7 @@ impl> RangeInclusive { /// // Precise field values are unspecified here /// assert!(r.is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) } From e236994c5e4c448fba3c02874f875b0844e43725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 31 Jan 2018 16:08:14 +0100 Subject: [PATCH 27/87] Add a `fatal_cycle` attribute for queries which indicates that they will cause a fatal error on query cycles --- src/librustc/ty/maps/mod.rs | 19 ++++++++++++------- src/librustc/ty/maps/plumbing.rs | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 85fca68187fe..21ffe6b895e7 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -78,6 +78,11 @@ pub use self::on_disk_cache::OnDiskCache; // a way that memoizes and does dep-graph tracking, // wrapping around the actual chain of providers that // the driver creates (using several `rustc_*` crates). +// +// The result of query must implement Clone. They must also implement ty::maps::values::Value +// which produces an appropiate error value if the query resulted in a query cycle. +// Queries marked with `fatal_cycle` do not need that implementation +// as they will raise an fatal error on query cycles instead. define_maps! { <'tcx> /// Records the type of every item. [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, @@ -267,13 +272,13 @@ define_maps! { <'tcx> [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) -> Rc>, - [] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, - [] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, - [] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, - [] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, - [] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, - [] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, - [] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, + [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, + [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, + [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, + [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, + [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, [] fn extern_crate: ExternCrate(DefId) -> Rc>, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9..f02c7cbd0ea3 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -183,6 +183,19 @@ macro_rules! profq_key { } } +macro_rules! handle_cycle_error { + ([][$this: expr]) => {{ + Value::from_cycle_error($this.global_tcx()) + }}; + ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ + $this.tcx.sess.abort_if_errors(); + unreachable!(); + }}; + ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { + handle_cycle_error!([$($modifiers),*][$($args)*]) + }; +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -564,7 +577,7 @@ macro_rules! define_maps { pub fn $name(self, key: $K) -> $V { queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|mut e| { e.emit(); - Value::from_cycle_error(self.global_tcx()) + handle_cycle_error!([$($modifiers)*][self]) }) })* } @@ -583,7 +596,7 @@ macro_rules! define_maps { macro_rules! define_map_struct { (tcx: $tcx:tt, - input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { + input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Maps<$tcx> { providers: IndexVec>, query_stack: RefCell)>>, From 0cccd9aca51e3fe2952633b34c4c877539d1113d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Feb 2018 14:57:08 +0100 Subject: [PATCH 28/87] Show better warning for trying to cast non-u8 scalar to char --- src/librustc_lint/types.rs | 17 +++++++++++++++++ src/test/ui/cast_char.rs | 20 ++++++++++++++++++++ src/test/ui/cast_char.stderr | 20 ++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/cast_char.rs create mode 100644 src/test/ui/cast_char.stderr diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e7e4119b9999..f734f3182a93 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,6 +11,7 @@ #![allow(non_snake_case)] use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; @@ -176,6 +177,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => bug!(), }; if lit_val < min || lit_val > max { + let parent_id = cx.tcx.hir.get_parent_node(e.id); + if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) { + if let hir::ExprCast(..) = parent_expr.node { + if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + parent_expr.span, + "only u8 can be casted into char"); + err.span_suggestion(parent_expr.span, + &"use a char literal instead", + format!("'\\u{{{:X}}}'", lit_val)); + err.emit(); + return + } + } + } cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs new file mode 100644 index 000000000000..cd8ade5e51a1 --- /dev/null +++ b/src/test/ui/cast_char.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(overflowing_literals)] + +fn main() { + const XYZ: char = 0x1F888 as char; + //~^ ERROR only u8 can be casted into char + const XY: char = 129160 as char; + //~^ ERROR only u8 can be casted into char + const ZYX: char = '\u{01F888}'; + println!("{}", XYZ); +} diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr new file mode 100644 index 000000000000..e42a38dace9d --- /dev/null +++ b/src/test/ui/cast_char.stderr @@ -0,0 +1,20 @@ +error: only u8 can be casted into char + --> $DIR/cast_char.rs:14:23 + | +14 | const XYZ: char = 0x1F888 as char; + | ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + | +note: lint level defined here + --> $DIR/cast_char.rs:11:9 + | +11 | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: only u8 can be casted into char + --> $DIR/cast_char.rs:16:22 + | +16 | const XY: char = 129160 as char; + | ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + +error: aborting due to 2 previous errors + From 14f488ee7d05c39b8d6ea2855da274157555df0b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 19:22:04 +0300 Subject: [PATCH 29/87] Whitelist pclmul x86 feature flag Relevant `stdsimd` [issue](https://github.com/rust-lang-nursery/stdsimd/issues/318). --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 843231d376f6..f719562b4764 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", + "xsaves\0", "aes\0", "pclmul\0" "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 877272ba066dd81d9d920b851d0300bb3e7ee2b3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 20:07:37 +0300 Subject: [PATCH 30/87] typo fix --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index f719562b4764..21def37e5e6e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0" + "xsaves\0", "aes\0", "pclmul\0", "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 3c01dea03e1b4ffbcb665a68bcf228c02497ecdc Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 10 Feb 2018 21:29:10 +0100 Subject: [PATCH 31/87] Add comment about the problem, and use provided path if available --- src/bootstrap/native.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bb482813a23f..108b0159dce7 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,11 +155,18 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + // By default, LLVM will automatically find OCaml and, if it finds it, + // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults + // to /usr/bin/ocaml. + // This causes problem for non-root builds of Rust. Side-step the issue + // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs + // in the prefix. + cfg.define("LLVM_OCAML_INSTALL_PATH", + env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space From 45d5a420ada9c11f61347fd4c63c7f0234adaea7 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 10 Feb 2018 21:20:42 +0000 Subject: [PATCH 32/87] Correct a few stability attributes --- src/libcore/num/mod.rs | 6 +++--- src/libcore/ptr.rs | 4 ++-- src/libcore/time.rs | 4 ++-- src/libstd/io/cursor.rs | 2 +- src/libstd/path.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c777..21d4a486b983 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe66..b266771b818e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25b..b8d0719b9b99 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5ba..76bcb5fedc94 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949ed..e03a182653e5 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874a..f8dbc4d0f453 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -538,7 +538,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) From 8be306840f89b92ee49d2c0fae2b189c45706b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:27:21 +0300 Subject: [PATCH 33/87] added conversion from Rust feature to LLVM feature --- src/librustc_trans/attributes.rs | 5 +-- src/librustc_trans/llvm_util.rs | 62 +++++++++++++++++--------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 6c8088375c4b..8309c91ab257 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -142,7 +142,7 @@ pub fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|c| c.to_str().unwrap().to_string()) + .map(|c| c.to_string()) .collect()) }; @@ -212,7 +212,8 @@ fn from_target_feature( let value = value.as_str(); for feature in value.split(',') { if whitelist.contains(feature) { - target_features.push(format!("+{}", feature)); + let llvm_feature = llvm_util::to_llvm_feature(feature); + target_features.push(format!("+{}", llvm_feature)); continue } diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 21def37e5e6e..61eefb32e099 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -79,45 +79,54 @@ unsafe fn configure_llvm(sess: &Session) { // detection code will walk past the end of the feature array, // leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"]; +const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"]; -const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"]; +const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"]; -const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", - "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", - "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", - "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", - "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0", - "avx512bw\0", "avx512cd\0", - "avx512dq\0", "avx512er\0", - "avx512f\0", "avx512ifma\0", - "avx512pf\0", "avx512vbmi\0", - "avx512vl\0", "avx512vpopcntdq\0", - "mmx\0", "fxsr\0"]; +const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse", + "sse2", "sse3", "sse4.1", "sse4.2", + "ssse3", "tbm", "lzcnt", "popcnt", + "sse4a", "rdrnd", "rdseed", "fma", + "xsave", "xsaveopt", "xsavec", + "xsaves", "aes", "pclmulqdq", + "avx512bw", "avx512cd", + "avx512dq", "avx512er", + "avx512f", "avx512ifma", + "avx512pf", "avx512vbmi", + "avx512vl", "avx512vpopcntdq", + "mmx", "fxsr"]; -const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"]; +const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"]; -const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0", - "power8-altivec\0", "power9-altivec\0", - "power8-vector\0", "power9-vector\0", - "vsx\0"]; +const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", + "power8-altivec", "power9-altivec", + "power8-vector", "power9-vector", + "vsx"]; -const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"]; +const MIPS_WHITELIST: &'static [&'static str] = &["msa"]; + +pub fn to_llvm_feature(s: &str) -> &str { + match s { + "pclmulqdq" => "pclmul", + s => s, + } +} pub fn target_features(sess: &Session) -> Vec { let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); let mut features = Vec::new(); - for feat in whitelist { - if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } { - features.push(Symbol::intern(feat.to_str().unwrap())); + for feature in whitelist { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { + features.push(Symbol::intern(feature)); } } features } -pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { +pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { let whitelist = match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, @@ -126,10 +135,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { "mips" | "mips64" => MIPS_WHITELIST, "powerpc" | "powerpc64" => POWERPC_WHITELIST, _ => &[], - }; - whitelist.iter().map(|m| { - CStr::from_bytes_with_nul(m.as_bytes()).unwrap() - }).collect() + } } pub fn print_version() { From c97aa0911785fc1c1306b38e978093b3153666ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:36:22 +0300 Subject: [PATCH 34/87] iterator instead loop --- src/librustc_trans/llvm_util.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 61eefb32e099..8839129f3f88 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -113,17 +113,15 @@ pub fn to_llvm_feature(s: &str) -> &str { } pub fn target_features(sess: &Session) -> Vec { - let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); - let mut features = Vec::new(); - for feature in whitelist { - let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); - if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { - features.push(Symbol::intern(feature)); - } - } - features + target_feature_whitelist(sess) + .iter() + .filter(|feature| { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + }) + .map(Symbol::intern).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { From 161e8ffda79d25ef7a570bf0c0d884201267c6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 11 Feb 2018 00:56:24 +0100 Subject: [PATCH 35/87] typo: correct endianess to endianness (this also changes function names!) --- src/librustc_mir/interpret/memory.rs | 32 ++++++++++++++-------------- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c4..7cc4ba848952 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { self.tcx.data_layout.pointer_size.bytes() } - pub fn endianess(&self) -> layout::Endian { + pub fn endianness(&self) -> layout::Endian { self.tcx.data_layout.endian } @@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! @@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } // Now we do the actual reading let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 + read_target_int(endianness, bytes).unwrap() as u128 } else { - read_target_uint(endianess, bytes).unwrap() + read_target_uint(endianness, bytes).unwrap() }; // See if we got a pointer if size != self.pointer_size() { @@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { @@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); + write_target_int(endianness, dst, bytes as i128).unwrap(); } else { - write_target_uint(endianess, dst, bytes).unwrap(); + write_target_uint(endianness, dst, bytes).unwrap(); } } @@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } //////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess +// Methods to access integers in the target endianness //////////////////////////////////////////////////////////////////////////////// fn write_target_uint( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_uint128::(data, len), layout::Endian::Big => target.write_uint128::(data, len), } } fn write_target_int( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: i128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_int128::(data, len), layout::Endian::Big => target.write_int128::(data, len), } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ecf68f29d6f1..a760922115ae 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1023,7 +1023,7 @@ impl f32 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 29ba7d0dac63..6f34f176a971 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -978,7 +978,7 @@ impl f64 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how From 7c6adb475abef794cc6b81f6a21094f3257ee37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 03:27:04 +0300 Subject: [PATCH 36/87] fixed errors --- src/librustc_trans/llvm_util.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 8839129f3f88..1f921513fe62 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -14,7 +14,7 @@ use llvm; use rustc::session::Session; use rustc::session::config::PrintRequest; use libc::c_int; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; @@ -118,14 +118,14 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); + let ptr = CString::new(llvm_feature).unwrap().as_ptr(); unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } }) - .map(Symbol::intern).collect() + .map(|feature| Symbol::intern(feature)).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { - let whitelist = match &*sess.target.target.arch { + match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, "x86" | "x86_64" => X86_WHITELIST, From 22b0489f80dae5242f19c4ce892b50d3685dbf82 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 10 Feb 2018 16:32:05 -0800 Subject: [PATCH 37/87] Add the emptiness condition to the docs; add a PartialOrd example with NAN --- src/libcore/ops/range.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 4e4d33475237..8a45444f1ab0 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -124,6 +124,17 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..5.0).is_empty()); + /// assert!( (3.0..NAN).is_empty()); + /// assert!( (NAN..5.0).is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) @@ -260,7 +271,7 @@ impl> RangeTo { /// An range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. +/// and `x <= end`. It is empty unless `start <= end`. /// /// This iterator is [fused], but the specific values of `start` and `end` after /// iteration has finished are **unspecified** other than that [`.is_empty()`] @@ -337,6 +348,17 @@ impl> RangeInclusive { /// assert!( (3..=2).is_empty()); /// ``` /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..=5.0).is_empty()); + /// assert!( (3.0..=NAN).is_empty()); + /// assert!( (NAN..=5.0).is_empty()); + /// ``` + /// /// This method returns `true` after iteration has finished: /// /// ``` From 8c506f9dae5664fb04bf070f1422df5308d90cb6 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Feb 2018 13:40:23 -0700 Subject: [PATCH 38/87] Implement excluding a build-step via --exclude --- src/bootstrap/builder.rs | 31 ++++++++++++++++++++++++++----- src/bootstrap/config.rs | 2 ++ src/bootstrap/flags.rs | 7 +++++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 74dd4a6fa014..b65c20e398e8 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -119,7 +119,28 @@ impl StepDescription { } } - fn maybe_run(&self, builder: &Builder, path: Option<&Path>) { + fn maybe_run(&self, builder: &Builder, should_run: &ShouldRun, path: Option<&Path>) { + if let Some(path) = path { + if builder.config.exclude.iter().any(|e| e == path) { + eprintln!("Skipping {:?} because this path is excluded", path); + return; + } else if !builder.config.exclude.is_empty() { + eprintln!("{:?} not skipped -- not in {:?}", path, builder.config.exclude); + } + } else { + if !should_run.paths.is_empty() { + if should_run.paths.iter().all(|p| builder.config.exclude.contains(&p)) { + eprintln!("Skipping because all of its paths ({:?}) are excluded", + should_run.paths); + return; + } else if should_run.paths.len() > 1 { + for path in &should_run.paths { + self.maybe_run(builder, should_run, Some(path)); + } + return; + } + } + } let build = builder.build; let hosts = if self.only_build_targets || self.only_build { build.build_triple() @@ -160,7 +181,7 @@ impl StepDescription { if paths.is_empty() { for (desc, should_run) in v.iter().zip(should_runs) { if desc.default && should_run.is_really_default { - desc.maybe_run(builder, None); + desc.maybe_run(builder, &should_run, None); } } } else { @@ -169,7 +190,7 @@ impl StepDescription { for (desc, should_run) in v.iter().zip(&should_runs) { if should_run.run(path) { attempted_run = true; - desc.maybe_run(builder, Some(path)); + desc.maybe_run(builder, &should_run, Some(path)); } } @@ -208,13 +229,13 @@ impl<'a> ShouldRun<'a> { pub fn krate(mut self, name: &str) -> Self { for (_, krate_path) in self.builder.crates(name) { - self.paths.insert(PathBuf::from(krate_path)); + self.paths.insert(t!(env::current_dir()).join(krate_path)); } self } pub fn path(mut self, path: &str) -> Self { - self.paths.insert(PathBuf::from(path)); + self.paths.insert(t!(env::current_dir()).join(path)); self } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4f4fd14ae8ca..812ca6d64fb6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -56,6 +56,7 @@ pub struct Config { pub sanitizers: bool, pub profiler: bool, pub ignore_git: bool, + pub exclude: Vec, pub run_host_only: bool, @@ -311,6 +312,7 @@ impl Config { let flags = Flags::parse(&args); let file = flags.config.clone(); let mut config = Config::default(); + config.exclude = flags.exclude; config.llvm_enabled = true; config.llvm_optimize = true; config.llvm_version_check = true; diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 478e496078ad..465ebf846d3d 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,7 @@ pub struct Flags { pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, + pub exclude: Vec, } pub enum Subcommand { @@ -109,6 +110,7 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); + opts.optmulti("", "exclude", "build paths to exclude", "PATH"); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optopt("", "stage", "stage to build", "N"); opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); @@ -358,10 +360,9 @@ Arguments: stage = Some(1); } - let cwd = t!(env::current_dir()); let src = matches.opt_str("src").map(PathBuf::from) .or_else(|| env::var_os("SRC").map(PathBuf::from)) - .unwrap_or(cwd); + .unwrap_or(cwd.clone()); Flags { verbose: matches.opt_count("verbose"), @@ -378,6 +379,8 @@ Arguments: jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd, incremental: matches.opt_present("incremental"), + exclude: split(matches.opt_strs("exclude")) + .into_iter().map(|p| cwd.join(p)).collect::>(), } } } From 11580b7be3a830ccea569b64545ec77008c452ac Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 10 Feb 2018 18:15:34 -0700 Subject: [PATCH 39/87] Make exclude and paths relative to root of checkout --- src/bootstrap/flags.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 465ebf846d3d..8a38fedc6136 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -275,7 +275,12 @@ Arguments: }; // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); - let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + let src = matches.opt_str("src").map(PathBuf::from) + .or_else(|| env::var_os("SRC").map(PathBuf::from)) + .unwrap_or(cwd.clone()); + let paths = matches.free[1..].iter().map(|p| { + cwd.join(p).strip_prefix(&src).expect("paths passed to be inside checkout").into() + }).collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -360,10 +365,6 @@ Arguments: stage = Some(1); } - let src = matches.opt_str("src").map(PathBuf::from) - .or_else(|| env::var_os("SRC").map(PathBuf::from)) - .unwrap_or(cwd.clone()); - Flags { verbose: matches.opt_count("verbose"), stage, @@ -375,12 +376,14 @@ Arguments: target: split(matches.opt_strs("target")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), config: cfg_file, - src, jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd, incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) - .into_iter().map(|p| cwd.join(p)).collect::>(), + .into_iter().map(|p| { + cwd.join(p).strip_prefix(&src).expect("paths to be inside checkout").into() + }).collect::>(), + src, } } } From 55c36e37443e6fa4252157d4bc47b49b3d6e201d Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 10 Feb 2018 18:18:41 -0700 Subject: [PATCH 40/87] Remove DontDistWithMiri struct and instead just directly check it in builder --- src/bootstrap/builder.rs | 9 +++++++-- src/bootstrap/dist.rs | 25 ------------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b65c20e398e8..32cc1d7223db 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -286,8 +286,7 @@ impl<'a> Builder<'a> { doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook), Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, - dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign, - dist::DontDistWithMiriEnabled), + dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign), Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls, install::Rustfmt, install::Analysis, install::Src, install::Rustc), } @@ -344,6 +343,12 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), }; + if kind == Kind::Dist { + assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\ + The distributed libraries would include all MIR (increasing binary size). + The distributed MIR would include validation statements."); + } + StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths); } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 460fb016f16e..e7aed7eb4fea 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1233,31 +1233,6 @@ impl Step for Rustfmt { } } - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct DontDistWithMiriEnabled; - -impl Step for DontDistWithMiriEnabled { - type Output = PathBuf; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - let build_miri = run.builder.build.config.test_miri; - run.default_condition(build_miri) - } - - fn make_run(run: RunConfig) { - run.builder.ensure(DontDistWithMiriEnabled); - } - - fn run(self, _: &Builder) -> PathBuf { - panic!("Do not distribute with miri enabled.\n\ - The distributed libraries would include all MIR (increasing binary size). - The distributed MIR would include validation statements."); - } -} - - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, From bf69b0feed33f40ddbef2940b9a3d99845982153 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 26 Jan 2018 03:14:20 +0800 Subject: [PATCH 41/87] Upgrade the Travis CI macOS images for testing from Xcode 8.3 to 9.2. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1007aad925d9..280da0569950 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto - env: > @@ -70,7 +70,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto # OSX builders producing releases. These do not run the full test suite and From c2a31dee835c2312a9e527b1f9ea1b77c24beeab Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 11 Feb 2018 15:57:07 +0300 Subject: [PATCH 42/87] Dangling pointer fix --- src/librustc_trans/llvm_util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 1f921513fe62..b25562252e72 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -118,8 +118,8 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).unwrap().as_ptr(); - unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + let cstr = CString::new(llvm_feature).unwrap(); + unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } }) .map(|feature| Symbol::intern(feature)).collect() } From f104b120595d21e8aef311bc0057b3f854cddfc0 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 11 Feb 2018 09:51:58 -0700 Subject: [PATCH 43/87] Change Step to be invoked with a path when in default mode. Previously, a Step would be able to tell on its own when it was invoked "by-default" (that is, `./x.py test` was called instead of `./x.py test some/path`). This commit replaces that functionality, invoking each Step with each of the paths it has specified as "should be invoked by." For example, if a step calls `path("src/tools/cargo")` and `path("src/doc/cargo")` then it's make_run will be called twice, with "src/tools/cargo" and "src/doc/cargo." This makes it so that default handling logic is in builder, instead of spread across various Steps. However, this meant that some Step specifications needed to be updated, since for example `rustdoc` can be built by `./x.py build src/librustdoc` or `./x.py build src/tools/rustdoc`. A `PathSet` abstraction is added that handles this: now, each Step can not only list `path(...)` but also `paths(&[a, b, ...])` which will make it so that we don't invoke it with each of the individual paths, instead invoking it with the first path in the list (though this shouldn't be depended on). Future work likely consists of implementing a better/easier way for a given Step to work with "any" crate in-tree, especially those that want to run tests, build, or check crates in the std, test, or rustc crate trees. Currently this is rather painful to do as most of the logic is duplicated across should_run and make_run. It seems likely this can be abstracted away into builder somehow. --- src/bootstrap/builder.rs | 125 ++++++--- src/bootstrap/check.rs | 6 +- src/bootstrap/compile.rs | 10 +- src/bootstrap/doc.rs | 2 +- src/bootstrap/lib.rs | 37 +-- src/bootstrap/native.rs | 4 +- src/bootstrap/test.rs | 559 +++++++++++++++++++++------------------ 7 files changed, 423 insertions(+), 320 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 32cc1d7223db..cbd303e11406 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -95,7 +95,7 @@ pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, pub host: Interned, pub target: Interned, - pub path: Option<&'a Path>, + pub path: &'a Path, } struct StepDescription { @@ -105,6 +105,28 @@ struct StepDescription { only_build: bool, should_run: fn(ShouldRun) -> ShouldRun, make_run: fn(RunConfig), + name: &'static str, +} + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +struct PathSet { + set: BTreeSet, +} + +impl PathSet { + fn one>(path: P) -> PathSet { + let mut set = BTreeSet::new(); + set.insert(path.into()); + PathSet { set } + } + + fn has(&self, needle: &Path) -> bool { + self.set.iter().any(|p| p.ends_with(needle)) + } + + fn path(&self) -> &Path { + self.set.iter().next().unwrap() + } } impl StepDescription { @@ -116,30 +138,17 @@ impl StepDescription { only_build: S::ONLY_BUILD, should_run: S::should_run, make_run: S::make_run, + name: unsafe { ::std::intrinsics::type_name::() }, } } - fn maybe_run(&self, builder: &Builder, should_run: &ShouldRun, path: Option<&Path>) { - if let Some(path) = path { - if builder.config.exclude.iter().any(|e| e == path) { - eprintln!("Skipping {:?} because this path is excluded", path); - return; - } else if !builder.config.exclude.is_empty() { - eprintln!("{:?} not skipped -- not in {:?}", path, builder.config.exclude); - } - } else { - if !should_run.paths.is_empty() { - if should_run.paths.iter().all(|p| builder.config.exclude.contains(&p)) { - eprintln!("Skipping because all of its paths ({:?}) are excluded", - should_run.paths); - return; - } else if should_run.paths.len() > 1 { - for path in &should_run.paths { - self.maybe_run(builder, should_run, Some(path)); - } - return; - } - } + fn maybe_run(&self, builder: &Builder, pathset: &PathSet) { + if builder.config.exclude.iter().any(|e| pathset.has(e)) { + eprintln!("Skipping {:?} because it is excluded", pathset); + return; + } else if !builder.config.exclude.is_empty() { + eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset, + self.name, builder.config.exclude); } let build = builder.build; let hosts = if self.only_build_targets || self.only_build { @@ -165,7 +174,7 @@ impl StepDescription { for target in targets { let run = RunConfig { builder, - path, + path: pathset.path(), host: *host, target: *target, }; @@ -178,19 +187,28 @@ impl StepDescription { let should_runs = v.iter().map(|desc| { (desc.should_run)(ShouldRun::new(builder)) }).collect::>(); + + // sanity checks on rules + for (desc, should_run) in v.iter().zip(&should_runs) { + assert!(!should_run.paths.is_empty(), + "{:?} should have at least one pathset", desc.name); + } + if paths.is_empty() { for (desc, should_run) in v.iter().zip(should_runs) { if desc.default && should_run.is_really_default { - desc.maybe_run(builder, &should_run, None); + for pathset in &should_run.paths { + desc.maybe_run(builder, pathset); + } } } } else { for path in paths { let mut attempted_run = false; for (desc, should_run) in v.iter().zip(&should_runs) { - if should_run.run(path) { + if let Some(pathset) = should_run.pathset_for_path(path) { attempted_run = true; - desc.maybe_run(builder, &should_run, Some(path)); + desc.maybe_run(builder, pathset); } } @@ -206,7 +224,7 @@ impl StepDescription { pub struct ShouldRun<'a> { pub builder: &'a Builder<'a>, // use a BTreeSet to maintain sort order - paths: BTreeSet, + paths: BTreeSet, // If this is a default rule, this is an additional constraint placed on // it's run. Generally something like compiler docs being enabled. @@ -227,15 +245,35 @@ impl<'a> ShouldRun<'a> { self } + // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually + // ever be used, but as we transition to having all rules properly handle passing krate(...) by + // actually doing something different for every crate passed. + pub fn all_krates(mut self, name: &str) -> Self { + let mut set = BTreeSet::new(); + for krate in self.builder.in_tree_crates(name) { + set.insert(PathBuf::from(&krate.path)); + } + self.paths.insert(PathSet { set }); + self + } + pub fn krate(mut self, name: &str) -> Self { - for (_, krate_path) in self.builder.crates(name) { - self.paths.insert(t!(env::current_dir()).join(krate_path)); + for krate in self.builder.in_tree_crates(name) { + self.paths.insert(PathSet::one(&krate.path)); } self } - pub fn path(mut self, path: &str) -> Self { - self.paths.insert(t!(env::current_dir()).join(path)); + // single, non-aliased path + pub fn path(self, path: &str) -> Self { + self.paths(&[path]) + } + + // multiple aliases for the same job + pub fn paths(mut self, paths: &[&str]) -> Self { + self.paths.insert(PathSet { + set: paths.iter().map(PathBuf::from).collect(), + }); self } @@ -244,8 +282,8 @@ impl<'a> ShouldRun<'a> { self } - fn run(&self, path: &Path) -> bool { - self.paths.iter().any(|p| path.ends_with(p)) + fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> { + self.paths.iter().find(|pathset| pathset.has(path)) } } @@ -275,11 +313,16 @@ impl<'a> Builder<'a> { tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, native::Llvm, tool::Rustfmt, tool::Miri), Kind::Check => describe!(check::Std, check::Test, check::Rustc), - Kind::Test => describe!(test::Tidy, test::Bootstrap, test::DefaultCompiletest, - test::HostCompiletest, test::Crate, test::CrateLibrustc, test::Rustdoc, - test::Linkcheck, test::Cargotest, test::Cargo, test::Rls, test::Docs, - test::ErrorIndex, test::Distcheck, test::Rustfmt, test::Miri, test::Clippy, - test::RustdocJS, test::RustdocTheme), + Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, + test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, + test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo, + test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps, + test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty, + test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty, + test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake, + test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest, + test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck, + test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, @@ -317,8 +360,10 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); - for path in should_run.paths { - help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + for pathset in should_run.paths { + for path in pathset.set { + help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + } } Some(help) } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index ede403491d7f..767ee4016c6f 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -26,7 +26,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libstd").krate("std") + run.all_krates("std") } fn make_run(run: RunConfig) { @@ -67,7 +67,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc").krate("rustc-main") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { @@ -114,7 +114,7 @@ impl Step for Test { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libtest").krate("test") + run.all_krates("test") } fn make_run(run: RunConfig) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1d5e11c5d6d4..2dcc0e0e7cd9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,7 +48,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libstd").krate("std") + run.all_krates("std") } fn make_run(run: RunConfig) { @@ -320,7 +320,7 @@ impl Step for Test { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libtest").krate("test") + run.all_krates("test") } fn make_run(run: RunConfig) { @@ -436,7 +436,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc").krate("rustc-main") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { @@ -593,7 +593,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc_trans") + run.all_krates("rustc_trans") } fn make_run(run: RunConfig) { @@ -828,7 +828,7 @@ impl Step for Assemble { type Output = Compiler; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/rustc") + run.all_krates("rustc-main") } /// Prepare a new compiler from the artifacts in `stage` diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 6a75fc5112f5..55d9723527e6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -429,7 +429,7 @@ impl Step for Std { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("std").default_condition(builder.build.config.docs) + run.all_krates("std").default_condition(builder.build.config.docs) } fn make_run(run: RunConfig) { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 83c270865c0b..afd740ce5484 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -113,9 +113,8 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![deny(warnings)] -#![allow(stable_features)] -#![feature(associated_consts)] +//#![deny(warnings)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -267,6 +266,18 @@ struct Crate { bench_step: String, } +impl Crate { + fn is_local(&self, build: &Build) -> bool { + self.path.starts_with(&build.config.src) && + !self.path.to_string_lossy().ends_with("_shim") + } + + fn local_path(&self, build: &Build) -> PathBuf { + assert!(self.is_local(build)); + self.path.strip_prefix(&build.config.src).unwrap().into() + } +} + /// The various "modes" of invoking Cargo. /// /// These entries currently correspond to the various output directories of the @@ -949,22 +960,18 @@ impl Build { } } - /// Get a list of crates from a root crate. - /// - /// Returns Vec<(crate, path to crate, is_root_crate)> - fn crates(&self, root: &str) -> Vec<(Interned, &Path)> { - let interned = INTERNER.intern_string(root.to_owned()); + fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); - let mut list = vec![interned]; + let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - // If we can't strip prefix, then out-of-tree path - let path = krate.path.strip_prefix(&self.src).unwrap_or(&krate.path); - ret.push((krate.name, path)); - for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { - list.push(*dep); + if krate.is_local(self) { + ret.push(krate); + for dep in &krate.deps { + if visited.insert(dep) && dep != "build_helper" { + list.push(*dep); + } } } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 2ea026244034..3c91cf3ecc7b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -51,9 +51,7 @@ impl Step for Llvm { } fn make_run(run: RunConfig) { - let emscripten = run.path.map(|p| { - p.ends_with("llvm-emscripten") - }).unwrap_or(false); + let emscripten = run.path.ends_with("llvm-emscripten"); run.builder.ensure(Llvm { target: run.target, emscripten, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f6b95f0bf974..64ede4f4ecc8 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -13,7 +13,6 @@ //! This file implements the various regression test suites that we execute on //! our CI. -use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::iter; @@ -26,6 +25,7 @@ use std::io::Read; use build_helper::{self, output}; use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; +use Crate as CargoCrate; use cache::{INTERNER, Interned}; use compile; use dist; @@ -550,180 +550,213 @@ fn testdir(build: &Build, host: Interned) -> PathBuf { build.out.join(host).join("test") } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -struct Test { - path: &'static str, - mode: &'static str, - suite: &'static str, +macro_rules! default_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false }); + } } -static DEFAULT_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui", mode: "ui", suite: "ui" }, - Test { path: "src/test/run-pass", mode: "run-pass", suite: "run-pass" }, - Test { path: "src/test/compile-fail", mode: "compile-fail", suite: "compile-fail" }, - Test { path: "src/test/parse-fail", mode: "parse-fail", suite: "parse-fail" }, - Test { path: "src/test/run-fail", mode: "run-fail", suite: "run-fail" }, - Test { - path: "src/test/run-pass-valgrind", - mode: "run-pass-valgrind", - suite: "run-pass-valgrind" - }, - Test { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" }, - Test { path: "src/test/codegen", mode: "codegen", suite: "codegen" }, - Test { path: "src/test/codegen-units", mode: "codegen-units", suite: "codegen-units" }, - Test { path: "src/test/incremental", mode: "incremental", suite: "incremental" }, +macro_rules! host_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true }); + } +} +macro_rules! test { + ($name:ident { + path: $path:expr, + mode: $mode:expr, + suite: $suite:expr, + default: $default:expr, + host: $host:expr + }) => { + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub struct $name { + pub compiler: Compiler, + pub target: Interned, + } + + impl Step for $name { + type Output = (); + const DEFAULT: bool = $default; + const ONLY_HOSTS: bool = $host; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path($path) + } + + fn make_run(run: RunConfig) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + + run.builder.ensure($name { + compiler, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Compiletest { + compiler: self.compiler, + target: self.target, + mode: $mode, + suite: $suite, + }) + } + } + } +} + +default_test!(Ui { + path: "src/test/ui", + mode: "ui", + suite: "ui" +}); + +default_test!(RunPass { + path: "src/test/run-pass", + mode: "run-pass", + suite: "run-pass" +}); + +default_test!(CompileFail { + path: "src/test/compile-fail", + mode: "compile-fail", + suite: "compile-fail" +}); + +default_test!(ParseFail { + path: "src/test/parse-fail", + mode: "parse-fail", + suite: "parse-fail" +}); + +default_test!(RunFail { + path: "src/test/run-fail", + mode: "run-fail", + suite: "run-fail" +}); + +default_test!(RunPassValgrind { + path: "src/test/run-pass-valgrind", + mode: "run-pass-valgrind", + suite: "run-pass-valgrind" +}); + +default_test!(MirOpt { + path: "src/test/mir-opt", + mode: "mir-opt", + suite: "mir-opt" +}); + +default_test!(Codegen { + path: "src/test/codegen", + mode: "codegen", + suite: "codegen" +}); + +default_test!(CodegenUnits { + path: "src/test/codegen-units", + mode: "codegen-units", + suite: "codegen-units" +}); + +default_test!(Incremental { + path: "src/test/incremental", + mode: "incremental", + suite: "incremental" +}); + +default_test!(Debuginfo { + path: "src/test/debuginfo", // What this runs varies depending on the native platform being apple - Test { path: "src/test/debuginfo", mode: "debuginfo-XXX", suite: "debuginfo" }, -]; + mode: "debuginfo-XXX", + suite: "debuginfo" +}); -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct DefaultCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} +host_test!(UiFullDeps { + path: "src/test/ui-fulldeps", + mode: "ui", + suite: "ui-fulldeps" +}); -impl Step for DefaultCompiletest { - type Output = (); - const DEFAULT: bool = true; +host_test!(RunPassFullDeps { + path: "src/test/run-pass-fulldeps", + mode: "run-pass", + suite: "run-pass-fulldeps" +}); - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in DEFAULT_COMPILETESTS { - run = run.path(test.path); - } - run - } +host_test!(RunFailFullDeps { + path: "src/test/run-fail-fulldeps", + mode: "run-fail", + suite: "run-fail-fulldeps" +}); - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); +host_test!(CompileFailFullDeps { + path: "src/test/compile-fail-fulldeps", + mode: "compile-fail", + suite: "compile-fail-fulldeps" +}); - let test = run.path.map(|path| { - DEFAULT_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); +host_test!(IncrementalFullDeps { + path: "src/test/incremental-fulldeps", + mode: "incremental", + suite: "incremental-fulldeps" +}); - if let Some(test) = test { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in DEFAULT_COMPILETESTS { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } +host_test!(Rustdoc { + path: "src/test/rustdoc", + mode: "rustdoc", + suite: "rustdoc" +}); - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} +test!(Pretty { + path: "src/test/pretty", + mode: "pretty", + suite: "pretty", + default: false, + host: true +}); +test!(RunPassPretty { + path: "src/test/run-pass/pretty", + mode: "pretty", + suite: "run-pass", + default: false, + host: true +}); +test!(RunFailPretty { + path: "src/test/run-fail/pretty", + mode: "pretty", + suite: "run-fail", + default: false, + host: true +}); +test!(RunPassValgrindPretty { + path: "src/test/run-pass-valgrind/pretty", + mode: "pretty", + suite: "run-pass-valgrind", + default: false, + host: true +}); +test!(RunPassFullDepsPretty { + path: "src/test/run-pass-fulldeps/pretty", + mode: "pretty", + suite: "run-pass-fulldeps", + default: false, + host: true +}); +test!(RunFailFullDepsPretty { + path: "src/test/run-fail-fulldeps/pretty", + mode: "pretty", + suite: "run-fail-fulldeps", + default: false, + host: true +}); -// Also default, but host-only. -static HOST_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" }, - Test { path: "src/test/run-pass-fulldeps", mode: "run-pass", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps", mode: "run-fail", suite: "run-fail-fulldeps" }, - Test { - path: "src/test/compile-fail-fulldeps", - mode: "compile-fail", - suite: "compile-fail-fulldeps", - }, - Test { - path: "src/test/incremental-fulldeps", - mode: "incremental", - suite: "incremental-fulldeps", - }, - Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }, - - Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" }, - Test { path: "src/test/run-pass/pretty", mode: "pretty", suite: "run-pass" }, - Test { path: "src/test/run-fail/pretty", mode: "pretty", suite: "run-fail" }, - Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" }, - Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" }, - Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" }, -]; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct HostCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} - -impl Step for HostCompiletest { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in HOST_COMPILETESTS { - run = run.path(test.path); - } - run - } - - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - - let test = run.path.map(|path| { - HOST_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); - - if let Some(test) = test { - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in HOST_COMPILETESTS { - if test.mode == "pretty" { - continue; - } - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } - - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} +host_test!(RunMake { + path: "src/test/run-make", + mode: "run-make", + suite: "run-make" +}); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct Compiletest { @@ -902,7 +935,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally don't work without LLVM"); + println!("Ignoring run-make test suite as they generally dont work without LLVM"); return; } @@ -1099,7 +1132,7 @@ pub struct CrateLibrustc { compiler: Compiler, target: Interned, test_kind: TestKind, - krate: Option>, + krate: Interned, } impl Step for CrateLibrustc { @@ -1115,35 +1148,26 @@ impl Step for CrateLibrustc { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let make = |name: Option>| { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + for krate in builder.in_tree_crates("rustc-main") { + if run.path.ends_with(&krate.path) { + let test_kind = if builder.kind == Kind::Test { + TestKind::Test + } else if builder.kind == Kind::Bench { + TestKind::Bench + } else { + panic!("unexpected builder.kind in crate: {:?}", builder.kind); + }; - builder.ensure(CrateLibrustc { - compiler, - target: run.target, - test_kind, - krate: name, - }); - }; - - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("rustc-main") { - if path.ends_with(krate_path) { - make(Some(name)); - } + builder.ensure(CrateLibrustc { + compiler, + target: run.target, + test_kind, + krate: krate.name, + }); } - } else { - make(None); } } - fn run(self, builder: &Builder) { builder.ensure(Crate { compiler: self.compiler, @@ -1156,27 +1180,95 @@ impl Step for CrateLibrustc { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Crate { +pub struct CrateNotDefault { compiler: Compiler, target: Interned, - mode: Mode, test_kind: TestKind, - krate: Option>, + krate: &'static str, } -impl Step for Crate { +impl Step for CrateNotDefault { type Output = (); - const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.krate("std").krate("test") + run.path("src/liballoc_jemalloc") + .path("src/librustc_asan") + .path("src/librustc_lsan") + .path("src/librustc_msan") + .path("src/librustc_tsan") } fn make_run(run: RunConfig) { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let make = |mode: Mode, name: Option>| { + let test_kind = if builder.kind == Kind::Test { + TestKind::Test + } else if builder.kind == Kind::Bench { + TestKind::Bench + } else { + panic!("unexpected builder.kind in crate: {:?}", builder.kind); + }; + + builder.ensure(CrateNotDefault { + compiler, + target: run.target, + test_kind, + krate: match run.path { + _ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc", + _ if run.path.ends_with("src/librustc_asan") => "rustc_asan", + _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan", + _ if run.path.ends_with("src/librustc_msan") => "rustc_msan", + _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan", + _ => panic!("unexpected path {:?}", run.path), + }, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Crate { + compiler: self.compiler, + target: self.target, + mode: Mode::Libstd, + test_kind: self.test_kind, + krate: INTERNER.intern_str(self.krate), + }); + } +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Crate { + compiler: Compiler, + target: Interned, + mode: Mode, + test_kind: TestKind, + krate: Interned, +} + +impl Step for Crate { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(mut run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run = run.krate("test"); + for krate in run.builder.in_tree_crates("std") { + if krate.is_local(&run.builder) && + !krate.name.contains("jemalloc") && + !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) && + krate.name != "dlmalloc" { + run = run.path(krate.local_path(&builder).to_str().unwrap()); + } + } + run + } + + fn make_run(run: RunConfig) { + let builder = run.builder; + let compiler = builder.compiler(builder.top_stage, run.host); + + let make = |mode: Mode, krate: &CargoCrate| { let test_kind = if builder.kind == Kind::Test { TestKind::Test } else if builder.kind == Kind::Bench { @@ -1190,29 +1282,24 @@ impl Step for Crate { target: run.target, mode, test_kind, - krate: name, + krate: krate.name, }); }; - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("std") { - if path.ends_with(krate_path) { - make(Mode::Libstd, Some(name)); - } + for krate in builder.in_tree_crates("std") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libstd, krate); } - for (name, krate_path) in builder.crates("test") { - if path.ends_with(krate_path) { - make(Mode::Libtest, Some(name)); - } + } + for krate in builder.in_tree_crates("test") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libtest, krate); } - } else { - make(Mode::Libstd, None); - make(Mode::Libtest, None); } } - /// Run all unit tests plus documentation tests for an entire crate DAG defined - /// by a `Cargo.toml` + /// Run all unit tests plus documentation tests for a given crate defined + /// by a `Cargo.toml` (single manifest) /// /// This is what runs tests for crates like the standard library, compiler, etc. /// It essentially is the driver for running `cargo test`. @@ -1241,27 +1328,23 @@ impl Step for Crate { }; let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); - let (name, root) = match mode { + match mode { Mode::Libstd => { compile::std_cargo(build, &compiler, target, &mut cargo); - ("libstd", "std") } Mode::Libtest => { compile::test_cargo(build, &compiler, target, &mut cargo); - ("libtest", "test") } Mode::Librustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(build, &mut cargo); - ("librustc", "rustc-main") } _ => panic!("can only test libraries"), }; - let root = INTERNER.intern_string(String::from(root)); let _folder = build.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name) + format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) }); - println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage, + println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, &compiler.host, target); // Build up the base `cargo test` command. @@ -1273,37 +1356,7 @@ impl Step for Crate { cargo.arg("--no-fail-fast"); } - match krate { - Some(krate) => { - cargo.arg("-p").arg(krate); - } - None => { - let mut visited = HashSet::new(); - let mut next = vec![root]; - while let Some(name) = next.pop() { - // Right now jemalloc and the sanitizer crates are - // target-specific crate in the sense that it's not present - // on all platforms. Custom skip it here for now, but if we - // add more this probably wants to get more generalized. - // - // Also skip `build_helper` as it's not compiled normally - // for target during the bootstrap and it's just meant to be - // a helper crate, not tested. If it leaks through then it - // ends up messing with various mtime calculations and such. - if !name.contains("jemalloc") && - *name != *"build_helper" && - !(name.starts_with("rustc_") && name.ends_with("san")) && - name != "dlmalloc" { - cargo.arg("-p").arg(&format!("{}:0.0.0", name)); - } - for dep in build.crates[&name].deps.iter() { - if visited.insert(dep) { - next.push(*dep); - } - } - } - } - } + cargo.arg("-p").arg(krate); // The tests are going to run with the *target* libraries, so we need to // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent. @@ -1355,18 +1408,18 @@ impl Step for Crate { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rustdoc { +pub struct CrateRustdoc { host: Interned, test_kind: TestKind, } -impl Step for Rustdoc { +impl Step for CrateRustdoc { type Output = (); const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustdoc").path("src/tools/rustdoc") + run.paths(&["src/librustdoc", "src/tools/rustdoc"]) } fn make_run(run: RunConfig) { @@ -1380,7 +1433,7 @@ impl Step for Rustdoc { panic!("unexpected builder.kind in crate: {:?}", builder.kind); }; - builder.ensure(Rustdoc { + builder.ensure(CrateRustdoc { host: run.host, test_kind, }); From bd426f1d69ec8371d86e06382e96e9ed842f3933 Mon Sep 17 00:00:00 2001 From: Jason Schein Date: Sun, 11 Feb 2018 17:54:44 -0800 Subject: [PATCH 44/87] Update ops range example to avoid confusion between indexes and values. --- src/libcore/ops/range.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb6..a80699c0f5af 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// let arr = ['a', 'b', 'c', 'd']; +/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); +/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); +/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); +/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] From f7cabc6550f23d8a761abf737763a0375a0ac41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 11 Feb 2018 22:10:35 -0800 Subject: [PATCH 45/87] Continue parsing function after finding `...` arg When encountering a variadic argument in a function definition that doesn't accept it, if immediately after there's a closing paren, continue parsing as normal. Otherwise keep current behavior of emitting error and stopping. --- src/libsyntax/parse/parser.rs | 21 +++++++++++++++----- src/test/ui/invalid-variadic-function.rs | 13 ++++++++++++ src/test/ui/invalid-variadic-function.stderr | 14 +++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/invalid-variadic-function.rs create mode 100644 src/test/ui/invalid-variadic-function.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc3745fc4a3e..ac582627f88f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4859,19 +4859,30 @@ impl<'a> Parser<'a> { |p| { if p.token == token::DotDotDot { p.bump(); + variadic = true; if allow_variadic { if p.token != token::CloseDelim(token::Paren) { let span = p.span; p.span_err(span, "`...` must be last in argument list for variadic function"); } + Ok(None) } else { - let span = p.span; - p.span_err(span, - "only foreign functions are allowed to be variadic"); + let span = p.prev_span; + if p.token == token::CloseDelim(token::Paren) { + // continue parsing to present any further errors + p.struct_span_err( + span, + "only foreign functions are allowed to be variadic" + ).emit(); + Ok(Some(dummy_arg(span))) + } else { + // this function definition looks beyond recovery, stop parsing + p.span_err(span, + "only foreign functions are allowed to be variadic"); + Ok(None) + } } - variadic = true; - Ok(None) } else { match p.parse_arg_general(named_args) { Ok(arg) => Ok(Some(arg)), diff --git a/src/test/ui/invalid-variadic-function.rs b/src/test/ui/invalid-variadic-function.rs new file mode 100644 index 000000000000..3d421e00b08e --- /dev/null +++ b/src/test/ui/invalid-variadic-function.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "C" fn foo(x: u8, ...); +//~^ ERROR only foreign functions are allowed to be variadic +//~| ERROR expected one of `->`, `where`, or `{`, found `;` diff --git a/src/test/ui/invalid-variadic-function.stderr b/src/test/ui/invalid-variadic-function.stderr new file mode 100644 index 000000000000..15a908b3f00f --- /dev/null +++ b/src/test/ui/invalid-variadic-function.stderr @@ -0,0 +1,14 @@ +error: only foreign functions are allowed to be variadic + --> $DIR/invalid-variadic-function.rs:11:26 + | +11 | extern "C" fn foo(x: u8, ...); + | ^^^ + +error: expected one of `->`, `where`, or `{`, found `;` + --> $DIR/invalid-variadic-function.rs:11:30 + | +11 | extern "C" fn foo(x: u8, ...); + | ^ expected one of `->`, `where`, or `{` here + +error: aborting due to 2 previous errors + From 0f789aad2b3cfc0b0925b726295200267130e69d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:05:46 +0100 Subject: [PATCH 46/87] add core::iter::repeat_with --- src/libcore/iter/sources.rs | 104 ++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 44 +++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b05a893e6610..980f3fc7443a 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -57,6 +57,12 @@ unsafe impl TrustedLen for Repeat {} /// /// [`take`]: trait.Iterator.html#method.take /// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with`] function. +/// +/// [`repeat_with`]: fn.repeat_with.html +/// /// # Examples /// /// Basic usage: @@ -99,6 +105,104 @@ pub fn repeat(elt: T) -> Repeat { Repeat{element: elt} } +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with`] function. +/// See its documentation for more. +/// +/// [`repeat_with`]: fn.repeat_with.html +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub struct RepeatWith { + repeater: F +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { Some((self.repeater)()) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> DoubleEndedIterator for RepeatWith { + #[inline] + fn next_back(&mut self) -> Option { self.next() } +} + +#[unstable(feature = "fused", issue = "35602")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} + +/// Creates a new that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over and over and +/// over and over and 🔁. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`take`], in order to make them finite. +/// +/// [`take`]: trait.Iterator.html#method.take +/// +/// If the element type of the iterator you need implements `Clone`, and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat`] function. +/// +/// [`repeat`]: fn.repeat.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + /// An iterator that yields nothing. /// /// This `struct` is created by the [`empty`] function. See its documentation for more. diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67..ca5318d198e7 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1549,6 +1549,50 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +fn test_repeat_with() { + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_rev() { + let mut curr = 1; + let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .rev().take(4); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), + (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .take(5).collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + #[test] fn test_fuse() { let mut it = 0..3; From c4099ca4b11acb9949ef0da804a819b4ddfa24a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:25:39 +0100 Subject: [PATCH 47/87] core::iter::repeat_with: general fixes --- src/libcore/iter/mod.rs | 2 ++ src/libcore/iter/sources.rs | 4 ++++ src/libcore/lib.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 29b62c901f31..ac3fb5a57dd3 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,6 +333,8 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; #[stable(feature = "iter_once", since = "1.2.0")] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 980f3fc7443a..2cf90fd079e2 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -162,6 +162,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -182,6 +184,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // From the zeroth to the third power of two: diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 59a296c2a762..447e144bf0fd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(unwind_attributes)] #![feature(doc_spotlight)] #![feature(rustc_const_unstable)] +#![feature(iterator_repeat_with)] #[prelude_import] #[allow(unused)] From 1af9ee1350cc69e7c1873d26637064824d07c2b8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:35:12 +0100 Subject: [PATCH 48/87] core::iter::repeat_with: derive Copy, Clone, Debug --- src/libcore/iter/sources.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2cf90fd079e2..d77e8d4db04a 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -112,6 +112,7 @@ pub fn repeat(elt: T) -> Repeat { /// See its documentation for more. /// /// [`repeat_with`]: fn.repeat_with.html +#[derive(Copy, Clone, Debug)] #[unstable(feature = "iterator_repeat_with", issue = "0")] pub struct RepeatWith { repeater: F From f025eff21d1832fcd3941ae847fec2aaf23d3b0b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:13:47 +0100 Subject: [PATCH 49/87] core::iter::repeat_with: fix tests --- src/libcore/tests/iter.rs | 3 ++- src/libcore/tests/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ca5318d198e7..f42970685f57 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1551,6 +1551,7 @@ fn test_repeat_take_collect() { #[test] fn test_repeat_with() { + #[derive(PartialEq, Debug)] struct NotClone(usize); let mut it = repeat_with(|| NotClone(42)); assert_eq!(it.next(), Some(NotClone(42))); @@ -1586,7 +1587,7 @@ fn test_repeat_with_take() { } #[test] -fn test_repeat_take_collect() { +fn test_repeat_with_take_collect() { let mut curr = 1; let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .take(5).collect(); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9e90313bc0e9..2b9fae88bf49 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] From 55c669c4d9f7b245e2c237dc2b5d0390afe2620d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:15:13 +0100 Subject: [PATCH 50/87] core::iter::repeat_with: fix tests some more --- src/libcore/tests/iter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f42970685f57..4c33c8440a3d 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1565,11 +1565,11 @@ fn test_repeat_with_rev() { let mut curr = 1; let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .rev().take(4); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.next(), None); + assert_eq!(pow2.next(), Some(1)); + assert_eq!(pow2.next(), Some(2)); + assert_eq!(pow2.next(), Some(4)); + assert_eq!(pow2.next(), Some(8)); + assert_eq!(pow2.next(), None); } #[test] From efa332038c74931738c44f48622c2a99b5a36cf0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:18:22 +0100 Subject: [PATCH 51/87] core::iter::repeat_with: fix doc tests --- src/libcore/iter/sources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index d77e8d4db04a..b364292f57e9 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -163,7 +163,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// @@ -185,7 +185,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// From 29f71488bc50843b65660867ab41e6ebf1101e6e Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:00:08 +0000 Subject: [PATCH 52/87] 38880 remove redundant extra function --- src/libstd/collections/hash/map.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 04c9f617d019..d798854927d3 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,17 +397,6 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } -/// Search for a pre-hashed key when the hash map is known to be non-empty. -#[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) - -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - search_hashed_body(table, hash, is_match) -} - /// Search for a pre-hashed key. /// If you don't already know the hash, use search or search_mut instead #[inline] @@ -422,16 +411,19 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE return InternalEntry::TableIsEmpty; } - search_hashed_body(table, hash, is_match) + search_hashed_nonempty(table, hash, is_match) } -/// The body of the search_hashed[_nonempty] functions + +/// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { + // Do not check the capacity as an extra branch could slow the lookup. + let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; From fd78621717e4f9f73b41256627bfe3a83aa5e660 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:53:09 +0000 Subject: [PATCH 53/87] 38880 fixup add missing mut --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d798854927d3..c4f3fdc283ef 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -417,7 +417,7 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool From 0f16eee013aa64108a1b1ca8fa9f9cf263635071 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 21:21:02 -0800 Subject: [PATCH 54/87] rustc: Add the ability to not run dsymutil This commit adds the ability for rustc to not run `dsymutil` by default on OSX. A new codegen option, `-Z run-dsymutil=no`, was added to specify that `dsymutil` should *not* run and instead the compiler should unconditionally keep the object files around in a compilation if necessary for debug information. cc #47240 --- src/librustc/session/config.rs | 2 ++ src/librustc_trans/back/link.rs | 58 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da0..1f40c2db4539 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1320,6 +1320,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "The epoch to build Rust with. Newer epochs may include features that require breaking changes. The default epoch is 2015 (the first epoch). Crates compiled with different epochs can be linked together."), + run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], + "run `dsymutil` and delete intermediate object files"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index f050edcd513b..4fe294a790fc 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -166,7 +166,9 @@ pub(crate) fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() { + if sess.opts.output_types.should_trans() && + !preserve_objects_for_their_debuginfo(sess) + { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { remove(sess, obj); } @@ -190,6 +192,52 @@ pub(crate) fn link_binary(sess: &Session, out_filenames } +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == NoDebugInfo { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { let out_filename = outputs.single_output_file.clone() .unwrap_or(outputs @@ -736,8 +784,12 @@ fn link_natively(sess: &Session, // On macOS, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != NoDebugInfo && + !preserve_objects_for_their_debuginfo(sess) + { match Command::new("dsymutil").arg(out_filename).output() { Ok(..) => {} Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), From 9cee79a7ff09851109f621bd4510909f5740ae28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 18:03:56 +0100 Subject: [PATCH 55/87] core::iter::repeat_with: document DoubleEndedIterator behavior --- src/libcore/iter/sources.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b364292f57e9..abf2befa9cd1 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -158,6 +158,12 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`repeat`]: fn.repeat.html /// +/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. +/// It is important to not that reversing `repeat_with(f)` will produce +/// the exact same sequence as the non-reversed iterator. In other words, +/// `repeat_with(f).rev().collect::>()` is equivalent to +/// `repeat_with(f).collect::>()`. +/// /// # Examples /// /// Basic usage: From 43e8ac27d9bf645b66a15f762be6969e9fe16285 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 08:38:46 -0800 Subject: [PATCH 56/87] rustc: Persist LLVM's `Linker` in Fat LTO This commit updates our Fat LTO logic to tweak our custom wrapper around LLVM's "link modules" functionality. Previously whenever the `LLVMRustLinkInExternalBitcode` function was called it would call LLVM's `Linker::linkModules` wrapper. Internally this would crate an instance of a `Linker` which internally creates an instance of an `IRMover`. Unfortunately for us the creation of `IRMover` is somewhat O(n) with the input module. This means that every time we linked a module it was O(n) with respect to the entire module we had built up! Now the modules we build up during LTO are quite large, so this quickly started creating an O(n^2) problem for us! Discovered in #48025 it turns out this has always been a problem and we just haven't noticed it. It became particularly worse recently though due to most libraries having 16x more object files than they previously did (1 -> 16). This commit fixes this performance issue by preserving the `Linker` instance across all links into the main LLVM module. This means we only create one `IRMover` and allows LTO to progress much speedier. From the `cargo-cache` project in #48025 a **full build** locally when from 5m15s to 2m24s. Looking at the timing logs each object file was linked in in single-digit millisecond rather than hundreds, clearly being a nice improvement! Closes #48025 --- src/librustc_llvm/build.rs | 1 + src/librustc_llvm/ffi.rs | 10 ++++- src/librustc_trans/back/lto.rs | 40 +++++++++++++++---- src/rustllvm/Linker.cpp | 72 ++++++++++++++++++++++++++++++++++ src/rustllvm/RustWrapper.cpp | 40 ------------------- 5 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 src/rustllvm/Linker.cpp diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 49b93f3c7d6a..54e3f544acb6 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -155,6 +155,7 @@ fn main() { cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") + .file("../rustllvm/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("rustllvm"); diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 99e43a2ddf98..e71bef512cf0 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Linker_opaque {} +pub type LinkerRef = *mut Linker_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); @@ -1608,7 +1611,6 @@ extern "C" { pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool; pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t); pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); @@ -1724,4 +1726,10 @@ extern "C" { CU2: *mut *mut c_void); pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void); pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef); + + pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef; + pub fn LLVMRustLinkerAdd(linker: LinkerRef, + bytecode: *const c_char, + bytecode_len: usize) -> bool; + pub fn LLVMRustLinkerFree(linker: LinkerRef); } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 9ff5bcf7a33c..a33270380196 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext, // know much about the memory management here so we err on the side of being // save and persist everything with the original module. let mut serialized_bitcode = Vec::new(); + let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { info!("linking {:?}", name); - time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe { + time(cgcx.time_passes, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); - if llvm::LLVMRustLinkInExternalBitcode(llmod, - data.as_ptr() as *const libc::c_char, - data.len() as libc::size_t) { - Ok(()) - } else { + linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - Err(write::llvm_err(&diag_handler, msg)) - } + write::llvm_err(&diag_handler, msg) + }) })?; timeline.record(&format!("link {:?}", name)); serialized_bitcode.push(bc_decoded); } + drop(linker); cgcx.save_temp_bitcode(&module, "lto.input"); // Internalize everything that *isn't* in our whitelist to help strip out @@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext, }]) } +struct Linker(llvm::LinkerRef); + +impl Linker { + fn new(llmod: ModuleRef) -> Linker { + unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } + } + + fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + unsafe { + if llvm::LLVMRustLinkerAdd(self.0, + bytecode.as_ptr() as *const libc::c_char, + bytecode.len()) { + Ok(()) + } else { + Err(()) + } + } + } +} + +impl Drop for Linker { + fn drop(&mut self) { + unsafe { llvm::LLVMRustLinkerFree(self.0); } + } +} + /// Prepare "thin" LTO to get run on these modules. /// /// The general structure of ThinLTO is quite different from the structure of diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp new file mode 100644 index 000000000000..534e4b910902 --- /dev/null +++ b/src/rustllvm/Linker.cpp @@ -0,0 +1,72 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#include "llvm/Linker/Linker.h" + +#include "rustllvm.h" + +using namespace llvm; + +struct RustLinker { + Linker L; + LLVMContext &Ctx; + + RustLinker(Module &M) : + L(M), + Ctx(M.getContext()) + {} +}; + +extern "C" RustLinker* +LLVMRustLinkerNew(LLVMModuleRef DstRef) { + Module *Dst = unwrap(DstRef); + + auto Ret = llvm::make_unique(*Dst); + return Ret.release(); +} + +extern "C" void +LLVMRustLinkerFree(RustLinker *L) { + delete L; +} + +extern "C" bool +LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { + std::unique_ptr Buf = + MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); + +#if LLVM_VERSION_GE(4, 0) + Expected> SrcOrError = + llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx); + if (!SrcOrError) { + LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); + return false; + } + + auto Src = std::move(*SrcOrError); +#else + ErrorOr> Src = + llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx); + if (!Src) { + LLVMRustSetLastError(Src.getError().message().c_str()); + return false; + } +#endif + +#if LLVM_VERSION_GE(4, 0) + if (L->L.linkInModule(std::move(Src))) { +#else + if (L->L.linkInModule(std::move(Src.get()))) { +#endif + LLVMRustSetLastError(""); + return false; + } + return true; +} diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4dfc4029d75d..27d5496f5762 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC, - size_t Len) { - Module *Dst = unwrap(DstRef); - - std::unique_ptr Buf = - MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); - -#if LLVM_VERSION_GE(4, 0) - Expected> SrcOrError = - llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext()); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return false; - } - - auto Src = std::move(*SrcOrError); -#else - ErrorOr> Src = - llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext()); - if (!Src) { - LLVMRustSetLastError(Src.getError().message().c_str()); - return false; - } -#endif - - std::string Err; - - raw_string_ostream Stream(Err); - DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_GE(4, 0) - if (Linker::linkModules(*Dst, std::move(Src))) { -#else - if (Linker::linkModules(*Dst, std::move(Src.get()))) { -#endif - LLVMRustSetLastError(Err.c_str()); - return false; - } - return true; -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The From 4c658f76c1b51ced4f6c30ea37441c4141659b93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 10:46:31 -0800 Subject: [PATCH 57/87] Update compiletest's `read2` function This was originally copied over from Cargo and Cargo has since [been updated][update] so let's pull in the fixes here too! [update]: https://github.com/rust-lang/cargo/pull/5030 --- src/tools/compiletest/src/read2.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 1d8816c7db13..486c0d81e3f4 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -58,9 +58,12 @@ mod imp { fds[0].events = libc::POLLIN; fds[1].fd = err_pipe.as_raw_fd(); fds[1].events = libc::POLLIN; - loop { + let mut nfds = 2; + let mut errfd = 1; + + while nfds > 0 { // wait for either pipe to become readable using `select` - let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) }; + let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; if r == -1 { let err = io::Error::last_os_error(); if err.kind() == io::ErrorKind::Interrupted { @@ -86,19 +89,20 @@ mod imp { } } }; - if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { - out_done = true; - } - data(true, &mut out, out_done); - if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { + if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { err_done = true; + nfds -= 1; } data(false, &mut err, err_done); - - if out_done && err_done { - return Ok(()) + if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { + out_done = true; + fds[0].fd = err_pipe.as_raw_fd(); + errfd = 0; + nfds -= 1; } + data(true, &mut out, out_done); } + Ok(()) } } From f237e9e2e74dfd5b223589f6254c80e8a69b724e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Mon, 12 Feb 2018 12:28:32 -0700 Subject: [PATCH 58/87] Remove allocation from width of character function. --- src/libsyntax/codemap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3601b9ba8a8c..ff6f32fc3be0 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -690,14 +690,16 @@ impl CodeMap { return 1; } + let src = local_begin.fm.external_src.borrow(); + // We need to extend the snippet to the end of the src rather than to end_index so when // searching forwards for boundaries we've got somewhere to search. let snippet = if let Some(ref src) = local_begin.fm.src { let len = src.len(); - (&src[start_index..len]).to_string() - } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() { + (&src[start_index..len]) + } else if let Some(src) = src.get_source() { let len = src.len(); - (&src[start_index..len]).to_string() + (&src[start_index..len]) } else { return 1; }; From 91a4b9044d7f104516984d1076b04b99cef7a6b9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 21:47:59 +0100 Subject: [PATCH 59/87] core::iter::repeat_with: tracking issue is #48169 --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ac3fb5a57dd3..d929d1d65a91 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,7 +333,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index abf2befa9cd1..eb8a22709b06 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,7 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> DoubleEndedIterator for RepeatWith { #[inline] fn next_back(&mut self) -> Option { self.next() } @@ -209,7 +209,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } From db13296b6fd6b68ab06055bdcb9a22078b11de6a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Feb 2018 06:20:17 +0100 Subject: [PATCH 60/87] core::iter::repeat_with: fix missing word, see @Pazzaz's review --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index eb8a22709b06..3e9d799c0894 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -141,7 +141,7 @@ impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl A> TrustedLen for RepeatWith {} -/// Creates a new that repeats elements of type `A` endlessly by +/// Creates a new iterator that repeats elements of type `A` endlessly by /// applying the provided closure, the repeater, `F: FnMut() -> A`. /// /// The `repeat_with()` function calls the repeater over and over and over and From 0397fc1b3ad598819b3eedcd7773ef32b2a685b7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Feb 2018 17:21:01 +0100 Subject: [PATCH 61/87] Handle path prefix mapping in a more stable way when computing the crate hash. --- src/librustc/hir/map/collector.rs | 20 ++++++++++++++++++-- src/librustc/hir/map/mod.rs | 1 + src/librustc/session/config.rs | 6 +++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 0e1c66277163..99b1e5783e01 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -9,14 +9,15 @@ // except according to those terms. use super::*; - use dep_graph::{DepGraph, DepKind, DepNodeIndex}; +use hir::def_id::{LOCAL_CRATE, CrateNum}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::svh::Svh; use middle::cstore::CrateStore; use session::CrateDisambiguator; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID}; +use syntax::codemap::CodeMap; use syntax_pos::Span; use ich::StableHashingContext; @@ -123,6 +124,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn finalize_and_compute_crate_hash(self, crate_disambiguator: CrateDisambiguator, cstore: &CrateStore, + codemap: &CodeMap, commandline_args_hash: u64) -> (Vec>, Svh) { let mut node_hashes: Vec<_> = self @@ -147,11 +149,25 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { (name1, dis1).cmp(&(name2, dis2)) }); + // We hash the final, remapped names of all local source files so we + // don't have to include the path prefix remapping commandline args. + // If we included the full mapping in the SVH, we could only have + // reproducible builds by compiling from the same directory. So we just + // hash the result of the mapping instead of the mapping itself. + let mut source_file_names: Vec<_> = codemap + .files() + .iter() + .filter(|filemap| CrateNum::from_u32(filemap.crate_of_origin) == LOCAL_CRATE) + .map(|filemap| filemap.name_hash) + .collect(); + + source_file_names.sort_unstable(); + let (_, crate_dep_node_index) = self .dep_graph .with_task(DepNode::new_no_params(DepKind::Krate), &self.hcx, - ((node_hashes, upstream_crates), + (((node_hashes, upstream_crates), source_file_names), (commandline_args_hash, crate_disambiguator.to_fingerprint())), identity_fn); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5feea602d281..b6b3e8955351 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1065,6 +1065,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, let cmdline_args = sess.opts.dep_tracking_hash(); collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, + sess.codemap(), cmdline_args) }; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da0..82ee7e31dae0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1269,9 +1269,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the optimization fuel quota for a crate"), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make Rustc print the total optimization fuel used by a crate"), - remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a source pattern to the file path remapping config"), - remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a mapping target to the file path remapping config"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable"), @@ -1717,7 +1717,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len(); - let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len(); + let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len(); if remap_path_prefix_targets < remap_path_prefix_sources { for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] { From 580dd42cfaefcb3189eab786224403ffe45bd37f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 13:37:32 +0100 Subject: [PATCH 62/87] incr.comp.: Run cache directory garbage collection before loading dep-graph. --- src/librustc_driver/driver.rs | 9 +++++++++ src/librustc_incremental/lib.rs | 1 + src/librustc_incremental/persist/fs.rs | 16 +++++++++++++++- src/librustc_incremental/persist/mod.rs | 3 ++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f344624666a6..b8a1fe991054 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -660,6 +660,15 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, disambiguator, ); + if sess.opts.incremental.is_some() { + time(time_passes, "garbage collect incremental cache directory", || { + if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { + warn!("Error while trying to garbage collect incremental \ + compilation cache directory: {}", e); + } + }); + } + // If necessary, compute the dependency graph (in the background). let future_dep_graph = if sess.opts.build_dep_graph() { Some(rustc_incremental::load_dep_graph(sess, time_passes)) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index b53ee1daada4..65fbd9d0bf8f 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -46,3 +46,4 @@ pub use persist::in_incr_comp_dir; pub use persist::prepare_session_directory; pub use persist::finalize_session_directory; pub use persist::delete_workproduct_files; +pub use persist::garbage_collect_session_directories; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index f4171f951f40..795825f180c9 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -603,7 +603,7 @@ fn timestamp_to_string(timestamp: SystemTime) -> String { } fn string_to_timestamp(s: &str) -> Result { - let micros_since_unix_epoch = u64::from_str_radix(s, 36); + let micros_since_unix_epoch = u64::from_str_radix(s, INT_ENCODE_BASE as u32); if micros_since_unix_epoch.is_err() { return Err(()) @@ -733,6 +733,20 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { }) .collect(); + // Delete all session directories that don't have a lock file. + for directory_name in session_directories { + if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) { + let path = crate_directory.join(directory_name); + if let Err(err) = safe_remove_dir_all(&path) { + sess.warn(&format!("Failed to garbage collect invalid incremental \ + compilation session directory `{}`: {}", + path.display(), + err)); + } + } + } + + // Now garbage collect the valid session directories. let mut deletion_candidates = vec![]; let mut definitely_delete = vec![]; diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 82a43d85bc60..2f864aaefba8 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -20,9 +20,10 @@ mod save; mod work_product; mod file_format; -pub use self::fs::prepare_session_directory; pub use self::fs::finalize_session_directory; +pub use self::fs::garbage_collect_session_directories; pub use self::fs::in_incr_comp_dir; +pub use self::fs::prepare_session_directory; pub use self::load::dep_graph_tcx_init; pub use self::load::load_dep_graph; pub use self::load::load_query_result_cache; From 7984c895b6995703254035e81d0a85ae1fa9fe2b Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 11 Feb 2018 05:05:11 +0800 Subject: [PATCH 63/87] Improve debuggability of #48116. 1. When the invalid condition is hit, write out the relevant variables too 2. In compile-fail/parse-fail tests, check for ICE first, so the invalid error patterns won't mask our ICE output. --- src/librustc_resolve/resolve_imports.rs | 15 +++++++++++++-- src/tools/compiletest/src/runtest.rs | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8cb25f449b66..a8070c553bdb 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -1026,6 +1026,8 @@ fn import_path_to_string(names: &[SpannedIdent], if names.is_empty() { import_directive_subclass_to_string(subclass) } else { + // FIXME: Remove this entire logic after #48116 is fixed. + // // Note that this code looks a little wonky, it's currently here to // hopefully help debug #48116, but otherwise isn't intended to // cause any problems. @@ -1034,8 +1036,17 @@ fn import_path_to_string(names: &[SpannedIdent], names_to_string(names), import_directive_subclass_to_string(subclass), ); - assert!(!names.is_empty()); - assert!(!x.starts_with("::")); + if names.is_empty() || x.starts_with("::") { + span_bug!( + span, + "invalid name `{}` at {:?}; global = {}, names = {:?}, subclass = {:?}", + x, + span, + global, + names, + subclass + ); + } return x } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a87809dd7bcf..bef085e17ea1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -250,6 +250,7 @@ impl<'test> TestCx<'test> { fn run_cfail_test(&self) { let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); + self.check_no_compiler_crash(&proc_res); let output_to_check = self.get_output(&proc_res); let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); @@ -262,7 +263,6 @@ impl<'test> TestCx<'test> { self.check_error_patterns(&output_to_check, &proc_res); } - self.check_no_compiler_crash(&proc_res); self.check_forbid_output(&output_to_check, &proc_res); } From 7cf5ea02a94814d52825c742bd1d1415748c505b Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 13 Feb 2018 08:08:38 -0700 Subject: [PATCH 64/87] Add note about Cargo cwd change to release notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index d6f95f52075d..7a9d256be282 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -78,6 +78,7 @@ Compatibility Notes - [`column!()` macro is one-based instead of zero-based][46977] - [`fmt::Arguments` can no longer be shared across threads][45198] - [Access to `#[repr(packed)]` struct fields is now unsafe][44884] +- [Cargo sets a different working directory for the compiler][cargo/4788] [44884]: https://github.com/rust-lang/rust/pull/44884 [45198]: https://github.com/rust-lang/rust/pull/45198 @@ -106,6 +107,7 @@ Compatibility Notes [47080]: https://github.com/rust-lang/rust/pull/47080 [47084]: https://github.com/rust-lang/rust/pull/47084 [cargo/4743]: https://github.com/rust-lang/cargo/pull/4743 +[cargo/4788]: https://github.com/rust-lang/cargo/pull/4788 [cargo/4817]: https://github.com/rust-lang/cargo/pull/4817 [`RefCell::replace`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace [`RefCell::swap`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.swap From fbad3b2468f46c14d0fd1283aa4935b3d79f007b Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 13 Feb 2018 08:48:25 -0700 Subject: [PATCH 65/87] Switch to retain calling drain_filter. --- src/liballoc/vec.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 41ba8e12105b..5c7f8ef73217 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -805,27 +805,7 @@ impl Vec { pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool { - let len = self.len(); - let mut del = 0; - { - let v = &mut **self; - - for i in 0..len { - if !f(&v[i]) { - del += 1; - unsafe { - ptr::drop_in_place(&mut v[i]); - } - } else if del > 0 { - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - unsafe { - ptr::copy_nonoverlapping(src, dst, 1); - } - } - } - } - self.len = len - del; + self.drain_filter(|x| !f(x)); } /// Removes all but the first of consecutive elements in the vector that resolve to the same From a295ec1ec9d7616474a620a8acd15944aaf0c638 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:32:35 +0000 Subject: [PATCH 66/87] 38880 restore original entry(key) method --- src/libstd/collections/hash/map.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c4f3fdc283ef..23a932c7aa36 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1031,7 +1031,9 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - self.search_mut(&key).into_entry(key).expect("unreachable") + let hash = self.make_hash(&key); + search_hashed(&mut self.table, hash, |q| q.eq(&key)) + .into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. From 94c3c84b6a9c382862b1f750f782c33256fa58bd Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:33:00 +0000 Subject: [PATCH 67/87] 38880 hashmap check size=0, not just capacity=0 --- src/libstd/collections/hash/map.rs | 54 +++++++++++++----------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 23a932c7aa36..fdc62be3dd96 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -414,7 +414,6 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE search_hashed_nonempty(table, hash, is_match) } - /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) @@ -557,32 +556,36 @@ impl HashMap } /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. + /// If you already have the hash for the key lying around, or if you need an + /// InternalEntry, use search_hashed or search_hashed_nonempty. #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry> + fn search<'a, Q: ?Sized>(&'a self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if !self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry> + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } // The caller should ensure that invariants by Robin Hood Hashing hold @@ -1140,7 +1143,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1167,7 +1170,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().is_some() + self.search(k).is_some() } /// Returns a mutable reference to the value corresponding to the key. @@ -1196,7 +1199,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Inserts a key-value pair into the map. @@ -1256,11 +1259,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - - self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } /// Removes a key from the map, returning the stored key and value if the @@ -1296,7 +1295,6 @@ impl HashMap } self.search_mut(k) - .into_occupied_bucket() .map(|bucket| { let (k, v, _) = pop_internal(bucket); (k, v) @@ -2654,15 +2652,11 @@ impl super::Recover for HashMap #[inline] fn get(&self, key: &Q) -> Option<&K> { - self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) + self.search(key).map(|bucket| bucket.into_refs().0) } fn take(&mut self, key: &Q) -> Option { - if self.table.size() == 0 { - return None; - } - - self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) + self.search_mut(key).map(|bucket| pop_internal(bucket).0) } #[inline] From f3330cea7f43288362fec9b010b04e22dfbf45a2 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 17:15:58 +0000 Subject: [PATCH 68/87] 38880 fix incorrect negation --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fdc62be3dd96..a8f419d6c6c8 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -564,7 +564,7 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - if !self.is_empty() { + if self.is_empty() { return None; } From e034dddb32cd9814d9f71bb2b444f9863fba2dfc Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 20:25:10 +0000 Subject: [PATCH 69/87] 38880 remove unnecessary self.table.size check --- src/libstd/collections/hash/map.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8f419d6c6c8..a82ff915093c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1290,10 +1290,6 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - self.search_mut(k) .map(|bucket| { let (k, v, _) = pop_internal(bucket); From 893fc3274477fe22fb3b481583df9d0b81df718d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 13 Feb 2018 22:25:41 +0100 Subject: [PATCH 70/87] Update compiler-builtins to latest master. - Rebase compiler-rt to LLVM 6 - New VFP intrinsics on ARM - Add generic conversion from a narrower to a wider FP type (f32->f64) - Fixes minor issues on _subsf3, __subdf3 and __aeabi_fcmple - Split test suite to a separate crate --- src/libcompiler_builtins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 345447948f7a..266ea0740a5b 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 345447948f7a51eca970fa036cefd613d54a4f79 +Subproject commit 266ea0740a5bdd262a38bbd88fb55fc3d2a7a96e From a64575c3bd81f6f169eff22a4884984c9c5b36c0 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 13 Feb 2018 18:42:26 -0700 Subject: [PATCH 71/87] Fix default Steps without paths. Some Steps are by-default run but don't have any paths associated with them. We need to have at least one PathSet per each Step, though, so we add an empty one on calls to `never()`. --- src/bootstrap/builder.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cbd303e11406..c00138d85e14 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -95,7 +95,7 @@ pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, pub host: Interned, pub target: Interned, - pub path: &'a Path, + pub path: PathBuf, } struct StepDescription { @@ -114,6 +114,10 @@ struct PathSet { } impl PathSet { + fn empty() -> PathSet { + PathSet { set: BTreeSet::new() } + } + fn one>(path: P) -> PathSet { let mut set = BTreeSet::new(); set.insert(path.into()); @@ -124,8 +128,8 @@ impl PathSet { self.set.iter().any(|p| p.ends_with(needle)) } - fn path(&self) -> &Path { - self.set.iter().next().unwrap() + fn path(&self, builder: &Builder) -> PathBuf { + self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf() } } @@ -174,7 +178,7 @@ impl StepDescription { for target in targets { let run = RunConfig { builder, - path: pathset.path(), + path: pathset.path(builder), host: *host, target: *target, }; @@ -278,7 +282,8 @@ impl<'a> ShouldRun<'a> { } // allows being more explicit about why should_run in Step returns the value passed to it - pub fn never(self) -> ShouldRun<'a> { + pub fn never(mut self) -> ShouldRun<'a> { + self.paths.insert(PathSet::empty()); self } From fa94c5c3112cf6008a12ea505a3e9a909e74e244 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 14 Feb 2018 21:09:51 +1300 Subject: [PATCH 72/87] Update RLS --- src/Cargo.lock | 54 ++++++++++++++++++++++++++++++++++---------------- src/tools/rls | 2 +- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 6b722db53ed3..4b3099eed016 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -328,6 +328,26 @@ dependencies = [ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clippy_lints" +version = "0.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cmake" version = "0.1.29" @@ -1003,7 +1023,7 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.27.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1640,17 +1660,20 @@ name = "rls" version = "0.125.0" dependencies = [ "cargo 0.26.0", + "clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1663,27 +1686,21 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rls-data" -version = "0.14.0" +name = "rls-blacklist" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rls-data" @@ -1692,6 +1709,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2986,6 +3005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" +"checksum clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)" = "a3864104a4e6092e644b985dd7543e5f24e99aa7262f5ee400bcb17cfeec1bf5" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" @@ -3050,7 +3070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kuchiki 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e03098e8e719c92b7794515dfd5c1724e2b12f5ce1788e61cfa4663f82eba8d8" -"checksum languageserver-types 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a2036fc8576a22689b7e3171c07eb8e8f700678d7a8a53f6f65abbeb35261e1" +"checksum languageserver-types 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1541f9b22687f060511d213036e1f058797c48e3501e177f01cb6e88de802f5b" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" @@ -3114,8 +3134,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" -"checksum rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "38841e3c5271715a574ac220d9b408b59ed9e2626909c3bc54b5853b4eaadb7b" -"checksum rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8024f1feaca72d0aa4ae1e2a8d454a31b9a33ed02f8d0e9c8559bf53c267ec3c" +"checksum rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30b08808959205a5cf23c68ace2d9d6defdd6867f3cd5d62981cf50fb52f8882" +"checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" "checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" diff --git a/src/tools/rls b/src/tools/rls index dee42bda8156..f01491115e82 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e +Subproject commit f01491115e821e10217574ad4091b08015b7b1c8 From 288c0c3081419c0d522d76cfbb36fabd038ed4f2 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 11:30:53 +0000 Subject: [PATCH 73/87] Clarified why `Sized` bound not implicit on trait's implicit `Self` type. --- src/libcore/marker.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3032fb2de33a..5b482d467bc8 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -63,9 +63,13 @@ impl !Send for *mut T { } /// struct BarUse(Bar<[i32]>); // OK /// ``` /// -/// The one exception is the implicit `Self` type of a trait, which does not -/// get an implicit `Sized` bound. This is because a `Sized` bound prevents -/// the trait from being used to form a [trait object]: +/// The one exception is the implicit `Self` type of a trait. A trait does not +/// have an implicit `Sized` bound as this is incompatible with [trait object]s +/// where, by definition, one cannot know the size of all possible +/// implementations of the trait. +/// +/// Although Rust will let you bind `Sized` to a trait, you won't +/// be able to use it as a trait object later: /// /// ``` /// # #![allow(unused_variables)] From ec36e7e972e8036fe7bd428458462a2aacd40927 Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 14 Feb 2018 23:18:18 +0800 Subject: [PATCH 74/87] Partially revert #47333. Removed the `assume()` which we assumed is the cause of misoptimization in issue #48116. --- src/libcore/slice/mod.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index aacbbd5058e0..ac390313a679 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1246,15 +1246,18 @@ macro_rules! iterator { { // The addition might panic on overflow // Use the len of the slice to hint optimizer to remove result index bounds check. - let n = make_slice!(self.ptr, self.end).len(); + let _n = make_slice!(self.ptr, self.end).len(); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } #[inline] @@ -1271,10 +1274,13 @@ macro_rules! iterator { if predicate(x) { Err(i) } else { Ok(i) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } } From e0da9902a1ab8e620be45470130cd72e31d54fc2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 14 Feb 2018 07:44:53 -0800 Subject: [PATCH 75/87] Revert "rustbuild: Pass `ccache` to build scripts" This reverts commit 64a8730e171367e4979cd9c25f0e0fdc2c157446. --- src/bootstrap/builder.rs | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 74dd4a6fa014..03630dfbed3e 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -600,25 +600,9 @@ impl<'a> Builder<'a> { // // FIXME: the guard against msvc shouldn't need to be here if !target.contains("msvc") { - let ccache = self.config.ccache.as_ref(); - let ccacheify = |s: &Path| { - let ccache = match ccache { - Some(ref s) => s, - None => return s.display().to_string(), - }; - // FIXME: the cc-rs crate only recognizes the literal strings - // `ccache` and `sccache` when doing caching compilations, so we - // mirror that here. It should probably be fixed upstream to - // accept a new env var or otherwise work with custom ccache - // vars. - match &ccache[..] { - "ccache" | "sccache" => format!("{} {}", ccache, s.display()), - _ => s.display().to_string(), - } - }; - let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc) - .env("CC", &cc); + let cc = self.cc(target); + cargo.env(format!("CC_{}", target), cc) + .env("CC", cc); let cflags = self.cflags(target).join(" "); cargo.env(format!("CFLAGS_{}", target), cflags.clone()) @@ -633,9 +617,8 @@ impl<'a> Builder<'a> { } if let Ok(cxx) = self.cxx(target) { - let cxx = ccacheify(&cxx); - cargo.env(format!("CXX_{}", target), &cxx) - .env("CXX", &cxx) + cargo.env(format!("CXX_{}", target), cxx) + .env("CXX", cxx) .env(format!("CXXFLAGS_{}", target), cflags.clone()) .env("CXXFLAGS", cflags); } From 45944f670bec8128ef0b51a2391cd6c3c0f42941 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Wed, 14 Feb 2018 09:57:21 -0700 Subject: [PATCH 76/87] Exclude clippy lints from tidy license check --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 159c9e035b7a..4dedf6bfe779 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -41,6 +41,7 @@ static EXCEPTIONS: &'static [&'static str] = &[ "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) "cssparser-macros", // MPL-2.0, rustdoc "selectors", // MPL-2.0, rustdoc + "clippy_lints", // MPL-2.0 rls ]; pub fn check(path: &Path, bad: &mut bool) { From 673d97e3ca764e4fd9a3c6389f5f0f2e19e0584d Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 27 Jan 2018 20:15:18 +0000 Subject: [PATCH 77/87] Added tests for #47703 --- src/test/run-pass/issue-47703-1.rs | 33 ++++++++++++++++++++++++++++++ src/test/run-pass/issue-47703.rs | 28 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/run-pass/issue-47703-1.rs create mode 100644 src/test/run-pass/issue-47703.rs diff --git a/src/test/run-pass/issue-47703-1.rs b/src/test/run-pass/issue-47703-1.rs new file mode 100644 index 000000000000..facdee5cc176 --- /dev/null +++ b/src/test/run-pass/issue-47703-1.rs @@ -0,0 +1,33 @@ +// 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(nll)] + +struct AtomicRefMut<'a> { + value: &'a mut i32, + borrow: AtomicBorrowRefMut, +} + +struct AtomicBorrowRefMut { +} + +impl Drop for AtomicBorrowRefMut { + fn drop(&mut self) { + } +} + +fn map(orig: AtomicRefMut) -> AtomicRefMut { + AtomicRefMut { + value: orig.value, + borrow: orig.borrow, + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-47703.rs b/src/test/run-pass/issue-47703.rs new file mode 100644 index 000000000000..2146986377a0 --- /dev/null +++ b/src/test/run-pass/issue-47703.rs @@ -0,0 +1,28 @@ +// 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(nll)] + +struct MyStruct<'a> { + field: &'a mut (), + field2: WithDrop +} + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +impl<'a> MyStruct<'a> { + fn consume(self) -> &'a mut () { self.field } +} + +fn main() {} From 6493ab6f2aa709c019baf640e31699535679553d Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 31 Jan 2018 23:46:05 +0000 Subject: [PATCH 78/87] Fixed incorrect reporting of errors when checking borrows in drops. --- src/librustc_mir/borrow_check/mod.rs | 50 ++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c4df7349391e..e321661e40ef 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -2073,7 +2073,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// currently in, when such distinction matters. fn each_borrow_involving_path( &mut self, - _context: Context, + context: Context, access_place: (ShallowOrDeep, &Place<'tcx>), flow_state: &Flows<'cx, 'gcx, 'tcx>, mut op: F, @@ -2085,20 +2085,50 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // FIXME: analogous code in check_loans first maps `place` to // its base_path. + // When this function is called as a result of an `access_terminator` call attempting + // to drop a struct, if that struct does not have a destructor, then we need to check + // each of the fields in the struct. See #47703. + let (access, places) = if let ContextKind::Drop = context.kind { + let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + + match ty.sty { + ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { + let mut places = Vec::new(); + + for (index, field) in def.all_fields().enumerate() { + let proj = Projection { + base: place.clone(), + elem: ProjectionElem::Field(Field::new(index), + field.ty(self.tcx, substs)), + }; + + places.push(Place::Projection(Box::new(proj))); + } + + (ShallowOrDeep::Shallow(None), places) + }, + _ => (access, vec![ place.clone() ]), + } + } else { + (access, vec![ place.clone() ]) + }; + let data = flow_state.borrows.operator().borrows(); // check for loan restricting path P being used. Accounts for // borrows of P, P.a.b, etc. - let mut elems_incoming = flow_state.borrows.elems_incoming(); - while let Some(i) = elems_incoming.next() { - let borrowed = &data[i.borrow_index()]; + for place in places { + let mut elems_incoming = flow_state.borrows.elems_incoming(); + while let Some(i) = elems_incoming.next() { + let borrowed = &data[i.borrow_index()]; - if self.places_conflict(&borrowed.borrowed_place, place, access) { - debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", - i, borrowed, place, access); - let ctrl = op(self, i, borrowed); - if ctrl == Control::Break { - return; + if self.places_conflict(&borrowed.borrowed_place, &place, access) { + debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", + i, borrowed, place, access); + let ctrl = op(self, i, borrowed); + if ctrl == Control::Break { + return; + } } } } From e7f328ea574bbfc3e927be01eb5f7b66bae5a578 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 1 Feb 2018 12:27:56 +0000 Subject: [PATCH 79/87] Handle recursive case of dropping structs with field accesses when struct has no dtor. --- src/librustc_mir/borrow_check/mod.rs | 117 ++++++++++++++++----------- 1 file changed, 70 insertions(+), 47 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index e321661e40ef..af834ede1ee3 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -463,13 +463,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx target: _, unwind: _, } => { - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); + self.visit_terminator_drop(loc, term, flow_state, drop_place, span); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -717,6 +711,65 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } + fn visit_terminator_drop( + &mut self, + loc: Location, + term: &Terminator<'tcx>, + flow_state: &Flows<'cx, 'gcx, 'tcx>, + drop_place: &Place<'tcx>, + span: Span, + ) { + let ty = drop_place.ty(self.mir, self.tcx).to_ty(self.tcx); + match ty.sty { + // When a struct is being dropped, we need to check whether it has a + // destructor, if it does, then we can call it, if it does not then we + // need to check the individual fields instead. + // See #47703. + ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { + for (index, field) in def.all_fields().enumerate() { + let field_ty = field.ty(self.tcx, substs); + let proj = Projection { + base: drop_place.clone(), + elem: ProjectionElem::Field(Field::new(index), field_ty), + }; + let place = Place::Projection(Box::new(proj)); + + match field_ty.sty { + // It may be the case that this issue occurs with a struct within a + // struct, so we recurse to handle that. + ty::TyAdt(def, _) if def.is_struct() && !def.has_dtor(self.tcx) => { + self.visit_terminator_drop( + loc, + term, + flow_state, + &place, + span, + ); + }, + _ => { + self.access_place( + ContextKind::Drop.new(loc), + (&place, span), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + }, + } + } + }, + _ => { + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + }, + } + } + /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this @@ -2073,7 +2126,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// currently in, when such distinction matters. fn each_borrow_involving_path( &mut self, - context: Context, + _context: Context, access_place: (ShallowOrDeep, &Place<'tcx>), flow_state: &Flows<'cx, 'gcx, 'tcx>, mut op: F, @@ -2085,50 +2138,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // FIXME: analogous code in check_loans first maps `place` to // its base_path. - // When this function is called as a result of an `access_terminator` call attempting - // to drop a struct, if that struct does not have a destructor, then we need to check - // each of the fields in the struct. See #47703. - let (access, places) = if let ContextKind::Drop = context.kind { - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); - - match ty.sty { - ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { - let mut places = Vec::new(); - - for (index, field) in def.all_fields().enumerate() { - let proj = Projection { - base: place.clone(), - elem: ProjectionElem::Field(Field::new(index), - field.ty(self.tcx, substs)), - }; - - places.push(Place::Projection(Box::new(proj))); - } - - (ShallowOrDeep::Shallow(None), places) - }, - _ => (access, vec![ place.clone() ]), - } - } else { - (access, vec![ place.clone() ]) - }; - let data = flow_state.borrows.operator().borrows(); // check for loan restricting path P being used. Accounts for // borrows of P, P.a.b, etc. - for place in places { - let mut elems_incoming = flow_state.borrows.elems_incoming(); - while let Some(i) = elems_incoming.next() { - let borrowed = &data[i.borrow_index()]; + let mut elems_incoming = flow_state.borrows.elems_incoming(); + while let Some(i) = elems_incoming.next() { + let borrowed = &data[i.borrow_index()]; - if self.places_conflict(&borrowed.borrowed_place, &place, access) { - debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", - i, borrowed, place, access); - let ctrl = op(self, i, borrowed); - if ctrl == Control::Break { - return; - } + if self.places_conflict(&borrowed.borrowed_place, &place, access) { + debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", + i, borrowed, place, access); + let ctrl = op(self, i, borrowed); + if ctrl == Control::Break { + return; } } } From 5fd64dde2198971df0869cbf4944d3996395b826 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 5 Feb 2018 17:04:25 +0000 Subject: [PATCH 80/87] Simplified logic and corrected shallow to deep. --- src/librustc_mir/borrow_check/mod.rs | 38 ++++++++-------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index af834ede1ee3..46f94f2388ff 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -727,35 +727,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { for (index, field) in def.all_fields().enumerate() { - let field_ty = field.ty(self.tcx, substs); - let proj = Projection { - base: drop_place.clone(), - elem: ProjectionElem::Field(Field::new(index), field_ty), - }; - let place = Place::Projection(Box::new(proj)); + let place = drop_place.clone(); + let place = place.field(Field::new(index), field.ty(self.tcx, substs)); + let place = place.deref(); - match field_ty.sty { - // It may be the case that this issue occurs with a struct within a - // struct, so we recurse to handle that. - ty::TyAdt(def, _) if def.is_struct() && !def.has_dtor(self.tcx) => { - self.visit_terminator_drop( - loc, - term, - flow_state, - &place, - span, - ); - }, - _ => { - self.access_place( - ContextKind::Drop.new(loc), - (&place, span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - }, - } + self.visit_terminator_drop( + loc, + term, + flow_state, + &place, + span, + ); } }, _ => { From 552024a52eb17b2542e87f9fc97b7b643707d759 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Feb 2018 14:49:27 -0500 Subject: [PATCH 81/87] check that types "need drop" before we access them Also, add some comments and remove extra deref. --- src/librustc_mir/borrow_check/mod.rs | 40 +++++++++++++++++++--------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 46f94f2388ff..3cdfe6400062 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -711,6 +711,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } + /// Invokes `access_place` as appropriate for dropping the value + /// at `drop_place`. Note that the *actual* `Drop` in the MIR is + /// always for a variable (e.g., `Drop(x)`) -- but we recursively + /// break this variable down into subpaths (e.g., `Drop(x.foo)`) + /// to indicate more precisely which fields might actually be + /// accessed by a destructor. fn visit_terminator_drop( &mut self, loc: Location, @@ -721,15 +727,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) { let ty = drop_place.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - // When a struct is being dropped, we need to check whether it has a - // destructor, if it does, then we can call it, if it does not then we - // need to check the individual fields instead. - // See #47703. + // When a struct is being dropped, we need to check + // whether it has a destructor, if it does, then we can + // call it, if it does not then we need to check the + // individual fields instead. This way if `foo` has a + // destructor but `bar` does not, we will only check for + // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { for (index, field) in def.all_fields().enumerate() { let place = drop_place.clone(); let place = place.field(Field::new(index), field.ty(self.tcx, substs)); - let place = place.deref(); self.visit_terminator_drop( loc, @@ -741,13 +748,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } }, _ => { - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); + // We have now refined the type of the value being + // dropped (potentially) to just the type of a + // subfield; so check whether that field's type still + // "needs drop". If so, we assume that the destructor + // may access any data it likes (i.e., a Deep Write). + let gcx = self.tcx.global_tcx(); + let erased_ty = gcx.lift(&self.tcx.erase_regions(&ty)).unwrap(); + if erased_ty.needs_drop(gcx, self.param_env) { + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + } }, } } From 38064a9a7ce6b5050ca1d629aef22f17f2548d07 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 19:14:25 +0000 Subject: [PATCH 82/87] Review change - Expanded on explanation. --- src/libcore/marker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 5b482d467bc8..98e0f71eb935 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -65,11 +65,11 @@ impl !Send for *mut T { } /// /// The one exception is the implicit `Self` type of a trait. A trait does not /// have an implicit `Sized` bound as this is incompatible with [trait object]s -/// where, by definition, one cannot know the size of all possible -/// implementations of the trait. +/// where, by definition, the trait needs to work with all possible implementors, +/// and thus could be any size. /// /// Although Rust will let you bind `Sized` to a trait, you won't -/// be able to use it as a trait object later: +/// be able to use it to form a trait object later: /// /// ``` /// # #![allow(unused_variables)] From 98904c2ecc580b27f87e43dbe3e7f6995a2ec3a2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 14 Feb 2018 18:14:31 +0000 Subject: [PATCH 83/87] Normalizing associated types when checking borrows in drops. --- src/librustc_mir/borrow_check/mod.rs | 31 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 3cdfe6400062..650f99828ae4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -463,7 +463,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx target: _, unwind: _, } => { - self.visit_terminator_drop(loc, term, flow_state, drop_place, span); + let gcx = self.tcx.global_tcx(); + + // Compute the type with accurate region information. + let drop_place_ty = drop_place.ty(self.mir, self.tcx); + + // Erase the regions. + let drop_place_ty = self.tcx.erase_regions(&drop_place_ty).to_ty(self.tcx); + + // "Lift" into the gcx -- once regions are erased, this type should be in the + // global arenas; this "lift" operation basically just asserts that is true, but + // that is useful later. + let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); + + self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -723,10 +736,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { term: &Terminator<'tcx>, flow_state: &Flows<'cx, 'gcx, 'tcx>, drop_place: &Place<'tcx>, + erased_drop_place_ty: ty::Ty<'gcx>, span: Span, ) { - let ty = drop_place.ty(self.mir, self.tcx).to_ty(self.tcx); - match ty.sty { + match erased_drop_place_ty.sty { // When a struct is being dropped, we need to check // whether it has a destructor, if it does, then we can // call it, if it does not then we need to check the @@ -735,14 +748,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { for (index, field) in def.all_fields().enumerate() { - let place = drop_place.clone(); - let place = place.field(Field::new(index), field.ty(self.tcx, substs)); + let gcx = self.tcx.global_tcx(); + let field_ty = field.ty(gcx, substs); + let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env); + let place = drop_place.clone().field(Field::new(index), field_ty); self.visit_terminator_drop( loc, term, flow_state, &place, + field_ty, span, ); } @@ -754,8 +770,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // "needs drop". If so, we assume that the destructor // may access any data it likes (i.e., a Deep Write). let gcx = self.tcx.global_tcx(); - let erased_ty = gcx.lift(&self.tcx.erase_regions(&ty)).unwrap(); - if erased_ty.needs_drop(gcx, self.param_env) { + if erased_drop_place_ty.needs_drop(gcx, self.param_env) { self.access_place( ContextKind::Drop.new(loc), (drop_place, span), @@ -2144,7 +2159,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { while let Some(i) = elems_incoming.next() { let borrowed = &data[i.borrow_index()]; - if self.places_conflict(&borrowed.borrowed_place, &place, access) { + if self.places_conflict(&borrowed.borrowed_place, place, access) { debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", i, borrowed, place, access); let ctrl = op(self, i, borrowed); From 220bb22e1b621ad5a10a44080e3e1872d99f3e9f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 14 Feb 2018 17:25:42 +0000 Subject: [PATCH 84/87] add Self: Trait<..> inside the param_env of a default impl --- src/libcore/iter/mod.rs | 6 +-- src/librustc/traits/select.rs | 42 +++++-------------- src/librustc/ty/mod.rs | 25 +---------- src/librustc_typeck/collect.rs | 20 ++++++++- ...ecialization-trait-item-not-implemented.rs | 2 + .../specialization-trait-not-implemented.rs | 4 ++ .../defaultimpl/specialization-wfcheck.rs | 2 + ...ecialization-trait-item-not-implemented.rs | 10 ++++- 8 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index bf8367d85fd1..652e0027383c 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -579,15 +579,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned {} #[doc(hidden)] -default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned where I: TrustedRandomAccess, T: Clone { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { self.it.get_unchecked(i).clone() } #[inline] - fn may_have_side_effect() -> bool { true } + default fn may_have_side_effect() -> bool { true } } #[doc(hidden)] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index aa43bf8ca2ef..4ed25646d436 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1710,44 +1710,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - // Check if default impls should be emitted. - // default impls are emitted if the param_env is refered to a default impl. - // The param_env should contain a Self: Trait<..> predicate in those cases - let self_trait_is_present:Vec<&ty::Predicate<'tcx>> = - obligation.param_env - .caller_bounds - .iter() - .filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref trait_predicate) => { - trait_predicate.def_id() == - obligation.predicate.def_id() && - obligation.predicate.0.trait_ref.self_ty() == - trait_predicate.skip_binder().self_ty() - } - _ => false - } - }).collect::>>(); - self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self_trait_is_present.len() > 0 || - !self.tcx().impl_is_default(impl_def_id) { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); - } - Err(_) => { } + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); } - }); - } + Err(_) => { } + } + }); } ); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 52d33c750f86..f52f2ea0f9fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,31 +2606,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. - let mut predicates = tcx.predicates_of(def_id); - match tcx.hir.as_local_node_id(def_id) - .and_then(|node_id| tcx.hir.find(node_id)) - .and_then(|item| { - match item { - hir::map::NodeItem(..) => { - if tcx.impl_is_default(def_id) { - tcx.impl_trait_ref(def_id) - } else { - None - } - } - _ => None - } - }) { - Some(trait_ref) => - predicates.predicates - .push( - trait_ref.to_poly_trait_ref() - .to_predicate() - ), - None => {} - } - let bounds = predicates.instantiate_identity(tcx); + let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c224..1c8d22e4666a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; + let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); @@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { + ItemImpl(_, _, defaultness, ref generics, ..) => { + if defaultness.is_default() { + is_default_impl_trait = tcx.impl_trait_ref(def_id); + } + generics + } ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } + // In default impls, we can assume that the self type implements + // the trait. So in: + // + // default impl Foo for Bar { .. } + // + // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // (see below). Recall that a default impl is not itself an impl, but rather a + // set of defaults that can be incorporated into another impl. + if let Some(trait_ref) = is_default_impl_trait { + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 072507851d79..eacec2e40f07 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that default impls do not have to supply all items but regular impls do. + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index d020a6775772..04ddf9ebb177 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that: +// - default impls do not have to supply all items and +// - a default impl does not count as an impl (in this case, an incomplete default impl). + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 342297379928..445a59a373e5 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that a default impl still has to have a WF trait ref. + #![feature(specialization)] trait Foo<'a, T: Eq + 'a> { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index e11a30214974..fc7312020053 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,18 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that we can combine a default impl that supplies one method with a +// full impl that supplies the other, and they can invoke one another. + #![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; + fn foo_three(&self) -> &'static str; } struct MyStruct; default impl Foo for T { fn foo_one(&self) -> &'static str { - "generic" + self.foo_three() } } @@ -27,6 +31,10 @@ impl Foo for MyStruct { fn foo_two(&self) -> &'static str { self.foo_one() } + + fn foo_three(&self) -> &'static str { + "generic" + } } fn main() { From e78ecd2e70961e64040598a019febec44959f7dd Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 15 Feb 2018 18:01:26 -0700 Subject: [PATCH 85/87] Prevent silently ignoring unmatched paths Primarily for CI purposes; this is intended to avoid cases where we update rustbuild and unintentionally make CI stop running some builds to the arguments being passed no longer applying for some reason. --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 001ae7246fdf..22a128e38e80 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -217,7 +217,7 @@ impl StepDescription { } if !attempted_run { - eprintln!("Warning: no rules matched {}.", path.display()); + panic!("Error: no rules matched {}.", path.display()); } } } From 366a65665aed84fda50e4ea8bc905153ffcc1287 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 15 Feb 2018 18:12:04 -0700 Subject: [PATCH 86/87] Consider paths passed to x.py to be root-relative. We'd previously assumed that these paths would be relative to the src dir, and that for example our various CI scripts would, when calling x.py, use `../x.py build ../src/tools/...` but this isn't the case -- they use `../x.py` without using the relevant source-relative path. We eventually may want to make this (actually somewhat logical) change, but this is not that time. --- src/bootstrap/builder.rs | 4 ++++ src/bootstrap/flags.rs | 8 ++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 22a128e38e80..7345b284dc70 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -385,6 +385,10 @@ impl<'a> Builder<'a> { Subcommand::Clean { .. } => panic!(), }; + if paths[0] == Path::new("nonexistent/path/to/trigger/cargo/metadata") { + return; + } + let builder = Builder { build, top_stage: build.config.stage.unwrap_or(2), diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 8a38fedc6136..42b949527e09 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -278,9 +278,7 @@ Arguments: let src = matches.opt_str("src").map(PathBuf::from) .or_else(|| env::var_os("SRC").map(PathBuf::from)) .unwrap_or(cwd.clone()); - let paths = matches.free[1..].iter().map(|p| { - cwd.join(p).strip_prefix(&src).expect("paths passed to be inside checkout").into() - }).collect::>(); + let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -380,9 +378,7 @@ Arguments: cmd, incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) - .into_iter().map(|p| { - cwd.join(p).strip_prefix(&src).expect("paths to be inside checkout").into() - }).collect::>(), + .into_iter().map(|p| p.into()).collect::>(), src, } } From c788433b15a81935abcb84e9644d04422bf84a48 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 16 Feb 2018 14:27:45 +0800 Subject: [PATCH 87/87] Fix panic when `x.py` is called without any arguments. --- src/bootstrap/builder.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7345b284dc70..66a1c9724620 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -385,8 +385,10 @@ impl<'a> Builder<'a> { Subcommand::Clean { .. } => panic!(), }; - if paths[0] == Path::new("nonexistent/path/to/trigger/cargo/metadata") { - return; + if let Some(path) = paths.get(0) { + if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { + return; + } } let builder = Builder {