From 507381ed0367f27e8804a1da33f8565c96a260ce Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Sat, 13 Oct 2018 23:38:31 +0200 Subject: [PATCH 01/16] Fix ICE and report a human readable error --- src/librustc/ty/cast.rs | 2 ++ src/librustc_mir/transform/qualify_min_const_fn.rs | 13 ++++++++++--- .../ui/consts/min_const_fn/bad_const_fn_body_ice.rs | 5 +++++ .../min_const_fn/bad_const_fn_body_ice.stderr | 10 ++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs create mode 100644 src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c0861abb774..ab82f28c8bf 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -58,6 +58,8 @@ pub enum CastKind { } impl<'tcx> CastTy<'tcx> { + /// Returns `Some` for integral/pointer casts. + /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> { match t.sty { ty::Bool => Some(CastTy::Int(IntTy::Bool)), diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index aa559c96ec6..edcae4648b7 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -148,7 +148,7 @@ fn check_rvalue( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { check_place(tcx, mir, place, span, PlaceMode::Read) } - Rvalue::Cast(_, operand, cast_ty) => { + Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -163,6 +163,10 @@ fn check_rvalue( _ => check_operand(tcx, mir, operand, span), } } + Rvalue::Cast(_, _, _) => Err(( + span, + "only int casts are allowed in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { check_operand(tcx, mir, lhs, span)?; @@ -177,8 +181,11 @@ fn check_rvalue( )) } } - // checked by regular const fn checks - Rvalue::NullaryOp(..) => Ok(()), + Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), + Rvalue::NullaryOp(NullOp::Box, _) => Err(( + span, + "heap allocations are not allowed in const fn".into(), + )), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(mir, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs new file mode 100644 index 00000000000..3e42cb8c1b0 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -0,0 +1,5 @@ +const fn foo(a: i32) -> Vec<i32> { + vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn +} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr new file mode 100644 index 00000000000..f6b704370b6 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -0,0 +1,10 @@ +error: heap allocations are not allowed in const fn + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + | ^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + From 34052047cf7cc30ccc8fbd947db56822d3d71423 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Mon, 15 Oct 2018 19:58:21 +0200 Subject: [PATCH 02/16] Explain all casts in detail --- src/librustc_mir/transform/qualify_min_const_fn.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index edcae4648b7..c9d48f5f6ad 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -163,9 +163,18 @@ fn check_rvalue( _ => check_operand(tcx, mir, operand, span), } } - Rvalue::Cast(_, _, _) => Err(( + Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | + Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( span, - "only int casts are allowed in const fn".into(), + "function pointer casts are not allowed in const fn".into(), + )), + Rvalue::Cast(CastKind::ClosureFnPointer, _, _) => Err(( + span, + "closures are not allowed in const fn".into(), + )), + Rvalue::Cast(CastKind::Unsize, _, _) => Err(( + span, + "unsizing casts are not allowed in const fn".into(), )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { From 2456f330d508b223d8cfcada8652ad37b647996a Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Mon, 15 Oct 2018 20:10:16 +0200 Subject: [PATCH 03/16] Try to trigger some error cases --- .../ui/consts/min_const_fn/cast_errors.rs | 14 ++++++++ .../ui/consts/min_const_fn/cast_errors.stderr | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/test/ui/consts/min_const_fn/cast_errors.rs create mode 100644 src/test/ui/consts/min_const_fn/cast_errors.stderr diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs new file mode 100644 index 00000000000..36827b1b6b0 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -0,0 +1,14 @@ +fn main() {} + +const fn unsize(x: &[u8; 3]) -> &[u8] { x } +//~^ ERROR unsizing casts are not allowed in const fn +const fn closure() -> fn() { || {} } +//~^ ERROR function pointers in const fn are unstable +const fn closure2() { + (|| {}) as fn(); +//~^ ERROR function pointers in const fn are unstable +} +const fn reify(f: fn()) -> unsafe fn() { f } +//~^ ERROR function pointers in const fn are unstable +const fn reify2() { main as unsafe fn(); } +//~^ ERROR function pointers in const fn are unstable \ No newline at end of file diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr new file mode 100644 index 00000000000..ba980b7aacb --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -0,0 +1,32 @@ +error: unsizing casts are not allowed in const fn + --> $DIR/cast_errors.rs:3:41 + | +LL | const fn unsize(x: &[u8; 3]) -> &[u8] { x } + | ^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:5:23 + | +LL | const fn closure() -> fn() { || {} } + | ^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:8:5 + | +LL | (|| {}) as fn(); + | ^^^^^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:11:28 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:13:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + From 007390c21cc5e5e8705d455d20fba1df13bd7362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= <github35764891676564198441@oli-obk.de> Date: Mon, 15 Oct 2018 20:30:11 +0200 Subject: [PATCH 04/16] Add trailing newline to satisfy tidy --- src/test/ui/consts/min_const_fn/cast_errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs index 36827b1b6b0..8648cd35387 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.rs +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -11,4 +11,4 @@ const fn closure2() { const fn reify(f: fn()) -> unsafe fn() { f } //~^ ERROR function pointers in const fn are unstable const fn reify2() { main as unsafe fn(); } -//~^ ERROR function pointers in const fn are unstable \ No newline at end of file +//~^ ERROR function pointers in const fn are unstable From 38f3ad41c0bbf6ed7c389a070afb60a465b3afe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= <github35764891676564198441@oli-obk.de> Date: Wed, 17 Oct 2018 09:04:10 +0200 Subject: [PATCH 05/16] Squash closure cast error into fn ptr cast error --- src/librustc_mir/transform/qualify_min_const_fn.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c9d48f5f6ad..52c557b83d5 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -164,14 +164,11 @@ fn check_rvalue( } } Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | + Rvalue::Cast(CastKind::ClosureFnPointer, _, _) | Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( span, "function pointer casts are not allowed in const fn".into(), )), - Rvalue::Cast(CastKind::ClosureFnPointer, _, _) => Err(( - span, - "closures are not allowed in const fn".into(), - )), Rvalue::Cast(CastKind::Unsize, _, _) => Err(( span, "unsizing casts are not allowed in const fn".into(), From da40916bc20880785daec954ee20ee18464ecb7a Mon Sep 17 00:00:00 2001 From: ljedrz <ljedrz@gmail.com> Date: Wed, 17 Oct 2018 11:13:44 +0200 Subject: [PATCH 06/16] resolve: improve common patterns --- src/librustc_resolve/build_reduced_graph.rs | 11 +- src/librustc_resolve/check_unused.rs | 6 +- src/librustc_resolve/lib.rs | 63 ++++----- src/librustc_resolve/resolve_imports.rs | 146 ++++++++++---------- 4 files changed, 105 insertions(+), 121 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 25a7ff9cd3f..e2f5829d14f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -139,7 +139,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let prefix_iter = || parent_prefix.iter().cloned() .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident)); - let prefix_start = prefix_iter().nth(0); + let prefix_start = prefix_iter().next(); let starts_with_non_keyword = prefix_start.map_or(false, |ident| { !ident.is_path_segment_keyword() }); @@ -1048,13 +1048,10 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> { fn visit_token(&mut self, t: Token) { if let Token::Interpolated(nt) = t { - match nt.0 { - token::NtExpr(ref expr) => { - if let ast::ExprKind::Mac(..) = expr.node { - self.visit_invoc(expr.id); - } + if let token::NtExpr(ref expr) = nt.0 { + if let ast::ExprKind::Mac(..) = expr.node { + self.visit_invoc(expr.id); } - _ => {} } } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index de9481579e2..6f3135b37cf 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -109,7 +109,7 @@ impl<'a, 'b, 'cl> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'cl> { self.item_span }; - if items.len() == 0 { + if items.is_empty() { self.unused_imports .entry(self.base_id) .or_default() @@ -170,7 +170,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { for (id, spans) in &visitor.unused_imports { let len = spans.len(); - let mut spans = spans.values().map(|s| *s).collect::<Vec<Span>>(); + let mut spans = spans.values().cloned().collect::<Vec<Span>>(); spans.sort(); let ms = MultiSpan::from_spans(spans.clone()); let mut span_snippets = spans.iter() @@ -183,7 +183,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { span_snippets.sort(); let msg = format!("unused import{}{}", if len > 1 { "s" } else { "" }, - if span_snippets.len() > 0 { + if !span_snippets.is_empty() { format!(": {}", span_snippets.join(", ")) } else { String::new() diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 86fe584dc3a..5f821cc71c9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1633,19 +1633,17 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), - PathResult::NonModule(..) => match self.resolve_path( - None, - &path, - None, - true, - span, - CrateLint::No, - ) { - PathResult::Failed(span, msg, _) => { + PathResult::NonModule(..) => + if let PathResult::Failed(span, msg, _) = self.resolve_path( + None, + &path, + None, + true, + span, + CrateLint::No, + ) { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); - } - _ => {} - }, + }, PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { @@ -2351,7 +2349,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { span: prefix.span.to(use_tree.prefix.span), }; - if items.len() == 0 { + if items.is_empty() { // Resolve prefix of an import with empty braces (issue #28388). self.smart_resolve_path_with_crate_lint( id, @@ -2690,7 +2688,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let map_j = self.binding_mode_map(&q); for (&key, &binding_i) in &map_i { - if map_j.len() == 0 { // Account for missing bindings when + if map_j.is_empty() { // Account for missing bindings when let binding_error = missing_vars // map_j has none. .entry(key.name) .or_insert(BindingError { @@ -2751,9 +2749,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // This has to happen *after* we determine which pat_idents are variants self.check_consistent_bindings(&arm.pats); - match arm.guard { - Some(ast::Guard::If(ref expr)) => self.visit_expr(expr), - _ => {} + if let Some(ast::Guard::If(ref expr)) = arm.guard { + self.visit_expr(expr) } self.visit_expr(&arm.body); @@ -2994,14 +2991,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // Make the base error. let expected = source.descr_expected(); let path_str = names_to_string(path); - let item_str = path[path.len() - 1]; + let item_str = path.last().unwrap(); let code = source.error_code(def.is_some()); let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), format!("not a {}", expected), span) } else { - let item_span = path[path.len() - 1].span; + let item_span = path.last().unwrap().span; let (mod_prefix, mod_str) = if path.len() == 1 { (String::new(), "this scope".to_string()) } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { @@ -3368,7 +3365,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { ); } break; - } else if snippet.trim().len() != 0 { + } else if !snippet.trim().is_empty() { debug!("tried to find type ascription `:` token, couldn't find it"); break; } @@ -3930,7 +3927,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } _ => {} } - return def; + def } fn lookup_assoc_candidate<FilterFn>(&mut self, @@ -4482,21 +4479,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let extern_prelude_names = self.extern_prelude.clone(); for &name in extern_prelude_names.iter() { let ident = Ident::with_empty_ctxt(name); - match self.crate_loader.maybe_process_path_extern(name, ident.span) { - Some(crate_id) => { - let crate_root = self.get_module(DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }); - self.populate_module_if_necessary(&crate_root); + if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name, + ident.span) + { + let crate_root = self.get_module(DefId { + krate: crate_id, + index: CRATE_DEF_INDEX, + }); + self.populate_module_if_necessary(&crate_root); - suggestions.extend( - self.lookup_import_candidates_from_module( - lookup_name, namespace, crate_root, ident, &filter_fn - ) - ); - } - None => {} + suggestions.extend(self.lookup_import_candidates_from_module( + lookup_name, namespace, crate_root, ident, &filter_fn)); } } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 48f312ce9f2..d5d772e1359 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -672,7 +672,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { }; let has_explicit_self = - import.module_path.len() > 0 && + !import.module_path.is_empty() && import.module_path[0].name == keywords::SelfValue.name(); self.per_ns(|_, ns| { @@ -703,9 +703,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if let SingleImport { source, ref result, .. } = import.subclass { if source.name == "self" { // Silence `unresolved import` error if E0429 is already emitted - match result.value_ns.get() { - Err(Determined) => continue, - _ => {}, + if let Err(Determined) = result.value_ns.get() { + continue; } } } @@ -822,20 +821,19 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>, span: Option<MultiSpan>) { let max_span_label_msg_count = 10; // upper limit on number of span_label message. - let (span,msg) = match error_vec.is_empty() { - true => (span.unwrap(), "unresolved import".to_string()), - false => { - let span = MultiSpan::from_spans(error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { elem.0 } - ).collect()); - let path_vec: Vec<String> = error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) } - ).collect(); - let path = path_vec.join(", "); - let msg = format!("unresolved import{} {}", - if path_vec.len() > 1 { "s" } else { "" }, path); - (span, msg) - } + let (span, msg) = if error_vec.is_empty() { + (span.unwrap(), "unresolved import".to_string()) + } else { + let span = MultiSpan::from_spans(error_vec.clone().into_iter() + .map(|elem: (Span, String, String)| { elem.0 }) + .collect()); + let path_vec: Vec<String> = error_vec.clone().into_iter() + .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }) + .collect(); + let path = path_vec.join(", "); + let msg = format!("unresolved import{} {}", + if path_vec.len() > 1 { "s" } else { "" }, path); + (span, msg) }; let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); for span_error in error_vec.into_iter().take(max_span_label_msg_count) { @@ -1026,9 +1024,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - match this.resolve_ident_in_module(module, ident, ns, record_used, span) { - Ok(_) => all_ns_failed = false, - _ => {} + if this.resolve_ident_in_module(module, ident, ns, record_used, span).is_ok() { + all_ns_failed = false; } }); @@ -1247,65 +1244,62 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } - match binding.kind { - NameBindingKind::Import { binding: orig_binding, directive, .. } => { - if ns == TypeNS && orig_binding.is_variant() && - !orig_binding.vis.is_at_least(binding.vis, &*self) { - let msg = match directive.subclass { - ImportDirectiveSubclass::SingleImport { .. } => { - format!("variant `{}` is private and cannot be re-exported", - ident) - }, - ImportDirectiveSubclass::GlobImport { .. } => { - let msg = "enum is private and its variants \ - cannot be re-exported".to_owned(); - let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! - Some(binding.span), - msg.clone()); - let fresh = self.session.one_time_diagnostics - .borrow_mut().insert(error_id); - if !fresh { - continue; - } - msg - }, - ref s @ _ => bug!("unexpected import subclass {:?}", s) - }; - let mut err = self.session.struct_span_err(binding.span, &msg); + if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { + if ns == TypeNS && orig_binding.is_variant() && + !orig_binding.vis.is_at_least(binding.vis, &*self) { + let msg = match directive.subclass { + ImportDirectiveSubclass::SingleImport { .. } => { + format!("variant `{}` is private and cannot be re-exported", + ident) + }, + ImportDirectiveSubclass::GlobImport { .. } => { + let msg = "enum is private and its variants \ + cannot be re-exported".to_owned(); + let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! + Some(binding.span), + msg.clone()); + let fresh = self.session.one_time_diagnostics + .borrow_mut().insert(error_id); + if !fresh { + continue; + } + msg + }, + ref s @ _ => bug!("unexpected import subclass {:?}", s) + }; + let mut err = self.session.struct_span_err(binding.span, &msg); - let imported_module = match directive.imported_module.get() { - Some(ModuleOrUniformRoot::Module(module)) => module, - _ => bug!("module should exist"), - }; - let resolutions = imported_module.parent.expect("parent should exist") - .resolutions.borrow(); - let enum_path_segment_index = directive.module_path.len() - 1; - let enum_ident = directive.module_path[enum_path_segment_index]; + let imported_module = match directive.imported_module.get() { + Some(ModuleOrUniformRoot::Module(module)) => module, + _ => bug!("module should exist"), + }; + let resolutions = imported_module.parent.expect("parent should exist") + .resolutions.borrow(); + let enum_path_segment_index = directive.module_path.len() - 1; + let enum_ident = directive.module_path[enum_path_segment_index]; - let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) - .expect("resolution should exist"); - let enum_span = enum_resolution.borrow() - .binding.expect("binding should exist") - .span; - let enum_def_span = self.session.source_map().def_span(enum_span); - let enum_def_snippet = self.session.source_map() - .span_to_snippet(enum_def_span).expect("snippet should exist"); - // potentially need to strip extant `crate`/`pub(path)` for suggestion - let after_vis_index = enum_def_snippet.find("enum") - .expect("`enum` keyword should exist in snippet"); - let suggestion = format!("pub {}", - &enum_def_snippet[after_vis_index..]); + let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) + .expect("resolution should exist"); + let enum_span = enum_resolution.borrow() + .binding.expect("binding should exist") + .span; + let enum_def_span = self.session.source_map().def_span(enum_span); + let enum_def_snippet = self.session.source_map() + .span_to_snippet(enum_def_span).expect("snippet should exist"); + // potentially need to strip extant `crate`/`pub(path)` for suggestion + let after_vis_index = enum_def_snippet.find("enum") + .expect("`enum` keyword should exist in snippet"); + let suggestion = format!("pub {}", + &enum_def_snippet[after_vis_index..]); - self.session - .diag_span_suggestion_once(&mut err, - DiagnosticMessageId::ErrorId(0), - enum_def_span, - "consider making the enum public", - suggestion); - err.emit(); - } + self.session + .diag_span_suggestion_once(&mut err, + DiagnosticMessageId::ErrorId(0), + enum_def_span, + "consider making the enum public", + suggestion); + err.emit(); } - _ => {} } } From 89c20b78d68345040d68f0b475276687d10fdc92 Mon Sep 17 00:00:00 2001 From: ljedrz <ljedrz@gmail.com> Date: Wed, 17 Oct 2018 11:36:19 +0200 Subject: [PATCH 07/16] resolve: improve/remove allocations --- src/librustc_resolve/lib.rs | 20 +++++--------------- src/librustc_resolve/macros.rs | 7 +++---- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5f821cc71c9..131b69429c6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3021,10 +3021,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit help message for fake-self from other languages like `this`(javascript) - let fake_self: Vec<Ident> = ["this", "my"].iter().map( - |s| Ident::from_str(*s) - ).collect(); - if fake_self.contains(&item_str) + if ["this", "my"].contains(&&*item_str.as_str()) && this.self_value_is_available(path[0].span, span) { err.span_suggestion_with_applicability( span, @@ -4377,10 +4374,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { where FilterFn: Fn(Def) -> bool { let mut candidates = Vec::new(); - let mut worklist = Vec::new(); let mut seen_modules = FxHashSet(); let not_local_module = crate_name != keywords::Crate.ident(); - worklist.push((start_module, Vec::<ast::PathSegment>::new(), not_local_module)); + let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)]; while let Some((in_module, path_segments, @@ -4467,13 +4463,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { -> Vec<ImportSuggestion> where FilterFn: Fn(Def) -> bool { - let mut suggestions = vec![]; - - suggestions.extend( - self.lookup_import_candidates_from_module( - lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn - ) - ); + let mut suggestions = self.lookup_import_candidates_from_module( + lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn); if self.session.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); @@ -4502,9 +4493,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { -> Option<(Module<'a>, ImportSuggestion)> { let mut result = None; - let mut worklist = Vec::new(); let mut seen_modules = FxHashSet(); - worklist.push((self.graph_root, Vec::new())); + let mut worklist = vec![(self.graph_root, Vec::new())]; while let Some((in_module, path_segments)) = worklist.pop() { // abort if the module is already found diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6c57e6c88ab..28284a45bcd 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -203,9 +203,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { self.current_module = invocation.module.get(); self.current_module.unresolved_invocations.borrow_mut().remove(&mark); self.current_module.unresolved_invocations.borrow_mut().extend(derives); - for &derive in derives { - self.invocations.insert(derive, invocation); - } + self.invocations.extend(derives.iter().map(|&derive| (derive, invocation))); let mut visitor = BuildReducedGraphVisitor { resolver: self, current_legacy_scope: invocation.parent_legacy_scope.get(), @@ -277,11 +275,12 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { if traits.is_empty() { attrs.remove(i); } else { - let mut tokens = Vec::new(); + let mut tokens = Vec::with_capacity(traits.len() - 1); for (j, path) in traits.iter().enumerate() { if j > 0 { tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); } + tokens.reserve((path.segments.len() * 2).saturating_sub(1)); for (k, segment) in path.segments.iter().enumerate() { if k > 0 { tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); From 0a858dc859f828af2c578bcf23418dd14c767f3c Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Wed, 17 Oct 2018 23:51:01 +0100 Subject: [PATCH 08/16] Don't warn about parentheses on `match (return)` --- src/librustc_lint/unused.rs | 13 ++++++++----- src/test/ui/lint/no-unused-parens-return-block.rs | 6 ++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/lint/no-unused-parens-return-block.rs diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 76717548521..4cf2072e792 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -276,10 +276,13 @@ impl UnusedParens { cx: &EarlyContext, value: &ast::Expr, msg: &str, - struct_lit_needs_parens: bool) { + followed_by_block: bool) { if let ast::ExprKind::Paren(ref inner) = value.node { - let necessary = struct_lit_needs_parens && - parser::contains_exterior_struct_lit(&inner); + let necessary = followed_by_block && if let ast::ExprKind::Ret(_) = inner.node { + true + } else { + parser::contains_exterior_struct_lit(&inner) + }; if !necessary { let pattern = pprust::expr_to_string(value); Self::remove_outer_parens(cx, value.span, &pattern, msg); @@ -343,7 +346,7 @@ impl LintPass for UnusedParens { impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) { use syntax::ast::ExprKind::*; - let (value, msg, struct_lit_needs_parens) = match e.node { + let (value, msg, followed_by_block) = match e.node { If(ref cond, ..) => (cond, "`if` condition", true), While(ref cond, ..) => (cond, "`while` condition", true), IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true), @@ -380,7 +383,7 @@ impl EarlyLintPass for UnusedParens { return; } }; - self.check_unused_parens_expr(cx, &value, msg, struct_lit_needs_parens); + self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) { diff --git a/src/test/ui/lint/no-unused-parens-return-block.rs b/src/test/ui/lint/no-unused-parens-return-block.rs new file mode 100644 index 00000000000..fc8dbb743e1 --- /dev/null +++ b/src/test/ui/lint/no-unused-parens-return-block.rs @@ -0,0 +1,6 @@ +// run-pass + +fn main() { + match (return) {} // ok + if (return) {} // ok +} From 0e6c3f29be98176c91aa77eb71c04cca18c51115 Mon Sep 17 00:00:00 2001 From: Raph Levien <raph.levien@gmail.com> Date: Wed, 17 Oct 2018 18:15:00 -0700 Subject: [PATCH 09/16] Add a `copysign` function to f32 and f64 This patch adds a `copysign` function to the float primitive types. It is an exceptionally useful function for writing efficient numeric code, as it often avoids branches, is auto-vectorizable, and there are efficient intrinsics for most platforms. I think this might work as-is, as the relevant `copysign` intrinsic is already used internally for the implementation of `signum`. It's possible that an implementation might be needed in japaric/libm for portability across all platforms, in which case I'll do that also. Part of the work towards #55107 --- src/libstd/f32.rs | 28 ++++++++++++++++++++++++++++ src/libstd/f64.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e8340b3ed9..4ae8d2dcf16 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -198,6 +198,34 @@ impl f32 { } } + /// Returns a number composed of the magnitude of one number and the sign of + /// another. + /// + /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(copysign)] + /// use std::f32; + /// + /// let f = 3.5_f32; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f32); + /// assert_eq!(f.copysign(-0.42), -3.5_f32); + /// assert_eq!((-f).copysign(0.42), 3.5_f32); + /// assert_eq!((-f).copysign(-0.42), -3.5_f32); + /// + /// assert!(f32::NAN.copysign(1.0).is_nan()); + /// ``` + #[inline] + #[unstable(feature="copysign", issue="0")] + pub fn copysign(self, y: f32) -> f32 { + unsafe { intrinsics::copysignf32(self, y) } + } + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 6880294afca..3b805d6fa42 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -176,6 +176,33 @@ impl f64 { } } + /// Returns a number composed of the magnitude of one number and the sign of + /// another, or `NAN` if the number is `NAN`. + /// + /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// equal to `-y`. + /// + /// # Examples + /// + /// ``` + /// #![feature(copysign)] + /// use std::f64; + /// + /// let f = 3.5_f64; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f64); + /// assert_eq!(f.copysign(-0.42), -3.5_f64); + /// assert_eq!((-f).copysign(0.42), 3.5_f64); + /// assert_eq!((-f).copysign(-0.42), -3.5_f64); + /// + /// assert!(f64::NAN.copysign(1.0).is_nan()); + /// ``` + #[inline] + #[unstable(feature="copysign", issue="0")] + pub fn copysign(self, y: f64) -> f64 { + unsafe { intrinsics::copysignf64(self, y) } + } + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// From 9a2e7026dcbd84641b05334b5b4b0a4d647944f4 Mon Sep 17 00:00:00 2001 From: Raph Levien <raph.levien@gmail.com> Date: Wed, 17 Oct 2018 21:09:55 -0700 Subject: [PATCH 10/16] Fix inconsistent documentation I improved the f32 version and made a copy-paste error for f64. --- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 4ae8d2dcf16..369745d8189 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -221,7 +221,7 @@ impl f32 { /// assert!(f32::NAN.copysign(1.0).is_nan()); /// ``` #[inline] - #[unstable(feature="copysign", issue="0")] + #[unstable(feature="copysign", issue="55169")] pub fn copysign(self, y: f32) -> f32 { unsafe { intrinsics::copysignf32(self, y) } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 3b805d6fa42..df23d62ecfd 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -177,10 +177,11 @@ impl f64 { } /// Returns a number composed of the magnitude of one number and the sign of - /// another, or `NAN` if the number is `NAN`. + /// another. /// /// Equal to `self` if the sign of `self` and `y` are the same, otherwise - /// equal to `-y`. + /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` + /// is returned. /// /// # Examples /// @@ -198,7 +199,7 @@ impl f64 { /// assert!(f64::NAN.copysign(1.0).is_nan()); /// ``` #[inline] - #[unstable(feature="copysign", issue="0")] + #[unstable(feature="copysign", issue="55169")] pub fn copysign(self, y: f64) -> f64 { unsafe { intrinsics::copysignf64(self, y) } } From 40bba70823466eb1458a4fd99a4f644411b4eae4 Mon Sep 17 00:00:00 2001 From: varkor <github@varkor.com> Date: Thu, 18 Oct 2018 10:35:01 +0100 Subject: [PATCH 11/16] Make warnings into errors --- src/test/ui/lint/no-unused-parens-return-block.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ui/lint/no-unused-parens-return-block.rs b/src/test/ui/lint/no-unused-parens-return-block.rs index fc8dbb743e1..37dc519a204 100644 --- a/src/test/ui/lint/no-unused-parens-return-block.rs +++ b/src/test/ui/lint/no-unused-parens-return-block.rs @@ -1,5 +1,8 @@ // run-pass +#![deny(unused_parens)] +#![allow(unreachable_code)] + fn main() { match (return) {} // ok if (return) {} // ok From 518a5a4898799e4b6732ac217f85def83fc462aa Mon Sep 17 00:00:00 2001 From: Aaron Power <theaaronepower@gmail.com> Date: Mon, 17 Sep 2018 17:44:04 +0100 Subject: [PATCH 12/16] Updated RELEASES.md for 1.30.0 --- RELEASES.md | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 9bc750ddef5..b40897a7509 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,124 @@ +Version 1.30.0 (2018-10-25) +========================== + +Language +-------- +- [Procedural macros are now available.][52081] These kinds of macros allow for + more powerful code generation, there is a [new chapter available][proc-macros] + in Rust Programming Language book that goes further in depth. +- [You can now use keywords as identifiers using the raw identifiers + syntax (`r#`).][53236] e.g. `let r#bool = true;` +- [Using anonymous parameters in traits is now deprecated with a warning and + will be a hard error in the 2018 edition.][53272] +- [You can now use `crate` in paths.][54404] This allows you to refer to the + crate root in the path. e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`. +- [Using a external crate now no longer requires being prefixed with `::`.][54404] + e.g. previously using a external crate in a module without a use statement + required `let json = ::serde_json::from_str(foo);` can now be written + as `let json = serde_json::from_str(foo);`. +- [You can now apply the `#[used]` attribute to static items to prevent the + compiler from optimising them away even if they appear to be unused.][51363] + e.g. `#[used] static FOO: u32 = 1;` +- [You can now import and reexport macros from other crates with the `use` + syntax.][50911] Macros exported with `#[macro_export]` are now placed into + the root module of the crate. If your macro relies on calling other local + macros it is recommended to export with the + `#[macro_export(local_inner_macros)]` attribute so that users won't have to + import those macros. +- [`mod.rs` files are now optional.][54146] Previously if you had a `foo` module + with a `bar` submodule, you would have `src/foo/mod.rs` and `src/foo/bar.rs`. + Now you can have `src/foo.rs` and `src/foo/bar.rs` to achieve the same effect. +- [You can now catch visibility keywords (e.g. `pub`, `pub(crate)`) in macros + using the `vis` specifier.][53370] +- [Non-macro attributes now allow all forms of literals not just + strings.][53044] e.g. Previously you would write `#[attr("true")]` you can now + write `#[attr(true)]`. +- [You can now specify a function to handle a panic in the Rust runtime with the + `#[panic_handler]` attribute.][51366] + +Compiler +-------- +- [Added the `riscv32imc-unknown-none-elf` target.][53822] +- [Added the `aarch64-unknown-netbsd` target][53165] + +Libraries +--------- +- [`ManuallyDrop` now allows the inner type to be unsized.][53033] + +Stabilized APIs +--------------- +- [`Ipv4Addr::BROADCAST`] +- [`Ipv4Addr::LOCALHOST`] +- [`Ipv4Addr::UNSPECIFIED`] +- [`Ipv6Addr::LOCALHOST`] +- [`Ipv6Addr::UNSPECIFIED`] +- [`Iterator::find_map`] + + The following methods are a replacement methods for `trim_left`, `trim_right`, + `trim_left_matches`, and `trim_right_matches`. Which will be deprecated + in 1.33.0. +- [`str::trim_end_matches`] +- [`str::trim_end`] +- [`str::trim_start_matches`] +- [`str::trim_start`] + +Cargo +---- +- [`cargo run` doesn't require specifying a package in workspaces.][cargo/5877] +- [`cargo doc` now supports `--message-format=json`.][cargo/5878] This is + equivalent to calling `rustdoc --error-format=json`. +- [You can specify which edition to create a project in cargo + with `cargo new --edition`.][cargo/5984] Currently only `2015` is a + valid option. +- [Cargo will now provide a progress bar for builds.][cargo/5995] + +Misc +---- +- [`rustdoc` allows you to specify what edition to treat your code as with the + `--edition` option.][54057] +- [`rustdoc` now has the `--color` (Specify whether to output color) and + `--error-format` (Specify error format e.g. `json`) options.][53003] +- [We now distribute a `rust-gdbgui` script that invokes `gdbgui` with Rust + debug symbols.][53774] +- [Attributes from Rust tools such as `rustfmt` or `clippy` are now + available.][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item. + +[50911]: https://github.com/rust-lang/rust/pull/50911/ +[51363]: https://github.com/rust-lang/rust/pull/51363/ +[51366]: https://github.com/rust-lang/rust/pull/51366/ +[52081]: https://github.com/rust-lang/rust/pull/52081/ +[53003]: https://github.com/rust-lang/rust/pull/53003/ +[53033]: https://github.com/rust-lang/rust/pull/53033/ +[53044]: https://github.com/rust-lang/rust/pull/53044/ +[53165]: https://github.com/rust-lang/rust/pull/53165/ +[53213]: https://github.com/rust-lang/rust/pull/53213/ +[53236]: https://github.com/rust-lang/rust/pull/53236/ +[53272]: https://github.com/rust-lang/rust/pull/53272/ +[53370]: https://github.com/rust-lang/rust/pull/53370/ +[53459]: https://github.com/rust-lang/rust/pull/53459/ +[53774]: https://github.com/rust-lang/rust/pull/53774/ +[53822]: https://github.com/rust-lang/rust/pull/53822/ +[54057]: https://github.com/rust-lang/rust/pull/54057/ +[54146]: https://github.com/rust-lang/rust/pull/54146/ +[54404]: https://github.com/rust-lang/rust/pull/54404/ +[cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/ +[cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/ +[cargo/5984]: https://github.com/rust-lang/cargo/pull/5984/ +[cargo/5995]: https://github.com/rust-lang/cargo/pull/5995/ +[proc-macros]: https://doc.rust-lang.org/book/2018-edition/ch19-06-macros.html + +[`Ipv4Addr::BROADCAST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.BROADCAST +[`Ipv4Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.LOCALHOST +[`Ipv4Addr::UNSPECIFIED`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.UNSPECIFIED +[`Ipv6Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#associatedconstant.LOCALHOST +[`Ipv6Addr::UNSPECIFIED`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#associatedconstant.UNSPECIFIED +[`Iterator::find_map`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find_map +[`str::trim_end_matches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_end_matches +[`str::trim_end`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_end +[`str::trim_start_matches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_start_matches +[`str::trim_start`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_start + + Version 1.29.2 (2018-10-11) =========================== @@ -6,6 +127,7 @@ Version 1.29.2 (2018-10-11) [54639]: https://github.com/rust-lang/rust/pull/54639 + Version 1.29.1 (2018-09-25) =========================== @@ -19,6 +141,7 @@ Security Notes Thank you to Scott McMurray for responsibily disclosing this vulnerability to us. + Version 1.29.0 (2018-09-13) ========================== @@ -73,7 +196,10 @@ Compatibility Notes Consider using the `home_dir` function from https://crates.io/crates/dirs instead. - [`rustc` will no longer silently ignore invalid data in target spec.][52330] +- [`cfg` attributes and `--cfg` command line flags are now more + strictly validated.][53893] +[53893]: https://github.com/rust-lang/rust/pull/53893/ [52861]: https://github.com/rust-lang/rust/pull/52861/ [52656]: https://github.com/rust-lang/rust/pull/52656/ [52239]: https://github.com/rust-lang/rust/pull/52239/ From f08db6bf1ee44dd1bc8c4d3ddcea1425fcd8d118 Mon Sep 17 00:00:00 2001 From: Raph Levien <raph.levien@gmail.com> Date: Thu, 18 Oct 2018 08:35:09 -0700 Subject: [PATCH 13/16] Add must_use on copysign Added a #[must_use] annotation on copysign, per review feedback. --- src/libstd/f32.rs | 1 + src/libstd/f64.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 369745d8189..c3f225d1eb0 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -221,6 +221,7 @@ impl f32 { /// assert!(f32::NAN.copysign(1.0).is_nan()); /// ``` #[inline] + #[must_use] #[unstable(feature="copysign", issue="55169")] pub fn copysign(self, y: f32) -> f32 { unsafe { intrinsics::copysignf32(self, y) } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index df23d62ecfd..da062dda77a 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -199,6 +199,7 @@ impl f64 { /// assert!(f64::NAN.copysign(1.0).is_nan()); /// ``` #[inline] + #[must_use] #[unstable(feature="copysign", issue="55169")] pub fn copysign(self, y: f64) -> f64 { unsafe { intrinsics::copysignf64(self, y) } From b08ca2958e1b92c67c3ac0e76455f51742b95d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com> Date: Thu, 18 Oct 2018 10:22:34 +0300 Subject: [PATCH 14/16] Stabilize slice::chunks_exact() and slice::chunks_exact_mut() Fixes #47115 --- src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 2 +- src/liballoc/tests/lib.rs | 1 - src/libcore/slice/mod.rs | 38 +++++++++++++++++--------------------- src/libcore/tests/lib.rs | 1 - 5 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0cad471d9a1..540a17774e5 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -115,7 +115,6 @@ #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] -#![feature(chunks_exact)] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 2628757b503..8ffc043d816 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -123,7 +123,7 @@ pub use core::slice::{from_raw_parts, from_raw_parts_mut}; pub use core::slice::{from_ref, from_mut}; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; #[unstable(feature = "rchunks", issue = "55177")] pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut}; diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 62c84c9e086..5a21976d75d 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -19,7 +19,6 @@ #![feature(str_escape)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(chunks_exact)] #![feature(rchunks)] #![feature(repeat_generic_slice)] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 62f60034352..628d5542ac0 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -713,8 +713,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(chunks_exact)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.chunks_exact(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); @@ -725,7 +723,7 @@ impl<T> [T] { /// /// [`chunks`]: #method.chunks /// [`rchunks_exact`]: #method.rchunks_exact - #[unstable(feature = "chunks_exact", issue = "47115")] + #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<T> { assert!(chunk_size != 0); @@ -756,8 +754,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(chunks_exact)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -772,7 +768,7 @@ impl<T> [T] { /// /// [`chunks_mut`]: #method.chunks_mut /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut - #[unstable(feature = "chunks_exact", issue = "47115")] + #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<T> { assert!(chunk_size != 0); @@ -4022,25 +4018,25 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { /// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExact<'a, T:'a> { v: &'a [T], rem: &'a [T], chunk_size: usize } -#[unstable(feature = "chunks_exact", issue = "47115")] impl<'a, T> ChunksExact<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] pub fn remainder(&self) -> &'a [T] { self.rem } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<T> Clone for ChunksExact<'_, T> { fn clone(&self) -> Self { ChunksExact { @@ -4051,7 +4047,7 @@ impl<T> Clone for ChunksExact<'_, T> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> Iterator for ChunksExact<'a, T> { type Item = &'a [T]; @@ -4096,7 +4092,7 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4110,7 +4106,7 @@ impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<T> ExactSizeIterator for ChunksExact<'_, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4120,11 +4116,11 @@ impl<T> ExactSizeIterator for ChunksExact<'_, T> { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<T> TrustedLen for ChunksExact<'_, T> {} -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<T> FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let start = i * self.chunk_size; @@ -4146,24 +4142,24 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { /// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExactMut<'a, T:'a> { v: &'a mut [T], rem: &'a mut [T], chunk_size: usize } -#[unstable(feature = "chunks_exact", issue = "47115")] impl<'a, T> ChunksExactMut<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> Iterator for ChunksExactMut<'a, T> { type Item = &'a mut [T]; @@ -4210,7 +4206,7 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4226,7 +4222,7 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<T> ExactSizeIterator for ChunksExactMut<'_, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4236,11 +4232,11 @@ impl<T> ExactSizeIterator for ChunksExactMut<'_, T> { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {} -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<T> FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let start = i * self.chunk_size; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e889d484353..affcdbea9d3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -34,7 +34,6 @@ #![feature(trusted_len)] #![feature(try_from)] #![feature(try_trait)] -#![feature(chunks_exact)] #![feature(rchunks)] #![feature(align_offset)] #![feature(reverse_bits)] From 52cc6fde4b73a3013ce2185052f9492ae3728367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com> Date: Thu, 18 Oct 2018 18:48:02 +0300 Subject: [PATCH 15/16] Stabilize slice::rchunks(), rchunks_mut(), rchunks_exact(), rchunk_exact_mut() Fixes #55177 --- src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 2 +- src/liballoc/tests/lib.rs | 1 - src/libcore/slice/mod.rs | 72 +++++++++++++++++---------------------- src/libcore/tests/lib.rs | 1 - 5 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 540a17774e5..84ca7c4fec9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -119,7 +119,6 @@ #![feature(const_vec_new)] #![feature(slice_partition_dedup)] #![feature(maybe_uninit)] -#![feature(rchunks)] // Allow testing this library diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 8ffc043d816..1eaff7410ea 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -125,7 +125,7 @@ pub use core::slice::{from_ref, from_mut}; pub use core::slice::SliceIndex; #[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut}; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 5a21976d75d..6d1cfb10859 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -19,7 +19,6 @@ #![feature(str_escape)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(rchunks)] #![feature(repeat_generic_slice)] extern crate alloc_system; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 628d5542ac0..8a6b212020b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -795,8 +795,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.rchunks(2); /// assert_eq!(iter.next().unwrap(), &['e', 'm']); @@ -807,7 +805,7 @@ impl<T> [T] { /// /// [`rchunks_exact`]: #method.rchunks_exact /// [`chunks`]: #method.chunks - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks<T> { assert!(chunk_size != 0); @@ -831,8 +829,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -847,7 +843,7 @@ impl<T> [T] { /// /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut /// [`chunks_mut`]: #method.chunks_mut - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<T> { assert!(chunk_size != 0); @@ -875,8 +871,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.rchunks_exact(2); /// assert_eq!(iter.next().unwrap(), &['e', 'm']); @@ -887,7 +881,7 @@ impl<T> [T] { /// /// [`rchunks`]: #method.rchunks /// [`chunks_exact`]: #method.chunks_exact - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<T> { assert!(chunk_size != 0); @@ -917,8 +911,6 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -933,7 +925,7 @@ impl<T> [T] { /// /// [`rchunks_mut`]: #method.rchunks_mut /// [`chunks_exact_mut`]: #method.chunks_exact_mut - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<T> { assert!(chunk_size != 0); @@ -4256,14 +4248,14 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { /// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunks<'a, T:'a> { v: &'a [T], chunk_size: usize } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Clone for RChunks<'a, T> { fn clone(&self) -> RChunks<'a, T> { RChunks { @@ -4273,7 +4265,7 @@ impl<'a, T> Clone for RChunks<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunks<'a, T> { type Item = &'a [T]; @@ -4337,7 +4329,7 @@ impl<'a, T> Iterator for RChunks<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4353,17 +4345,17 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunks<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunks<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunks<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let end = self.v.len() - i * self.chunk_size; @@ -4387,13 +4379,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { /// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksMut<'a, T:'a> { v: &'a mut [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksMut<'a, T> { type Item = &'a mut [T]; @@ -4461,7 +4453,7 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4478,17 +4470,17 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksMut<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksMut<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let end = self.v.len() - i * self.chunk_size; @@ -4514,25 +4506,25 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { /// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExact<'a, T:'a> { v: &'a [T], rem: &'a [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] impl<'a, T> RChunksExact<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] pub fn remainder(&self) -> &'a [T] { self.rem } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Clone for RChunksExact<'a, T> { fn clone(&self) -> RChunksExact<'a, T> { RChunksExact { @@ -4543,7 +4535,7 @@ impl<'a, T> Clone for RChunksExact<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksExact<'a, T> { type Item = &'a [T]; @@ -4588,7 +4580,7 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4602,7 +4594,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4612,11 +4604,11 @@ impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksExact<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksExact<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let end = self.v.len() - i * self.chunk_size; @@ -4639,24 +4631,24 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { /// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExactMut<'a, T:'a> { v: &'a mut [T], rem: &'a mut [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] impl<'a, T> RChunksExactMut<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksExactMut<'a, T> { type Item = &'a mut [T]; @@ -4705,7 +4697,7 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4720,7 +4712,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksExactMut<'a, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4730,11 +4722,11 @@ impl<'a, T> ExactSizeIterator for RChunksExactMut<'a, T> { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksExactMut<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksExactMut<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let end = self.v.len() - i * self.chunk_size; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index affcdbea9d3..965bd545eed 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -34,7 +34,6 @@ #![feature(trusted_len)] #![feature(try_from)] #![feature(try_trait)] -#![feature(rchunks)] #![feature(align_offset)] #![feature(reverse_bits)] #![feature(inner_deref)] From ef1a40d5fec8678c4ae51cf2dcbed96934182b8c Mon Sep 17 00:00:00 2001 From: Matthew Jasper <mjjasper1@gmail.com> Date: Fri, 12 Oct 2018 15:16:29 +0100 Subject: [PATCH 16/16] Propagate bounds from generators --- .../borrow_check/nll/region_infer/mod.rs | 12 ++++------- .../borrow_check/nll/type_check/mod.rs | 15 ++++++------- .../borrow_check/nll/universal_regions.rs | 4 ++-- .../generator-region-requirements.ast.stderr | 12 +++++++++++ .../generator-region-requirements.nll.stderr | 12 +++++++++++ .../generator-region-requirements.rs | 21 +++++++++++++++++++ 6 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/generator/generator-region-requirements.ast.stderr create mode 100644 src/test/ui/generator/generator-region-requirements.nll.stderr create mode 100644 src/test/ui/generator/generator-region-requirements.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index dd8a7f19a63..0fabcfe4564 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1268,7 +1268,7 @@ pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> { tcx: TyCtxt<'_, 'gcx, 'tcx>, location: Location, closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>, + closure_substs: &'tcx ty::subst::Substs<'tcx>, ) -> Vec<QueryRegionConstraint<'tcx>>; fn subst_closure_mapping<T>( @@ -1299,23 +1299,19 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi tcx: TyCtxt<'_, 'gcx, 'tcx>, location: Location, closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>, + closure_substs: &'tcx ty::subst::Substs<'tcx>, ) -> Vec<QueryRegionConstraint<'tcx>> { debug!( "apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})", location, closure_def_id, closure_substs ); - // Get Tu. - let user_closure_ty = tcx.mk_closure(closure_def_id, closure_substs); - debug!("apply_requirements: user_closure_ty={:?}", user_closure_ty); - - // Extract the values of the free regions in `user_closure_ty` + // Extract the values of the free regions in `closure_substs` // into a vector. These are the regions that we will be // relating to one another. let closure_mapping = &UniversalRegions::closure_mapping( tcx, - user_closure_ty, + closure_substs, self.num_external_vids, tcx.closure_base_def_id(closure_def_id), ); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 1e79bc272e4..c5758cde949 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, UnpackedKind}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -2075,12 +2075,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, substs) => { - self.prove_closure_bounds(tcx, *def_id, *substs, location) - } - - AggregateKind::Generator(def_id, substs, _) => { - tcx.predicates_of(*def_id).instantiate(tcx, substs.substs) + AggregateKind::Closure(def_id, ty::ClosureSubsts { substs }) + | AggregateKind::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + self.prove_closure_bounds(tcx, *def_id, substs, location) } AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), @@ -2096,7 +2093,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, + substs: &'tcx Substs<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { if let Some(closure_region_requirements) = @@ -2155,7 +2152,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } - tcx.predicates_of(def_id).instantiate(tcx, substs.substs) + tcx.predicates_of(def_id).instantiate(tcx, substs) } fn prove_trait_ref( diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index eb6f1a0677b..c54a4f96b7d 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -232,13 +232,13 @@ impl<'tcx> UniversalRegions<'tcx> { /// `V[1]: V[2]`. pub fn closure_mapping( tcx: TyCtxt<'_, '_, 'tcx>, - closure_ty: Ty<'tcx>, + closure_substs: &'tcx Substs<'tcx>, expected_num_vars: usize, closure_base_def_id: DefId, ) -> IndexVec<RegionVid, ty::Region<'tcx>> { let mut region_mapping = IndexVec::with_capacity(expected_num_vars); region_mapping.push(tcx.types.re_static); - tcx.for_each_free_region(&closure_ty, |fr| { + tcx.for_each_free_region(&closure_substs, |fr| { region_mapping.push(fr); }); diff --git a/src/test/ui/generator/generator-region-requirements.ast.stderr b/src/test/ui/generator/generator-region-requirements.ast.stderr new file mode 100644 index 00000000000..6a423aea7ec --- /dev/null +++ b/src/test/ui/generator/generator-region-requirements.ast.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/generator-region-requirements.rs:15:51 + | +LL | fn dangle(x: &mut i32) -> &'static mut i32 { + | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` +... +LL | GeneratorState::Complete(c) => return c, + | ^ lifetime `'static` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generator/generator-region-requirements.nll.stderr b/src/test/ui/generator/generator-region-requirements.nll.stderr new file mode 100644 index 00000000000..5d1050dc352 --- /dev/null +++ b/src/test/ui/generator/generator-region-requirements.nll.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/generator-region-requirements.rs:11:9 + | +LL | fn dangle(x: &mut i32) -> &'static mut i32 { + | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` +... +LL | x + | ^ lifetime `'static` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generator/generator-region-requirements.rs b/src/test/ui/generator/generator-region-requirements.rs new file mode 100644 index 00000000000..59e7841309c --- /dev/null +++ b/src/test/ui/generator/generator-region-requirements.rs @@ -0,0 +1,21 @@ +// revisions: ast nll +// ignore-compare-mode-nll + +#![feature(generators, generator_trait)] +#![cfg_attr(nll, feature(nll))] +use std::ops::{Generator, GeneratorState}; + +fn dangle(x: &mut i32) -> &'static mut i32 { + let mut g = || { + yield; + x + }; + loop { + match unsafe { g.resume() } { + GeneratorState::Complete(c) => return c, + GeneratorState::Yielded(_) => (), + } + } +} + +fn main() {}