From 74bf59ea037e114fc2d586967601faba9fff64f4 Mon Sep 17 00:00:00 2001 From: Lucas Lois Date: Tue, 2 Oct 2018 13:31:40 -0300 Subject: [PATCH 01/21] Documents reference equality by address (#54197) Clarification of the use of `ptr::eq` to test equality of references via address by pointer coercion --- src/libstd/primitive_docs.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 8d54728a75f42..11195bb9a2abd 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -908,11 +908,36 @@ mod prim_usize { } /// `&mut T` references can be freely coerced into `&T` references with the same referent type, and /// references with longer lifetimes can be freely coerced into references with shorter ones. /// +/// Reference equality by address, instead of comparing the values pointed to, is accomplished via +/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while +/// [`PartialEq`] compares values. +/// +/// [`ptr::eq`]: ptr/fn.eq.html +/// [`PartialEq`]: cmp/trait.PartialEq.html +/// +/// ``` +/// use std::ptr; +/// +/// let five = 5; +/// let other_five = 5; +/// let five_ref = &five; +/// let same_five_ref = &five; +/// let other_five_ref = &other_five; +/// +/// assert!(five_ref == same_five_ref); +/// assert!(five_ref == other_five_ref); +/// +/// assert!(ptr::eq(five_ref, same_five_ref)); +/// assert!(!ptr::eq(five_ref, other_five_ref)); +/// ``` +/// /// For more information on how to use references, see [the book's section on "References and /// Borrowing"][book-refs]. /// /// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html /// +/// # Trait implementations +/// /// The following traits are implemented for all `&T`, regardless of the type of its referent: /// /// * [`Copy`] From 68236e088d8b5694eb4097c1ad8302b92e36fd4a Mon Sep 17 00:00:00 2001 From: Lucas Lois Date: Tue, 2 Oct 2018 13:59:33 -0300 Subject: [PATCH 02/21] Cleans trailing whitespace --- src/libstd/primitive_docs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 11195bb9a2abd..3b432d0513209 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -909,12 +909,12 @@ mod prim_usize { } /// references with longer lifetimes can be freely coerced into references with shorter ones. /// /// Reference equality by address, instead of comparing the values pointed to, is accomplished via -/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while +/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while /// [`PartialEq`] compares values. -/// +/// /// [`ptr::eq`]: ptr/fn.eq.html /// [`PartialEq`]: cmp/trait.PartialEq.html -/// +/// /// ``` /// use std::ptr; /// @@ -930,14 +930,14 @@ mod prim_usize { } /// assert!(ptr::eq(five_ref, same_five_ref)); /// assert!(!ptr::eq(five_ref, other_five_ref)); /// ``` -/// +/// /// For more information on how to use references, see [the book's section on "References and /// Borrowing"][book-refs]. /// /// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html /// /// # Trait implementations -/// +/// /// The following traits are implemented for all `&T`, regardless of the type of its referent: /// /// * [`Copy`] From ac4945c1cbdee5800a53c7afe180b290291cefe1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 4 Oct 2018 12:39:37 +0200 Subject: [PATCH 03/21] Fix #24840: make default for `optimize` independent of `debug` setting in `Cargo.toml`. --- src/bootstrap/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 3a4bc526d03bf..3250594e4f443 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -624,6 +624,9 @@ impl Config { let default = false; config.llvm_assertions = llvm_assertions.unwrap_or(default); + let default = true; + config.rust_optimize = optimize.unwrap_or(default); + let default = match &config.channel[..] { "stable" | "beta" | "nightly" => true, _ => false, @@ -636,7 +639,6 @@ impl Config { config.debug_jemalloc = debug_jemalloc.unwrap_or(default); config.rust_debuginfo = debuginfo.unwrap_or(default); config.rust_debug_assertions = debug_assertions.unwrap_or(default); - config.rust_optimize = optimize.unwrap_or(!default); let default = config.channel == "dev"; config.ignore_git = ignore_git.unwrap_or(default); From 82444aa753180c9c13028066ae9ddc4933dc610d Mon Sep 17 00:00:00 2001 From: mandeep Date: Fri, 5 Oct 2018 18:22:19 -0400 Subject: [PATCH 04/21] Add doc comments about safest way to initialize a vector of zeros --- src/liballoc/vec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2bc037e3fee12..3188de512662c 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -120,7 +120,9 @@ use raw_vec::RawVec; /// assert_eq!(vec, [1, 2, 3, 4]); /// ``` /// -/// It can also initialize each element of a `Vec` with a given value: +/// It can also initialize each element of a `Vec` with a given value. +/// Initializing a `Vec` in this manner is the most efficient and safest way to allocate a +/// vector of zeros as previously zeroed memory is requested from the operating system: /// /// ``` /// let vec = vec![0; 5]; From c802e1348ebfd4a250562ed9255c7e74eb83e8fd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Oct 2018 18:48:31 +0200 Subject: [PATCH 05/21] Update minifier version --- src/Cargo.lock | 8 ++++---- src/librustdoc/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 5a44b696a03e1..ad4132559f741 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1255,7 +1255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.19" +version = "0.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2450,7 +2450,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3032,7 +3032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3234,7 +3234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11" +"checksum minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "96c269bb45c39b333392b2b18ad71760b34ac65666591386b0e959ed58b3f474" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 845bfad7807d3..8bac007b748ac 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,6 +9,6 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.1.2", default-features = false } -minifier = "0.0.19" +minifier = "0.0.20" tempfile = "3" parking_lot = "0.6.4" From ded0bf5f9b38b5b07560c2cdecfeb41b9cc3bda9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Oct 2018 18:51:56 +0200 Subject: [PATCH 06/21] Fix mobile doc display --- src/librustdoc/html/render.rs | 5 ++-- src/librustdoc/html/static/rustdoc.css | 37 +++++++++++++++++--------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1c61e73fae03c..23f1e15de3c92 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4098,12 +4098,13 @@ impl<'a> fmt::Display for Sidebar<'a> { ", version)?; } + } + write!(fmt, "
")?; + if it.is_crate() { write!(fmt, "

See all {}'s items

", it.name.as_ref().expect("crates always have a name"))?; } - - write!(fmt, "
")?; match it.inner { clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?, clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?, diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index ee811f3379239..c9e27dba479ad 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -909,10 +909,9 @@ span.since { padding-top: 0px; } - .sidebar { + body > .sidebar { height: 45px; min-height: 40px; - width: calc(100% + 30px); margin: 0; margin-left: -15px; padding: 0 15px; @@ -1014,6 +1013,10 @@ span.since { .anchor { display: none !important; } + + h1.fqn { + overflow: initial; + } } @media print { @@ -1113,6 +1116,18 @@ h4 > .important-traits { top: 2px; } +#all-types { + text-align: center; + border: 1px solid; + margin: 0 10px; + margin-bottom: 10px; + display: block; + border-radius: 7px; +} +#all-types > p { + margin: 5px 0; +} + @media (max-width: 700px) { h4 > .important-traits { position: absolute; @@ -1136,6 +1151,9 @@ h4 > .important-traits { background-color: rgba(0,0,0,0); height: 100%; } + .sidebar { + width: calc(100% + 30px); + } .show-it { display: block; @@ -1181,6 +1199,10 @@ h4 > .important-traits { .impl > .collapse-toggle { left: -10px; } + + #all-types { + margin: 10px; + } } @@ -1384,17 +1406,6 @@ kbd { #main > ul > li { list-style: none; } -#all-types { - text-align: center; - border: 1px solid; - margin: 0 10px; - margin-bottom: 10px; - display: block; - border-radius: 7px; -} -#all-types > p { - margin: 5px 0; -} .non-exhaustive { margin-bottom: 1em; From 9a9894a8f1f0dbf1acb35947081bbd299fc44968 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 7 Oct 2018 12:00:41 +0200 Subject: [PATCH 07/21] Fix tracking issue for Once::is_completed --- src/libstd/sync/once.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 17cb614ba11ff..98845e457b25c 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -329,7 +329,7 @@ impl Once { /// assert!(handle.join().is_err()); /// assert_eq!(INIT.is_completed(), false); /// ``` - #[unstable(feature = "once_is_completed", issue = "42")] + #[unstable(feature = "once_is_completed", issue = "54890")] #[inline] pub fn is_completed(&self) -> bool { // An `Acquire` load is enough because that makes all the initialization From b7248d5988ae4a4498fd900482142151e3ddddd2 Mon Sep 17 00:00:00 2001 From: Donato Sciarra Date: Sun, 7 Oct 2018 00:05:42 +0200 Subject: [PATCH 08/21] Fix internal compiler error on malformed match arm pattern. Issue: 54379 --- src/libsyntax/parse/parser.rs | 3 +++ src/test/ui/resolve/issue-54379.rs | 21 +++++++++++++++++++++ src/test/ui/resolve/issue-54379.stderr | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/test/ui/resolve/issue-54379.rs create mode 100644 src/test/ui/resolve/issue-54379.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d653ed819fddd..03decd584514d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3866,6 +3866,9 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { let err = self.struct_span_err(self.prev_span, "expected `,`"); + if let Some(mut delayed) = delayed_err { + delayed.emit(); + } return Err(err); } ate_comma = false; diff --git a/src/test/ui/resolve/issue-54379.rs b/src/test/ui/resolve/issue-54379.rs new file mode 100644 index 0000000000000..24aa758ea6c23 --- /dev/null +++ b/src/test/ui/resolve/issue-54379.rs @@ -0,0 +1,21 @@ +// 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. +struct MyStruct { + pub s1: Option, +} + +fn main() { + let thing = MyStruct { s1: None }; + + match thing { + MyStruct { .., Some(_) } => {}, + _ => {} + } +} diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr new file mode 100644 index 0000000000000..d1d693a3817b9 --- /dev/null +++ b/src/test/ui/resolve/issue-54379.stderr @@ -0,0 +1,24 @@ +error: expected `}`, found `,` + --> $DIR/issue-54379.rs:18:22 + | +LL | MyStruct { .., Some(_) } => {}, + | --^ + | | | + | | expected `}` + | `..` must be at the end and cannot have a trailing comma + +error: expected `,` + --> $DIR/issue-54379.rs:18:24 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^ + +error[E0027]: pattern does not mention field `s1` + --> $DIR/issue-54379.rs:18:9 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0027`. From 91b71f5e9416b570b3e4c1997056c3879e5029af Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 17:05:33 +0200 Subject: [PATCH 09/21] Identify borrows captured by trait objects. This commit enhances `LaterUseKind` detection to identify when a borrow is captured by a trait object which helps explain why there is a borrow error. --- .../borrow_check/nll/explain_borrow/mod.rs | 173 ++++++++++++++---- ...ons-close-over-type-parameter-2.nll.stderr | 2 +- 2 files changed, 137 insertions(+), 38 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index e55469436abf0..74bbdebe7a3ad 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -13,8 +13,10 @@ use borrow_check::error_reporting::UseSpans; use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, Region, TyCtxt}; -use rustc::mir::{FakeReadCause, Local, Location, Mir, Operand}; -use rustc::mir::{Place, StatementKind, TerminatorKind}; +use rustc::mir::{ + FakeReadCause, Local, Location, Mir, Operand, Place, Rvalue, Statement, StatementKind, + TerminatorKind +}; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -34,6 +36,7 @@ pub(in borrow_check) enum BorrowExplanation<'tcx> { #[derive(Clone, Copy)] pub(in borrow_check) enum LaterUseKind { + TraitCapture, ClosureCapture, Call, FakeLetRead, @@ -51,6 +54,7 @@ impl<'tcx> BorrowExplanation<'tcx> { match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { let message = match later_use_kind { + LaterUseKind::TraitCapture => "borrow later captured here by trait object", LaterUseKind::ClosureCapture => "borrow later captured here by closure", LaterUseKind::Call => "borrow later used by call", LaterUseKind::FakeLetRead => "borrow later stored here", @@ -60,9 +64,10 @@ impl<'tcx> BorrowExplanation<'tcx> { }, BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - }, + LaterUseKind::TraitCapture => + "borrow later captured here by trait object, in later iteration of loop", + LaterUseKind::ClosureCapture => + "borrow captured here by closure, in later iteration of loop", LaterUseKind::Call => "borrow used by call, in later iteration of loop", LaterUseKind::FakeLetRead => "borrow later stored here", LaterUseKind::Other => "borrow used here, in later iteration of loop", @@ -200,13 +205,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if self.is_borrow_location_in_loop(context.loc) { - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLater(later_use.0, later_use.1) } } @@ -316,42 +321,136 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { false } - fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) { - use self::LaterUseKind::*; - - let block = &self.mir.basic_blocks()[location.block]; + /// Determine how the borrow was later used. + fn later_use_kind( + &self, + borrow: &BorrowData<'tcx>, + use_spans: UseSpans, + location: Location + ) -> (LaterUseKind, Span) { match use_spans { - UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span), + UseSpans::ClosureUse { var_span, .. } => { + // Used in a closure. + (LaterUseKind::ClosureCapture, var_span) + }, UseSpans::OtherUse(span) => { - (if let Some(stmt) = block.statements.get(location.statement_index) { - match stmt.kind { - StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead, - _ => Other, + let block = &self.mir.basic_blocks()[location.block]; + + let kind = if let Some(&Statement { + kind: StatementKind::FakeRead(FakeReadCause::ForLet, _), + .. + }) = block.statements.get(location.statement_index) { + LaterUseKind::FakeLetRead + } else if self.was_captured_by_trait_object(borrow) { + LaterUseKind::TraitCapture + } else if location.statement_index == block.statements.len() { + if let TerminatorKind::Call { + ref func, from_hir_call: true, .. + } = block.terminator().kind { + // Just point to the function, to reduce the chance of overlapping spans. + let function_span = match func { + Operand::Constant(c) => c.span, + Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { + let local_decl = &self.mir.local_decls[*l]; + if local_decl.name.is_none() { + local_decl.source_info.span + } else { + span + } + }, + _ => span, + }; + return (LaterUseKind::Call, function_span); + } else { + LaterUseKind::Other } } else { - assert_eq!(location.statement_index, block.statements.len()); - match block.terminator().kind { - TerminatorKind::Call { ref func, from_hir_call: true, .. } => { - // Just point to the function, to reduce the chance - // of overlapping spans. - let function_span = match func { - Operand::Constant(c) => c.span, - Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { - let local_decl = &self.mir.local_decls[*l]; - if local_decl.name.is_none() { - local_decl.source_info.span - } else { - span - } - }, - _ => span, - }; - return (Call, function_span); - }, - _ => Other, + LaterUseKind::Other + }; + + (kind, span) + } + } + } + + /// Check if a borrowed value was captured by a trait object. + fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { + // In order to check if a value was captured by a trait object, we want to look through + // statements after the reserve location in the current block. We expect the reserve + // location to be a statement assigning to a local. We follow that local in the subsequent + // statements, checking for an assignment of our local (or something intermediate that + // it was assigned into) that results in a trait object. + let location = borrow.reserve_location; + let block = &self.mir[location.block]; + let stmt = block.statements.get(location.statement_index); + debug!( + "was_captured_by_trait_object: location={:?} block={:?} stmt={:?}", + location, block, stmt + ); + let mut target = if let Some(&Statement { + kind: StatementKind::Assign(Place::Local(local), _), + .. + }) = stmt { + local + } else { + return false; + }; + + debug!("was_captured_by_trait_object: target={:?}", target); + for stmt in &block.statements[location.statement_index + 1..] { + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + // Simple case where our target is assigned into another local, and we start + // watching that local instead. + if let StatementKind::Assign( + Place::Local(into), + box Rvalue::Use(operand), + ) = &stmt.kind { + debug!("was_captured_by_trait_object: target={:?} operand={:?}", target, operand); + match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => target = *into, + _ => {}, + } + } + } + + if let Some(terminator) = &block.terminator { + if let TerminatorKind::Call { + destination: Some((Place::Local(dest), _)), + args, + .. + } = &terminator.kind { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + let mut found_target = false; + for arg in args { + if let Operand::Move(Place::Local(potential)) = arg { + if *potential == target { + found_target = true; + } + } + } + + if found_target { + let local_decl_ty = &self.mir.local_decls[*dest].ty; + debug!("was_captured_by_trait_object: local_decl_ty={:?}", local_decl_ty); + match local_decl_ty.sty { + // `&dyn Trait` + ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, + // `Box` + _ if local_decl_ty.is_box() && local_decl_ty.boxed_ty().is_trait() => + return true, + // `dyn Trait` + _ if local_decl_ty.is_trait() => return true, + // Anything else. + _ => return false, } - }, span) + } } } + + false } } diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr index f8e5e3914eb3c..11fa447b5489a 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr +++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr @@ -4,7 +4,7 @@ error[E0597]: `tmp0` does not live long enough LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) - | --------------- borrow later used here + | --------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed From 72911fbbd051c1824f00735ac1b57017ca709a87 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 23:31:33 +0200 Subject: [PATCH 10/21] Update logic to search for casts. This commit updates the captured trait object search logic to look for unsized casts to boxed types rather than for functions that returned trait objects. --- .../borrow_check/nll/explain_borrow/mod.rs | 170 +++++++++++------- src/test/ui/nll/issue-52663-trait-object.rs | 27 +++ .../ui/nll/issue-52663-trait-object.stderr | 13 ++ 3 files changed, 149 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/nll/issue-52663-trait-object.rs create mode 100644 src/test/ui/nll/issue-52663-trait-object.stderr diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 74bbdebe7a3ad..307112f8ba16a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -14,8 +14,8 @@ use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, Region, TyCtxt}; use rustc::mir::{ - FakeReadCause, Local, Location, Mir, Operand, Place, Rvalue, Statement, StatementKind, - TerminatorKind + CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem, + Rvalue, Statement, StatementKind, TerminatorKind }; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -65,7 +65,7 @@ impl<'tcx> BorrowExplanation<'tcx> { BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => - "borrow later captured here by trait object, in later iteration of loop", + "borrow captured here by trait object, in later iteration of loop", LaterUseKind::ClosureCapture => "borrow captured here by closure, in later iteration of loop", LaterUseKind::Call => "borrow used by call, in later iteration of loop", @@ -373,20 +373,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - /// Check if a borrowed value was captured by a trait object. + /// Check if a borrowed value was captured by a trait object. We do this by + /// looking forward in the MIR from the reserve location and checking if we see + /// a unsized cast to a trait object on our data. fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { - // In order to check if a value was captured by a trait object, we want to look through - // statements after the reserve location in the current block. We expect the reserve - // location to be a statement assigning to a local. We follow that local in the subsequent - // statements, checking for an assignment of our local (or something intermediate that - // it was assigned into) that results in a trait object. + // Start at the reserve location, find the place that we want to see cast to a trait object. let location = borrow.reserve_location; let block = &self.mir[location.block]; let stmt = block.statements.get(location.statement_index); - debug!( - "was_captured_by_trait_object: location={:?} block={:?} stmt={:?}", - location, block, stmt - ); + debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); + + // We make a `queue` vector that has the locations we want to visit. As of writing, this + // will only ever have one item at any given time, but by using a vector, we can pop from + // it which simplifies the termination logic. + let mut queue = vec![location]; let mut target = if let Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. @@ -396,61 +396,109 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return false; }; - debug!("was_captured_by_trait_object: target={:?}", target); - for stmt in &block.statements[location.statement_index + 1..] { - debug!("was_captured_by_trait_object: stmt={:?}", stmt); - // Simple case where our target is assigned into another local, and we start - // watching that local instead. - if let StatementKind::Assign( - Place::Local(into), - box Rvalue::Use(operand), - ) = &stmt.kind { - debug!("was_captured_by_trait_object: target={:?} operand={:?}", target, operand); - match operand { - Operand::Copy(Place::Local(from)) | - Operand::Move(Place::Local(from)) if *from == target => target = *into, - _ => {}, - } - } - } - - if let Some(terminator) = &block.terminator { - if let TerminatorKind::Call { - destination: Some((Place::Local(dest), _)), - args, - .. - } = &terminator.kind { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - let mut found_target = false; - for arg in args { - if let Operand::Move(Place::Local(potential)) = arg { - if *potential == target { - found_target = true; - } + debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); + while let Some(current_location) = queue.pop() { + debug!("was_captured_by_trait: target={:?}", target); + let block = &self.mir[current_location.block]; + // We need to check the current location to find out if it is a terminator. + let is_terminator = current_location.statement_index == block.statements.len(); + if !is_terminator { + let stmt = &block.statements[current_location.statement_index]; + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + + // The only kind of statement that we care about is assignments... + if let StatementKind::Assign( + place, + box rvalue, + ) = &stmt.kind { + let into = match place { + Place::Local(into) => into, + Place::Projection(box Projection { + base: Place::Local(into), + elem: ProjectionElem::Deref, + }) => into, + _ => { + // Continue at the next location. + queue.push(current_location.successor_within_block()); + continue; + }, + }; + + match rvalue { + // If we see a use, we should check whether it is our data, and if so + // update the place that we're looking for to that new place. + Rvalue::Use(operand) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + target = *into; + }, + _ => {}, + }, + // If we see a unsized cast, then if it is our data we should check + // whether it is being cast to a trait object. + Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + match ty.sty { + // `&dyn Trait` + ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => + return true, + // `dyn Trait` + _ if ty.is_trait() => return true, + // Anything else. + _ => return false, + } + }, + _ => return false, + }, + _ => {}, } } - if found_target { - let local_decl_ty = &self.mir.local_decls[*dest].ty; - debug!("was_captured_by_trait_object: local_decl_ty={:?}", local_decl_ty); - match local_decl_ty.sty { - // `&dyn Trait` - ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, - // `Box` - _ if local_decl_ty.is_box() && local_decl_ty.boxed_ty().is_trait() => - return true, - // `dyn Trait` - _ if local_decl_ty.is_trait() => return true, - // Anything else. - _ => return false, - } + // Continue at the next location. + queue.push(current_location.successor_within_block()); + } else { + // The only thing we need to do for terminators is progress to the next block. + let terminator = block.terminator(); + debug!("was_captured_by_trait_object: terminator={:?}", terminator); + + match &terminator.kind { + TerminatorKind::Call { + destination: Some((Place::Local(dest), block)), + args, + .. + } => { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(Place::Local(potential)) = arg { + *potential == target + } else { + false + } + }); + + // If it is, follow this to the next block and update the target. + if found_target { + target = *dest; + queue.push(block.start_location()); + } + }, + _ => {}, } } + + debug!("was_captured_by_trait: queue={:?}", queue); } + // We didn't find anything and ran out of locations to check. false } } diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs new file mode 100644 index 0000000000000..65d73eeae67c4 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.rs @@ -0,0 +1,27 @@ +// 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(box_syntax)] +#![feature(nll)] + +trait Foo { fn get(&self); } + +impl Foo for A { + fn get(&self) { } +} + +fn main() { + let _ = { + let tmp0 = 3; + let tmp1 = &tmp0; + box tmp1 as Box + }; + //~^^^ ERROR `tmp0` does not live long enough +} diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr new file mode 100644 index 0000000000000..035422f245825 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.stderr @@ -0,0 +1,13 @@ +error[E0597]: `tmp0` does not live long enough + --> $DIR/issue-52663-trait-object.rs:23:20 + | +LL | let tmp1 = &tmp0; + | ^^^^^ borrowed value does not live long enough +LL | box tmp1 as Box + | ------------------------- borrow later captured here by trait object +LL | }; + | - `tmp0` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 8c01c225ce1fd2b28817f6ea72d29e218f0f8a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 8 Oct 2018 10:06:45 +0200 Subject: [PATCH 11/21] Stabilize the `Option::replace` method --- src/libcore/option.rs | 4 +--- src/libcore/tests/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0255f7a0885ea..ee313cd6e8e97 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -867,8 +867,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_replace)] - /// /// let mut x = Some(2); /// let old = x.replace(5); /// assert_eq!(x, Some(5)); @@ -880,7 +878,7 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] - #[unstable(feature = "option_replace", issue = "51998")] + #[stable(feature = "option_replace", since = "1.30.0")] pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index ada61d8dfd873..0beb60a127097 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -39,7 +39,6 @@ #![feature(reverse_bits)] #![feature(inner_deref)] #![feature(slice_internals)] -#![feature(option_replace)] #![feature(slice_partition_dedup)] #![feature(copy_within)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4405c0aef9023..0514bd20c985a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -21,7 +21,6 @@ #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(option_replace)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] From c232ea12763b82ae8d4b616df649c23c4961d0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 8 Oct 2018 10:18:43 +0200 Subject: [PATCH 12/21] Bump the `Option::replace` stabilize version to 1.31.0 --- src/libcore/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index ee313cd6e8e97..cf1c77041b91f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,7 +878,7 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] - #[stable(feature = "option_replace", since = "1.30.0")] + #[stable(feature = "option_replace", since = "1.31.0")] pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } From f8c1b0cd5bdd603e7a0e1193f0dd7a6c9b0ebcc2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 01:17:43 +0200 Subject: [PATCH 13/21] Add struct field suggestions. This commit adds suggestions to change the definitions of fields in struct definitions from immutable references to mutable references. --- .../borrow_check/mutability_errors.rs | 80 +++++++++++++++++++ .../ui/did_you_mean/issue-38147-2.nll.stderr | 3 + .../ui/did_you_mean/issue-38147-3.nll.stderr | 3 + 3 files changed, 86 insertions(+) diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index ba625fb08c82c..fe24ec382ceb3 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -218,6 +218,33 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on); match the_place_err { + // Suggest making an existing shared borrow in a struct definition a mutable borrow. + // + // This is applicable when we have a deref of a field access to a deref of a local - + // something like `*((*_1).0`. The local that we get will be a reference to the + // struct we've got a field access of (it must be a reference since there's a deref + // after the field access). + Place::Projection(box Projection { + base: Place::Projection(box Projection { + base: Place::Projection(box Projection { + base, + elem: ProjectionElem::Deref, + }), + elem: ProjectionElem::Field(field, _), + }), + elem: ProjectionElem::Deref, + }) => { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + + if let Some((span, message)) = annotate_struct_field( + self.infcx.tcx, + base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), + field, + ) { + err.span_label(span, message); + } + }, + // Suggest removing a `&mut` from the use of a mutable reference. Place::Local(local) if { @@ -592,3 +619,56 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>( fn is_closure_or_generator(ty: ty::Ty) -> bool { ty.is_closure() || ty.is_generator() } + +/// Add a suggestion to a struct definition given a field access to a local. +/// This function expects the local to be a reference to a struct in order to produce a suggestion. +/// +/// ```text +/// LL | s: &'a String +/// | ---------- use `&'a mut String` here to make mutable +/// ``` +fn annotate_struct_field( + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + ty: ty::Ty<'tcx>, + field: &mir::Field, +) -> Option<(Span, String)> { + // Expect our local to be a reference to a struct of some kind. + if let ty::TyKind::Ref(_, ty, _) = ty.sty { + if let ty::TyKind::Adt(def, _) = ty.sty { + let field = def.all_fields().nth(field.index())?; + let span = tcx.def_span(field.did); + + // Use the HIR types to construct the diagnostic message. + let node_id = tcx.hir.as_local_node_id(field.did)?; + let node = tcx.hir.find(node_id)?; + // Now we're dealing with the actual struct that we're going to suggest a change to, + // we can expect a field that is an immutable reference to a type. + if let hir::Node::Field(field) = node { + if let hir::TyKind::Rptr(lifetime, hir::MutTy { + mutbl: hir::Mutability::MutImmutable, + ref ty + }) = field.ty.node { + // Get the snippets in two parts - the named lifetime (if there is one) and + // type being referenced, that way we can reconstruct the snippet without loss + // of detail. + let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?; + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?) + } else { + String::new() + }; + + return Some(( + span, + format!( + "use `&{}mut {}` here to make mutable", + lifetime_snippet, &*type_snippet, + ), + )); + } + } + } + } + + None +} diff --git a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr index 21fc4079d5b59..91ccef1a32f1f 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr @@ -1,6 +1,9 @@ error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-2.rs:17:9 | +LL | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr index d426c1f37fc1c..ecc80a1d4310b 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr @@ -1,6 +1,9 @@ error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-3.rs:17:9 | +LL | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable From 9e49ac067f205e4400e85c98e35c2fe9af820d7d Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 5 Oct 2018 14:30:45 +0200 Subject: [PATCH 14/21] Change from label to suggestion. This commit changes the label to a maybe incorrect suggestion for better integration with RLS. --- src/librustc_mir/borrow_check/mutability_errors.rs | 13 ++++++++----- src/test/ui/did_you_mean/issue-38147-2.nll.stderr | 2 +- src/test/ui/did_you_mean/issue-38147-3.nll.stderr | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index fe24ec382ceb3..5ab1605d7f07a 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -241,7 +241,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), field, ) { - err.span_label(span, message); + err.span_suggestion_with_applicability( + span, + "consider changing this to be mutable", + message, + Applicability::MaybeIncorrect, + ); } }, @@ -636,8 +641,6 @@ fn annotate_struct_field( if let ty::TyKind::Ref(_, ty, _) = ty.sty { if let ty::TyKind::Adt(def, _) = ty.sty { let field = def.all_fields().nth(field.index())?; - let span = tcx.def_span(field.did); - // Use the HIR types to construct the diagnostic message. let node_id = tcx.hir.as_local_node_id(field.did)?; let node = tcx.hir.find(node_id)?; @@ -659,9 +662,9 @@ fn annotate_struct_field( }; return Some(( - span, + field.ty.span, format!( - "use `&{}mut {}` here to make mutable", + "&{}mut {}", lifetime_snippet, &*type_snippet, ), )); diff --git a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr index 91ccef1a32f1f..ebd44d46eb2ce 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` referenc --> $DIR/issue-38147-2.rs:17:9 | LL | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr index ecc80a1d4310b..d644a84c7bbce 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` referenc --> $DIR/issue-38147-3.rs:17:9 | LL | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable From 40e20e288d0f928c25bc74c14d74227c4d5c7182 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 8 Oct 2018 15:43:53 +0200 Subject: [PATCH 15/21] Added text explaining the (new) relative roles of `optimize`+`debug` and to briefly touch on the theory of debugging rustc versus the practice of such. --- config.toml.example | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/config.toml.example b/config.toml.example index 66eaab236f7c0..c840be9f5d295 100644 --- a/config.toml.example +++ b/config.toml.example @@ -243,19 +243,36 @@ # ============================================================================= [rust] -# Indicates that the build should be optimized for debugging Rust. Note that -# this is typically not what you want as it takes an incredibly large amount of -# time to have a debug-mode rustc compile any code (notably libstd). If this -# value is set to `true` it will affect a number of configuration options below -# as well, if unconfigured. -#debug = false - -# Whether or not to optimize the compiler and standard library +# Whether or not to optimize the compiler and standard library. +# # Note: the slowness of the non optimized compiler compiling itself usually # outweighs the time gains in not doing optimizations, therefore a -# full bootstrap takes much more time with optimize set to false. +# full bootstrap takes much more time with `optimize` set to false. #optimize = true +# Indicates that the build should be configured for debugging Rust. A +# `debug`-enabled compiler and standard library will be somewhat +# slower (due to e.g. checking of debug assertions) but should remain +# usable. +# +# Note: If this value is set to `true`, it will affect a number of +# configuration options below as well, if they have been left +# unconfigured in this file. +# +# Note: changes to the `debug` setting do *not* affect `optimize` +# above. In theory, a "maximally debuggable" environment would +# set `optimize` to `false` above to assist the introspection +# facilities of debuggers like lldb and gdb. To recreate such an +# environment, explicitly set `optimize` to `false` and `debug` +# to `true`. In practice, everyone leaves `optimize` set to +# `true`, because an unoptimized rustc with debugging +# enabled becomes *unusably slow* (e.g. rust-lang/rust#24840 +# reported a 25x slowdown) and bootstrapping the supposed +# "maximally debuggable" environment (notably libstd) takes +# hours to build. +# +#debug = false + # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. From 54a3583da7031df49009d1162ddbb054c488428c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 17:44:33 +0200 Subject: [PATCH 16/21] it's auto traits that make for automatic implementations --- src/libstd/panic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 48a9b2f4a93de..5c87035d8e929 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -79,7 +79,7 @@ pub use core::panic::{PanicInfo, Location}; /// /// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow /// witnessing a broken invariant through the use of `catch_unwind` (catching a -/// panic). This trait is a marker trait, so it is automatically implemented for +/// panic). This trait is an auto trait, so it is automatically implemented for /// many types, and it is also structurally composed (e.g. a struct is unwind /// safe if all of its components are unwind safe). /// From dd0f5e5b02674e9b41c2cb8170907ab219cfbfbe Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 8 Oct 2018 20:36:50 +0100 Subject: [PATCH 17/21] =?UTF-8?q?Unused=20result=20warning:=20"X=20which?= =?UTF-8?q?=20must"=20=E2=86=A6=20"X=20that=20must"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lints/listing/warn-by-default.md | 6 +-- src/libcore/iter/mod.rs | 2 +- src/librustc_lint/unused.rs | 6 +-- src/test/ui/fn_must_use.stderr | 14 +++---- src/test/ui/lint/must-use-ops.stderr | 42 +++++++++---------- src/test/ui/unused/unused-result.rs | 8 ++-- src/test/ui/unused/unused-result.stderr | 16 +++---- 7 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index de76ddf33c17e..b01aed0915d08 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -279,7 +279,7 @@ warning: functions generic over types must be mangled 1 | #[no_mangle] | ------------ help: remove this attribute 2 | / fn foo(t: T) { -3 | | +3 | | 4 | | } | |_^ | @@ -513,7 +513,7 @@ This will produce: warning: borrow of packed field requires unsafe function or block (error E0133) --> src/main.rs:11:13 | -11 | let y = &x.data.0; +11 | let y = &x.data.0; | ^^^^^^^^^ | = note: #[warn(safe_packed_borrows)] on by default @@ -874,7 +874,7 @@ fn main() { This will produce: ```text -warning: unused `std::result::Result` which must be used +warning: unused `std::result::Result` that must be used --> src/main.rs:6:5 | 6 | returns_result(); diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ef3f4ced4f9b2..c42fb7019c771 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -253,7 +253,7 @@ //! using it. The compiler will warn us about this kind of behavior: //! //! ```text -//! warning: unused result which must be used: iterator adaptors are lazy and +//! warning: unused result that must be used: iterator adaptors are lazy and //! do nothing unless consumed //! ``` //! diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ae178888b6a1c..b4c12d42608ef 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { if let Some(must_use_op) = must_use_op { cx.span_lint(UNUSED_MUST_USE, expr.span, - &format!("unused {} which must be used", must_use_op)); + &format!("unused {} that must be used", must_use_op)); op_warned = true; } @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str) -> bool { for attr in cx.tcx.get_attrs(def_id).iter() { if attr.check_name("must_use") { - let msg = format!("unused {}`{}` which must be used", + let msg = format!("unused {}`{}` that must be used", describe_path, cx.tcx.item_path_str(def_id)); let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg); // check for #[must_use = "..."] @@ -233,7 +233,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel) .is_some(); - // Has a plugin registered this attribute as one which must be used at + // Has a plugin registered this attribute as one that must be used at // the crate level? let plugin_crate = plugin_attributes.iter() .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr index b5bad22f3dc78..08d8e11ed898d 100644 --- a/src/test/ui/fn_must_use.stderr +++ b/src/test/ui/fn_must_use.stderr @@ -1,4 +1,4 @@ -warning: unused return value of `need_to_use_this_value` which must be used +warning: unused return value of `need_to_use_this_value` that must be used --> $DIR/fn_must_use.rs:60:5 | LL | need_to_use_this_value(); //~ WARN unused return value @@ -11,13 +11,13 @@ LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ = note: it's important -warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used +warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used --> $DIR/fn_must_use.rs:65:5 | LL | m.need_to_use_this_method_value(); //~ WARN unused return value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: unused return value of `EvenNature::is_even` which must be used +warning: unused return value of `EvenNature::is_even` that must be used --> $DIR/fn_must_use.rs:66:5 | LL | m.is_even(); // trait method! @@ -25,25 +25,25 @@ LL | m.is_even(); // trait method! | = note: no side effects -warning: unused return value of `std::cmp::PartialEq::eq` which must be used +warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:72:5 | LL | 2.eq(&3); //~ WARN unused return value | ^^^^^^^^^ -warning: unused return value of `std::cmp::PartialEq::eq` which must be used +warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:73:5 | LL | m.eq(&n); //~ WARN unused return value | ^^^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/fn_must_use.rs:76:5 | LL | 2 == 3; //~ WARN unused comparison | ^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/fn_must_use.rs:77:5 | LL | m == n; //~ WARN unused comparison diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr index 5703536ef48fd..0f8bd97525187 100644 --- a/src/test/ui/lint/must-use-ops.stderr +++ b/src/test/ui/lint/must-use-ops.stderr @@ -1,4 +1,4 @@ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:22:5 | LL | val == 1; @@ -10,121 +10,121 @@ note: lint level defined here LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:23:5 | LL | val < 1; | ^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:24:5 | LL | val <= 1; | ^^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:25:5 | LL | val != 1; | ^^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:26:5 | LL | val >= 1; | ^^^^^^^^ -warning: unused comparison which must be used +warning: unused comparison that must be used --> $DIR/must-use-ops.rs:27:5 | LL | val > 1; | ^^^^^^^ -warning: unused arithmetic operation which must be used +warning: unused arithmetic operation that must be used --> $DIR/must-use-ops.rs:30:5 | LL | val + 2; | ^^^^^^^ -warning: unused arithmetic operation which must be used +warning: unused arithmetic operation that must be used --> $DIR/must-use-ops.rs:31:5 | LL | val - 2; | ^^^^^^^ -warning: unused arithmetic operation which must be used +warning: unused arithmetic operation that must be used --> $DIR/must-use-ops.rs:32:5 | LL | val / 2; | ^^^^^^^ -warning: unused arithmetic operation which must be used +warning: unused arithmetic operation that must be used --> $DIR/must-use-ops.rs:33:5 | LL | val * 2; | ^^^^^^^ -warning: unused arithmetic operation which must be used +warning: unused arithmetic operation that must be used --> $DIR/must-use-ops.rs:34:5 | LL | val % 2; | ^^^^^^^ -warning: unused logical operation which must be used +warning: unused logical operation that must be used --> $DIR/must-use-ops.rs:37:5 | LL | true && true; | ^^^^^^^^^^^^ -warning: unused logical operation which must be used +warning: unused logical operation that must be used --> $DIR/must-use-ops.rs:38:5 | LL | false || true; | ^^^^^^^^^^^^^ -warning: unused bitwise operation which must be used +warning: unused bitwise operation that must be used --> $DIR/must-use-ops.rs:41:5 | LL | 5 ^ val; | ^^^^^^^ -warning: unused bitwise operation which must be used +warning: unused bitwise operation that must be used --> $DIR/must-use-ops.rs:42:5 | LL | 5 & val; | ^^^^^^^ -warning: unused bitwise operation which must be used +warning: unused bitwise operation that must be used --> $DIR/must-use-ops.rs:43:5 | LL | 5 | val; | ^^^^^^^ -warning: unused bitwise operation which must be used +warning: unused bitwise operation that must be used --> $DIR/must-use-ops.rs:44:5 | LL | 5 << val; | ^^^^^^^^ -warning: unused bitwise operation which must be used +warning: unused bitwise operation that must be used --> $DIR/must-use-ops.rs:45:5 | LL | 5 >> val; | ^^^^^^^^ -warning: unused unary operation which must be used +warning: unused unary operation that must be used --> $DIR/must-use-ops.rs:48:5 | LL | !val; | ^^^^ -warning: unused unary operation which must be used +warning: unused unary operation that must be used --> $DIR/must-use-ops.rs:49:5 | LL | -val; | ^^^^ -warning: unused unary operation which must be used +warning: unused unary operation that must be used --> $DIR/must-use-ops.rs:50:5 | LL | *val_pointer; diff --git a/src/test/ui/unused/unused-result.rs b/src/test/ui/unused/unused-result.rs index 363ab6220bd6e..69d226ef1d0ed 100644 --- a/src/test/ui/unused/unused-result.rs +++ b/src/test/ui/unused/unused-result.rs @@ -28,8 +28,8 @@ fn qux() -> MustUseMsg { return foo::(); } #[allow(unused_results)] fn test() { foo::(); - foo::(); //~ ERROR: unused `MustUse` which must be used - foo::(); //~ ERROR: unused `MustUseMsg` which must be used + foo::(); //~ ERROR: unused `MustUse` that must be used + foo::(); //~ ERROR: unused `MustUseMsg` that must be used //~^ NOTE: some message } @@ -42,8 +42,8 @@ fn test2() { fn main() { foo::(); //~ ERROR: unused result - foo::(); //~ ERROR: unused `MustUse` which must be used - foo::(); //~ ERROR: unused `MustUseMsg` which must be used + foo::(); //~ ERROR: unused `MustUse` that must be used + foo::(); //~ ERROR: unused `MustUseMsg` that must be used //~^ NOTE: some message let _ = foo::(); diff --git a/src/test/ui/unused/unused-result.stderr b/src/test/ui/unused/unused-result.stderr index e6ca7b8fab8fd..156ec889387b0 100644 --- a/src/test/ui/unused/unused-result.stderr +++ b/src/test/ui/unused/unused-result.stderr @@ -1,7 +1,7 @@ -error: unused `MustUse` which must be used +error: unused `MustUse` that must be used --> $DIR/unused-result.rs:31:5 | -LL | foo::(); //~ ERROR: unused `MustUse` which must be used +LL | foo::(); //~ ERROR: unused `MustUse` that must be used | ^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -10,10 +10,10 @@ note: lint level defined here LL | #![deny(unused_results, unused_must_use)] | ^^^^^^^^^^^^^^^ -error: unused `MustUseMsg` which must be used +error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:32:5 | -LL | foo::(); //~ ERROR: unused `MustUseMsg` which must be used +LL | foo::(); //~ ERROR: unused `MustUseMsg` that must be used | ^^^^^^^^^^^^^^^^^^^^ | = note: some message @@ -30,16 +30,16 @@ note: lint level defined here LL | #![deny(unused_results, unused_must_use)] | ^^^^^^^^^^^^^^ -error: unused `MustUse` which must be used +error: unused `MustUse` that must be used --> $DIR/unused-result.rs:45:5 | -LL | foo::(); //~ ERROR: unused `MustUse` which must be used +LL | foo::(); //~ ERROR: unused `MustUse` that must be used | ^^^^^^^^^^^^^^^^^ -error: unused `MustUseMsg` which must be used +error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:46:5 | -LL | foo::(); //~ ERROR: unused `MustUseMsg` which must be used +LL | foo::(); //~ ERROR: unused `MustUseMsg` that must be used | ^^^^^^^^^^^^^^^^^^^^ | = note: some message From be8896109af7b939b5c01c4ad1c470904d06f494 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 8 Oct 2018 21:08:01 +0100 Subject: [PATCH 18/21] Fix handling of #[must_use] on unit and uninhabited types --- src/librustc_lint/unused.rs | 23 +++++++++++++++-------- src/test/ui/lint/must_use-unit.rs | 17 +++++++++++++++++ src/test/ui/lint/must_use-unit.stderr | 20 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/lint/must_use-unit.rs create mode 100644 src/test/ui/lint/must_use-unit.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ae178888b6a1c..ec3c310c63c4f 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -59,15 +59,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let t = cx.tables.expr_ty(&expr); - let ty_warned = match t.sty { - ty::Tuple(ref tys) if tys.is_empty() => return, - ty::Never => return, + // FIXME(varkor): replace with `t.is_unit() || t.conservative_is_uninhabited()`. + let type_permits_no_use = match t.sty { + ty::Tuple(ref tys) if tys.is_empty() => true, + ty::Never => true, ty::Adt(def, _) => { if def.variants.is_empty() { - return; + true + } else { + check_must_use(cx, def.did, s.span, "") } - check_must_use(cx, def.did, s.span, "") - }, + } _ => false, }; @@ -95,7 +97,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { if let Some(def) = maybe_def { let def_id = def.def_id(); fn_warned = check_must_use(cx, def_id, s.span, "return value of "); + } else if type_permits_no_use { + // We don't warn about unused unit or uninhabited types. + // (See https://github.com/rust-lang/rust/issues/43806 for details.) + return; } + let must_use_op = match expr.node { // Hardcoding operators here seemed more expedient than the // refactoring that would be needed to look up the `#[must_use]` @@ -139,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { op_warned = true; } - if !(ty_warned || fn_warned || op_warned) { + if !(type_permits_no_use || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } @@ -233,7 +240,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel) .is_some(); - // Has a plugin registered this attribute as one which must be used at + // Has a plugin registered this attribute as one that must be used at // the crate level? let plugin_crate = plugin_attributes.iter() .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs new file mode 100644 index 0000000000000..92568252164f6 --- /dev/null +++ b/src/test/ui/lint/must_use-unit.rs @@ -0,0 +1,17 @@ +#![feature(never_type)] + +#![deny(unused_must_use)] + +#[must_use] +fn foo() {} + +#[must_use] +fn bar() -> ! { + unimplemented!() +} + +fn main() { + foo(); //~ unused return value of `foo` + + bar(); //~ unused return value of `bar` +} diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr new file mode 100644 index 0000000000000..0a956f74611b5 --- /dev/null +++ b/src/test/ui/lint/must_use-unit.stderr @@ -0,0 +1,20 @@ +error: unused return value of `foo` which must be used + --> $DIR/must_use-unit.rs:14:5 + | +LL | foo(); //~ unused return value of `foo` + | ^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-unit.rs:3:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused return value of `bar` which must be used + --> $DIR/must_use-unit.rs:16:5 + | +LL | bar(); //~ unused return value of `bar` + | ^^^^^^ + +error: aborting due to 2 previous errors + From 344747330c5f88d204ee99507aa0bd6358d0fbec Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Fri, 5 Oct 2018 11:32:57 -0400 Subject: [PATCH 19/21] parse_trait_item_ now handles interpolated blocks as function body decls --- src/libsyntax/parse/parser.rs | 17 ++++++++ src/test/run-pass/macros/macro-as-fn-body.rs | 42 ++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/test/run-pass/macros/macro-as-fn-body.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5571a18b59625..a5a13fa3029d8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1430,6 +1430,23 @@ impl<'a> Parser<'a> { attrs.extend(inner_attrs.iter().cloned()); Some(body) } + token::Interpolated(ref nt) => { + match &nt.0 { + token::NtBlock(..) => { + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => { + let token_str = self.this_token_to_string(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`", + token_str)); + err.span_label(self.span, "expected `;` or `{`"); + return Err(err); + } + } + } _ => { let token_str = self.this_token_to_string(); let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`", diff --git a/src/test/run-pass/macros/macro-as-fn-body.rs b/src/test/run-pass/macros/macro-as-fn-body.rs new file mode 100644 index 0000000000000..8c3c9fdc66df2 --- /dev/null +++ b/src/test/run-pass/macros/macro-as-fn-body.rs @@ -0,0 +1,42 @@ +// 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. +// +// run-pass +// +// Description - ensure Interpolated blocks can act as valid function bodies +// Covered cases: free functions, struct methods, and default trait functions + +macro_rules! def_fn { + ($body:block) => { + fn bar() $body + } +} + +trait Foo { + def_fn!({ println!("foo"); }); +} + +struct Baz {} + +impl Foo for Baz {} + +struct Qux {} + +impl Qux { + def_fn!({ println!("qux"); }); +} + +def_fn!({ println!("quux"); }); + +pub fn main() { + Baz::bar(); + Qux::bar(); + bar(); +} From 1e584bf5c9858bee54a9fbff25ab28b2ad29eb57 Mon Sep 17 00:00:00 2001 From: mandeep Date: Tue, 9 Oct 2018 01:51:22 -0400 Subject: [PATCH 20/21] Refactor macro comment and add resize with zeros example --- src/liballoc/vec.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 3188de512662c..f7a0bbdceafc9 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -121,12 +121,16 @@ use raw_vec::RawVec; /// ``` /// /// It can also initialize each element of a `Vec` with a given value. -/// Initializing a `Vec` in this manner is the most efficient and safest way to allocate a -/// vector of zeros as previously zeroed memory is requested from the operating system: +/// This may be more efficient than performing allocation and initialization +/// in separate steps, especially when initializing a vector of zeros: /// /// ``` /// let vec = vec![0; 5]; /// assert_eq!(vec, [0, 0, 0, 0, 0]); +/// +/// // The following is equivalent, but potentially slower: +/// let mut vec1 = Vec::with_capacity(5); +/// vec1.resize(5, 0); /// ``` /// /// Use a `Vec` as an efficient stack: From a0577ee3e3ae6bbf4830d307abae0dd0bc6dbc6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 18:48:44 +0200 Subject: [PATCH 21/21] impl Eq+Hash for TyLayout --- src/librustc_mir/interpret/operand.rs | 17 +---------------- src/librustc_target/abi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index b53bcfa993d53..c0c97b0cabe00 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,7 +11,6 @@ //! Functions concerning immediate values and operands, and reading from operands. //! All high-level functions to read from memory work on operands as sources. -use std::hash::{Hash, Hasher}; use std::convert::TryInto; use rustc::{mir, ty}; @@ -221,7 +220,7 @@ impl Operand { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct OpTy<'tcx> { crate op: Operand, // ideally we'd make this private, but const_prop needs this pub layout: TyLayout<'tcx>, @@ -255,20 +254,6 @@ impl<'tcx> From> for OpTy<'tcx> { } } -// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type -impl<'tcx> Hash for OpTy<'tcx> { - fn hash(&self, state: &mut H) { - self.op.hash(state); - self.layout.ty.hash(state); - } -} -impl<'tcx> PartialEq for OpTy<'tcx> { - fn eq(&self, other: &Self) -> bool { - self.op == other.op && self.layout.ty == other.layout.ty - } -} -impl<'tcx> Eq for OpTy<'tcx> {} - // Use the existing layout if given (but sanity check in debug mode), // or compute the layout. #[inline(always)] diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 96eb69163220e..6b28fd091748f 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -874,7 +874,7 @@ impl LayoutDetails { /// to those obtained from `layout_of(ty)`, as we need to produce /// layouts for which Rust types do not exist, such as enum variants /// or synthetic fields of enums (i.e. discriminants) and fat pointers. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct TyLayout<'a, Ty> { pub ty: Ty, pub details: &'a LayoutDetails