From a87b44dbea5335c9b5d563b44e0e5f8b074ac9db Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 2 Oct 2019 18:36:06 +0000 Subject: [PATCH 01/40] Always inline `mem::{size_of,align_of}` in debug builds Those two are const fn and do not have any arguments. Inlining helps reducing generated code size in debug builds. --- src/libcore/mem/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 95ad4272cedd..12942af307b4 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -236,7 +236,7 @@ pub fn forget_unsized(t: T) { /// ``` /// /// [alignment]: ./fn.align_of.html -#[inline] +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] pub const fn size_of() -> usize { @@ -328,7 +328,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// /// assert_eq!(4, mem::align_of::()); /// ``` -#[inline] +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] pub const fn align_of() -> usize { From 3b0fd82bfad814ff777e7aa236b74804e4c469c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 8 Oct 2019 00:00:00 +0000 Subject: [PATCH 02/40] Disable Go and OCaml bindings when building LLVM Instead of instaling OCaml bindings in a location where installation will not fail, don't build them in the first place. --- src/bootstrap/native.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 7bf9ea2688f4..fb308bc35ebc 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -157,6 +157,7 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_ENABLE_BINDINGS", "OFF") .define("LLVM_ENABLE_Z3_SOLVER", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) @@ -169,15 +170,6 @@ impl Step for Llvm { } } - // By default, LLVM will automatically find OCaml and, if it finds it, - // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults - // to /usr/bin/ocaml. - // This causes problem for non-root builds of Rust. Side-step the issue - // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs - // in the prefix. - cfg.define("LLVM_OCAML_INSTALL_PATH", - env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); - let want_lldb = builder.config.lldb_enabled && !self.emscripten; // This setting makes the LLVM tools link to the dynamic LLVM library, From e6ce3ef80aad6df7e9971d126bb22619ab34927e Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: [PATCH 03/40] Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 18 ++++++++++++++++-- src/libsyntax/parse/token.rs | 2 +- .../mismatched-delim-brace-empty-block.rs | 3 +++ .../mismatched-delim-brace-empty-block.stderr | 11 +++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/parser/mismatched-delim-brace-empty-block.rs create mode 100644 src/test/ui/parser/mismatched-delim-brace-empty-block.stderr diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index e5ba7e45309d..fa494db2f9f3 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxHashMap; use syntax_pos::Span; use crate::print::pprust::token_to_string; @@ -16,6 +17,7 @@ impl<'a> StringReader<'a> { unmatched_braces: Vec::new(), matching_delim_spans: Vec::new(), last_unclosed_found_span: None, + last_delim_empty_block_spans: FxHashMap::default() }; let res = tt_reader.parse_all_token_trees(); (res, tt_reader.unmatched_braces) @@ -34,6 +36,7 @@ struct TokenTreesReader<'a> { /// Used only for error recovery when arriving to EOF with mismatched braces. matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, last_unclosed_found_span: Option, + last_delim_empty_block_spans: FxHashMap } impl<'a> TokenTreesReader<'a> { @@ -121,13 +124,20 @@ impl<'a> TokenTreesReader<'a> { // Correct delimiter. token::CloseDelim(d) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + let close_brace_span = self.token.span; + + if close_brace_span.lo() == open_brace_span.hi() { + let empty_block_span = open_brace_span.to(close_brace_span); + self.last_delim_empty_block_spans.insert(delim, empty_block_span); + } + if self.open_braces.len() == 0 { // Clear up these spans to avoid suggesting them as we've found // properly matched delimiters so far for an entire block. self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.token.span), + (open_brace, open_brace_span, close_brace_span), ); } // Parse the close delimiter. @@ -193,13 +203,17 @@ impl<'a> TokenTreesReader<'a> { tts.into() ).into()) }, - token::CloseDelim(_) => { + token::CloseDelim(delim) => { // An unexpected closing delimiter (i.e., there is no // matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected close delimiter: `{}`", token_str); let mut err = self.string_reader.sess.span_diagnostic .struct_span_err(self.token.span, &msg); + + if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { + err.span_label(span, "this block is empty, you might have not meant to close it"); + } err.span_label(self.token.span, "unexpected close delimiter"); Err(err) }, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fd78a2bd5344..6038bcae5aef 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -36,7 +36,7 @@ pub enum BinOpToken { } /// A delimiter token. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum DelimToken { /// A round parenthesis (i.e., `(` or `)`). Paren, diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs new file mode 100644 index 000000000000..bcc95c09e1e9 --- /dev/null +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs @@ -0,0 +1,3 @@ +fn main() {} + let _ = (); +} //~ ERROR unexpected close delimiter diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr new file mode 100644 index 000000000000..82fe8930c325 --- /dev/null +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -0,0 +1,11 @@ +error: unexpected close delimiter: `}` + --> $DIR/mismatched-delim-brace-empty-block.rs:3:1 + | +LL | fn main() {} + | -- this block is empty, you might have not meant to close it +LL | let _ = (); +LL | } + | ^ unexpected close delimiter + +error: aborting due to previous error + From 888d0ba8df38681c08ac25f30ff4cbfad8168d90 Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: [PATCH 04/40] Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index fa494db2f9f3..b088d160b923 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -212,7 +212,10 @@ impl<'a> TokenTreesReader<'a> { .struct_span_err(self.token.span, &msg); if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { - err.span_label(span, "this block is empty, you might have not meant to close it"); + err.span_label( + span, + "this block is empty, you might have not meant to close it" + ); } err.span_label(self.token.span, "unexpected close delimiter"); Err(err) From 77f0aaf0d0a92feb068999d6b14f60dcf325b0c1 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Sat, 12 Oct 2019 20:53:11 +0200 Subject: [PATCH 05/40] Add more coherence tests --- .../ui/coherence/impl-foreign-for-foreign.rs | 17 +++++++++++ .../coherence/impl-foreign-for-foreign.stderr | 12 ++++++++ .../impl-foreign-for-foreign[foreign].rs | 25 ++++++++++++++++ .../impl-foreign-for-foreign[foreign].stderr | 30 +++++++++++++++++++ .../impl-foreign-for-foreign[local].rs | 16 ++++++++++ .../impl-foreign-for-fundamental[foreign].rs | 21 +++++++++++++ ...pl-foreign-for-fundamental[foreign].stderr | 21 +++++++++++++ .../impl-foreign-for-fundamental[local].rs | 17 +++++++++++ .../ui/coherence/impl-foreign-for-local.rs | 15 ++++++++++ ...reign[fundemental[foreign]]-for-foreign.rs | 26 ++++++++++++++++ ...n[fundemental[foreign]]-for-foreign.stderr | 30 +++++++++++++++++++ ...foreign[fundemental[local]]-for-foreign.rs | 18 +++++++++++ .../impl[t]-foreign-for-(local, t).rs | 17 +++++++++++ .../impl[t]-foreign-for-(local, t).stderr | 12 ++++++++ .../impl[t]-foreign-for-foreign[t].rs | 23 ++++++++++++++ .../impl[t]-foreign-for-foreign[t].stderr | 21 +++++++++++++ .../impl[t]-foreign-for-fundamental[t].rs | 17 +++++++++++ .../impl[t]-foreign-for-fundamental[t].stderr | 11 +++++++ ...eign[fundemental[local]]-for-foreign[t].rs | 17 +++++++++++ .../impl[t]-foreign[local]-for-foreign[t].rs | 17 +++++++++++ ...eign[local]-for-fundamental[foreign[t]].rs | 19 ++++++++++++ 21 files changed, 402 insertions(+) create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign.rs create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[local].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[local].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-local.rs create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.rs b/src/test/ui/coherence/impl-foreign-for-foreign.rs new file mode 100644 index 000000000000..de0b66a35eb0 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.stderr b/src/test/ui/coherence/impl-foreign-for-foreign.stderr new file mode 100644 index 000000000000..b03a75a77c34 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign.rs:12:1 + | +LL | impl Remote for i32 { + | ^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs new file mode 100644 index 000000000000..5146263d9911 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs @@ -0,0 +1,25 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr new file mode 100644 index 000000000000..bfaec790b20a --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:12:1 + | +LL | impl Remote1> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:16:1 + | +LL | impl Remote1> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:20:1 + | +LL | impl Remote1> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[local].rs b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs new file mode 100644 index 000000000000..050769dcf4ce --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local(Rc); + +impl Remote1> for i32 {} +impl Remote1> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs new file mode 100644 index 000000000000..03b11edf98b4 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs @@ -0,0 +1,21 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Box { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote for Box> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr new file mode 100644 index 000000000000..2ce4921cf938 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:12:1 + | +LL | impl Remote for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:16:1 + | +LL | impl Remote for Box> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs new file mode 100644 index 000000000000..ae03ce6a440d --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote for Box {} +impl Remote for Box> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-local.rs b/src/test/ui/coherence/impl-foreign-for-local.rs new file mode 100644 index 000000000000..c9dddeba18dc --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs new file mode 100644 index 000000000000..06efb6c2ad75 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs @@ -0,0 +1,26 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1>> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1>> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr new file mode 100644 index 000000000000..bf2361a1718a --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:13:1 + | +LL | impl Remote1> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:17:1 + | +LL | impl Remote1>> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:21:1 + | +LL | impl Remote1>> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs new file mode 100644 index 000000000000..d47e0a36a565 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs @@ -0,0 +1,18 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for i32 {} +impl Remote1>> for f64 {} +impl Remote1>> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs new file mode 100644 index 000000000000..850b6f85d0ed --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for (Local, T) { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr new file mode 100644 index 000000000000..ff0b9d6d0da9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-(local, t).rs:12:1 + | +LL | impl Remote for (Local, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs new file mode 100644 index 000000000000..db7a2ae8076a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs @@ -0,0 +1,23 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; +use std::sync::Arc; + +struct Local; + +impl Remote for Rc { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +impl Remote for Arc { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr new file mode 100644 index 000000000000..d7ffcaf76f9a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:13:1 + | +LL | impl Remote for Rc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:18:1 + | +LL | impl Remote for Arc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs new file mode 100644 index 000000000000..4cc19e1a526c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for + // | some local type (e.g., `MyStruct`) +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr new file mode 100644 index 000000000000..20ce11ef9759 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign-for-fundamental[t].rs:12:1 + | +LL | impl Remote for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs new file mode 100644 index 000000000000..914680f191ac --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for Rc {} +impl Remote1>> for Rc {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs new file mode 100644 index 000000000000..1e84ff40c622 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1 for Rc {} +impl Remote1> for Rc {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs new file mode 100644 index 000000000000..ea6aa101d209 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1 for Box> {} +impl Remote1> for Box> {} +impl Remote1> for Box> {} +impl Remote1>> for Box> {} + +fn main() {} From fe819a074c748fd3d11fcc0be8164645a7cd58db Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 13 Oct 2019 12:59:23 +0800 Subject: [PATCH 06/40] Collect occurrences of for mismatched braces diagnostic Change-Id: I20ba0b62308370ee961141fa1aefc4b9c9f0cb3a --- src/libsyntax/parse/lexer/tokentrees.rs | 2 +- .../parser/mismatched-delim-brace-empty-block.rs | 4 +++- .../mismatched-delim-brace-empty-block.stderr | 15 +++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index b088d160b923..b4dd23c9f9b0 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -126,7 +126,7 @@ impl<'a> TokenTreesReader<'a> { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); let close_brace_span = self.token.span; - if close_brace_span.lo() == open_brace_span.hi() { + if tts.is_empty() { let empty_block_span = open_brace_span.to(close_brace_span); self.last_delim_empty_block_spans.insert(delim, empty_block_span); } diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs index bcc95c09e1e9..0f5a2cb09ecc 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs @@ -1,3 +1,5 @@ -fn main() {} +fn main() { + +} let _ = (); } //~ ERROR unexpected close delimiter diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr index 82fe8930c325..5ae5fc91a4e8 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -1,11 +1,14 @@ error: unexpected close delimiter: `}` - --> $DIR/mismatched-delim-brace-empty-block.rs:3:1 + --> $DIR/mismatched-delim-brace-empty-block.rs:5:1 | -LL | fn main() {} - | -- this block is empty, you might have not meant to close it -LL | let _ = (); -LL | } - | ^ unexpected close delimiter +LL | fn main() { + | ___________- +LL | | +LL | | } + | |_- this block is empty, you might have not meant to close it +LL | let _ = (); +LL | } + | ^ unexpected close delimiter error: aborting due to previous error From 10236f1cee5d08e1f74d270fa37cd20fca6b4077 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Oct 2019 13:52:49 +0200 Subject: [PATCH 07/40] Add long error explanation for E0577 --- src/librustc_resolve/error_codes.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 1e65cbada069..7c7cd9ec24a0 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1661,6 +1661,33 @@ match eco { ``` "##, +E0577: r##" +Something other than a module was found in visibility scope. + +Erroneous code example: + +```compile_fail,E0577,edition2018 +pub struct Sea; + +pub (in crate::Sea) struct Shark; // error! + +fn main() {} +``` + +`Sea` is not a module, therefore, it is invalid. To fix this error, we need to +replace `Sea` with a module. + +Please note that the visibility scope can only be applied on ancestors! + +```edition2018 +pub mod Sea { + pub (in crate::Sea) struct Shark; // ok! +} + +fn main() {} +``` +"##, + E0603: r##" A private item was used outside its scope. @@ -1791,6 +1818,5 @@ struct Foo> { E0573, E0575, E0576, - E0577, E0578, } From 3d88f2cbd0068d386edd32553f24908e3237b3ef Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Oct 2019 13:52:57 +0200 Subject: [PATCH 08/40] Update ui tests --- src/test/ui/resolve/resolve-bad-visibility.stderr | 3 ++- src/test/ui/span/visibility-ty-params.stderr | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr index d2fb7c7a9e69..be59edffe7f5 100644 --- a/src/test/ui/resolve/resolve-bad-visibility.stderr +++ b/src/test/ui/resolve/resolve-bad-visibility.stderr @@ -30,4 +30,5 @@ LL | pub(in too_soon) struct H; error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0433`. +Some errors have detailed explanations: E0433, E0577. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/span/visibility-ty-params.stderr b/src/test/ui/span/visibility-ty-params.stderr index c2f0711b0c86..d3fa1d7732e7 100644 --- a/src/test/ui/span/visibility-ty-params.stderr +++ b/src/test/ui/span/visibility-ty-params.stderr @@ -18,3 +18,4 @@ LL | m!{ m<> } error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0577`. From 70b136d532460d2e35456d303726be736a3adb3d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Oct 2019 15:16:51 +1100 Subject: [PATCH 09/40] Use a `BitSet` in `LexicalResolver::iterate_until_fixed_point()`. This wins 3% on `unicode_normalization`. --- .../infer/lexical_region_resolve/mod.rs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 6f55ade1e861..a8d1b2647606 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -19,8 +19,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; +use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; use std::fmt; use syntax_pos::Span; @@ -870,21 +870,34 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { where F: FnMut(&Constraint<'tcx>) -> (bool, bool), { - let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect(); + // Using bitsets to track the remaining elements is faster than using a + // `Vec` by itself (which requires removing elements, which requires + // element shuffling, which is slow). + let constraints: Vec<_> = self.data.constraints.keys().collect(); + let mut live_indices: BitSet = BitSet::new_filled(constraints.len()); + let mut killed_indices: BitSet = BitSet::new_empty(constraints.len()); let mut iteration = 0; let mut changed = true; while changed { changed = false; iteration += 1; debug!("---- Expansion iteration {}", iteration); - constraints.retain(|constraint| { + for index in live_indices.iter() { + let constraint = constraints[index]; let (edge_changed, retain) = body(constraint); if edge_changed { debug!("updated due to constraint {:?}", constraint); changed = true; } - retain - }); + if !retain { + let changed = killed_indices.insert(index); + debug_assert!(changed); + } + } + live_indices.subtract(&killed_indices); + + // We could clear `killed_indices` here, but we don't need to and + // it's cheaper not to. } debug!("---- Expansion complete after {} iteration(s)", iteration); } From d51fee092c76016f973a4a73e52a14e44c92b1c7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 17 Oct 2019 09:30:25 +1100 Subject: [PATCH 10/40] Inline and remove `iterate_until_fixed_point()`. The commit also removes the debug statement, because they annoyed me. This change wins another 1% on `unicode_normalization`, at least partly because it no longer needs to increment `iteration`. --- .../infer/lexical_region_resolve/mod.rs | 67 ++++++++----------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index a8d1b2647606..f30f19d41509 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -304,8 +304,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { - self.iterate_until_fixed_point(|constraint| { - debug!("expansion: constraint={:?}", constraint); + let mut process_constraint = |constraint: &Constraint<'tcx>| { let (a_region, b_vid, b_data, retain) = match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); @@ -331,7 +330,33 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let changed = self.expand_node(a_region, b_vid, b_data); (changed, retain) - }) + }; + + // Using bitsets to track the remaining elements is faster than using a + // `Vec` by itself (which requires removing elements, which requires + // element shuffling, which is slow). + let constraints: Vec<_> = self.data.constraints.keys().collect(); + let mut live_indices: BitSet = BitSet::new_filled(constraints.len()); + let mut killed_indices: BitSet = BitSet::new_empty(constraints.len()); + let mut changed = true; + while changed { + changed = false; + for index in live_indices.iter() { + let constraint = constraints[index]; + let (edge_changed, retain) = process_constraint(constraint); + if edge_changed { + changed = true; + } + if !retain { + let changed = killed_indices.insert(index); + debug_assert!(changed); + } + } + live_indices.subtract(&killed_indices); + + // We could clear `killed_indices` here, but we don't need to and + // it's cheaper not to. + } } // This function is very hot in some workloads. There's a single callsite @@ -866,42 +891,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - fn iterate_until_fixed_point(&self, mut body: F) - where - F: FnMut(&Constraint<'tcx>) -> (bool, bool), - { - // Using bitsets to track the remaining elements is faster than using a - // `Vec` by itself (which requires removing elements, which requires - // element shuffling, which is slow). - let constraints: Vec<_> = self.data.constraints.keys().collect(); - let mut live_indices: BitSet = BitSet::new_filled(constraints.len()); - let mut killed_indices: BitSet = BitSet::new_empty(constraints.len()); - let mut iteration = 0; - let mut changed = true; - while changed { - changed = false; - iteration += 1; - debug!("---- Expansion iteration {}", iteration); - for index in live_indices.iter() { - let constraint = constraints[index]; - let (edge_changed, retain) = body(constraint); - if edge_changed { - debug!("updated due to constraint {:?}", constraint); - changed = true; - } - if !retain { - let changed = killed_indices.insert(index); - debug_assert!(changed); - } - } - live_indices.subtract(&killed_indices); - - // We could clear `killed_indices` here, but we don't need to and - // it's cheaper not to. - } - debug!("---- Expansion complete after {} iteration(s)", iteration); - } - fn bound_is_met( &self, bound: &VerifyBound<'tcx>, From 42c0236ed0071ed9f8734c346341f0bf54732b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 13 Jun 2019 23:14:44 +0200 Subject: [PATCH 11/40] Use a sharded dep node to dep node index map --- src/librustc/dep_graph/graph.rs | 29 +++++++++++++++++------- src/librustc_data_structures/sharded.rs | 30 +++++++++++++++++++------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 5d2d30f8debb..337cdddc432c 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -4,6 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use smallvec::SmallVec; use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, AtomicU64, Ordering}; +use rustc_data_structures::sharded::{self, Sharded}; use std::sync::atomic::Ordering::SeqCst; use std::env; use std::hash::Hash; @@ -381,7 +382,7 @@ impl DepGraph { #[inline] pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data { - let map = data.current.node_to_node_index.lock(); + let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); if let Some(dep_node_index) = map.get(&v).copied() { std::mem::drop(map); data.read_index(dep_node_index); @@ -405,6 +406,7 @@ impl DepGraph { .unwrap() .current .node_to_node_index + .get_shard_by_value(dep_node) .lock() .get(dep_node) .cloned() @@ -414,7 +416,11 @@ impl DepGraph { #[inline] pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { if let Some(ref data) = self.data { - data.current.node_to_node_index.lock().contains_key(dep_node) + data.current + .node_to_node_index + .get_shard_by_value(&dep_node) + .lock() + .contains_key(dep_node) } else { false } @@ -595,7 +601,11 @@ impl DepGraph { #[cfg(not(parallel_compiler))] { - debug_assert!(!data.current.node_to_node_index.lock().contains_key(dep_node)); + debug_assert!(!data.current + .node_to_node_index + .get_shard_by_value(dep_node) + .lock() + .contains_key(dep_node)); debug_assert!(data.colors.get(prev_dep_node_index).is_none()); } @@ -927,7 +937,7 @@ struct DepNodeData { /// acquire the lock on `data.` pub(super) struct CurrentDepGraph { data: Lock>, - node_to_node_index: Lock>, + node_to_node_index: Sharded>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -985,8 +995,8 @@ impl CurrentDepGraph { CurrentDepGraph { data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), - node_to_node_index: Lock::new(FxHashMap::with_capacity_and_hasher( - new_node_count_estimate, + node_to_node_index: Sharded::new(|| FxHashMap::with_capacity_and_hasher( + new_node_count_estimate / sharded::SHARDS, Default::default(), )), anon_id_seed: stable_hasher.finish(), @@ -1035,7 +1045,10 @@ impl CurrentDepGraph { edges: SmallVec<[DepNodeIndex; 8]>, fingerprint: Fingerprint ) -> DepNodeIndex { - debug_assert!(!self.node_to_node_index.lock().contains_key(&dep_node)); + debug_assert!(!self.node_to_node_index + .get_shard_by_value(&dep_node) + .lock() + .contains_key(&dep_node)); self.intern_node(dep_node, edges, fingerprint) } @@ -1045,7 +1058,7 @@ impl CurrentDepGraph { edges: SmallVec<[DepNodeIndex; 8]>, fingerprint: Fingerprint ) -> DepNodeIndex { - match self.node_to_node_index.lock().entry(dep_node) { + match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let mut data = self.data.lock(); diff --git a/src/librustc_data_structures/sharded.rs b/src/librustc_data_structures/sharded.rs index 31cb22098b8e..d0ff6108d6ea 100644 --- a/src/librustc_data_structures/sharded.rs +++ b/src/librustc_data_structures/sharded.rs @@ -2,6 +2,7 @@ use std::hash::{Hasher, Hash}; use std::mem; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; +use smallvec::SmallVec; use crate::fx::{FxHasher, FxHashMap}; use crate::sync::{Lock, LockGuard}; @@ -18,7 +19,7 @@ const SHARD_BITS: usize = 5; #[cfg(not(parallel_compiler))] const SHARD_BITS: usize = 0; -const SHARDS: usize = 1 << SHARD_BITS; +pub const SHARDS: usize = 1 << SHARD_BITS; /// An array of cache-line aligned inner locked structures with convenience methods. #[derive(Clone)] @@ -29,21 +30,36 @@ pub struct Sharded { impl Default for Sharded { #[inline] fn default() -> Self { + Self::new(|| T::default()) + } +} + +impl Sharded { + #[inline] + pub fn new(mut value: impl FnMut() -> T) -> Self { + // Create a vector of the values we want + let mut values: SmallVec<[_; SHARDS]> = (0..SHARDS).map(|_| { + CacheAligned(Lock::new(value())) + }).collect(); + + // Create an unintialized array let mut shards: mem::MaybeUninit<[CacheAligned>; SHARDS]> = mem::MaybeUninit::uninit(); - let first = shards.as_mut_ptr() as *mut CacheAligned>; + unsafe { - for i in 0..SHARDS { - first.add(i).write(CacheAligned(Lock::new(T::default()))); - } + // Copy the values into our array + let first = shards.as_mut_ptr() as *mut CacheAligned>; + values.as_ptr().copy_to_nonoverlapping(first, SHARDS); + + // Ignore the content of the vector + values.set_len(0); + Sharded { shards: shards.assume_init(), } } } -} -impl Sharded { #[inline] pub fn get_shard_by_value(&self, val: &K) -> &Lock { if SHARDS == 1 { From c716be6874f0c55c835d9b0aba5b41ff52329aab Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Thu, 17 Oct 2019 16:57:46 +0800 Subject: [PATCH 12/40] show up some extra info when t!() fails --- src/bootstrap/lib.rs | 2 +- src/build_helper/lib.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 9203a558f646..6fc72fa0b2a3 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1126,7 +1126,7 @@ impl Build { } let mut paths = Vec::new(); - let contents = t!(fs::read(stamp)); + let contents = t!(fs::read(stamp), &stamp); // This is the method we use for extracting paths from the stamp file passed to us. See // run_cargo for more information (in compile.rs). for part in contents.split(|b| *b == 0) { diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index f035a7119188..bb94fb2b755f 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -21,6 +21,13 @@ macro_rules! t { Err(e) => panic!("{} failed with {}", stringify!($e), e), } }; + // it can show extra info in the second parameter + ($e:expr, $extra:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra), + } + }; } // Because Cargo adds the compiler's dylib path to our library search path, llvm-config may From 83e97c6ac1b722c1b55fdf9d6378f87d9e0cdbdd Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 17 Oct 2019 13:53:57 +0200 Subject: [PATCH 13/40] properly document panics in div_euclid and rem_euclid --- src/libcore/num/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 998c8f816520..8f4ade377e31 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1864,7 +1864,7 @@ if `self < 0`, this is equal to round towards +/- infinity. # Panics -This function will panic if `rhs` is 0. +This function will panic if `rhs` is 0 or the division results in overflow. # Examples @@ -1903,7 +1903,7 @@ This is done as if by the Euclidean division algorithm -- given # Panics -This function will panic if `rhs` is 0. +This function will panic if `rhs` is 0 or the division results in overflow. # Examples @@ -3694,6 +3694,10 @@ Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self / rhs`. +# Panics + +This function will panic if `rhs` is 0. + # Examples Basic usage: @@ -3719,6 +3723,10 @@ Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self % rhs`. +# Panics + +This function will panic if `rhs` is 0. + # Examples Basic usage: From e4171802e29d77c1ead4a6816c8a6a78843f6834 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Thu, 17 Oct 2019 17:33:38 +0200 Subject: [PATCH 14/40] Update error_codes.rs --- src/librustc_resolve/error_codes.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 7c7cd9ec24a0..23bea5196d71 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -26,7 +26,7 @@ struct Foo { } ``` -Please also verify that this wasn't because of a name-clash and rename the type +Please also verify \hat this wasn't because of a name-clash and rename the type parameter if so. "##, @@ -1674,8 +1674,8 @@ pub (in crate::Sea) struct Shark; // error! fn main() {} ``` -`Sea` is not a module, therefore, it is invalid. To fix this error, we need to -replace `Sea` with a module. +`Sea` is not a module, therefore it is invalid to use it in a visibility path. +To fix this error we need to ensure `Sea` is a module. Please note that the visibility scope can only be applied on ancestors! From a4d94925c737b1fee1dc8e90225a71b47ed77042 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Oct 2019 14:15:59 -0400 Subject: [PATCH 15/40] add option to ping llvm ice-breakers to triagebot --- triagebot.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index d87c5b64c21c..b39c95f68361 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -8,3 +8,14 @@ allow-unauthenticated = [ ] [assign] + +[ping.icebreaker-llvm] +message = """\ +Hey LLVM ICE-breakers! This bug has been identified as a good +"LLVM ICE-breaking candidate". In case it's useful, here are some +[instructions] for tackling these sorts of bugs. Maybe take a look? +Thanks! <3 + +[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/llvm.html +""" +label = "ICEBreaker-LLVM" From 5fe88abed06b3efc8627d726c18dbc48d9d653b3 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 17 Oct 2019 20:48:00 +0200 Subject: [PATCH 16/40] save-analysis: Nest tables when processing impl items --- src/librustc_save_analysis/dump_visitor.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 502ae337b527..e282936b5d9e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -669,15 +669,18 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } } - self.visit_ty(&typ); - if let &Some(ref trait_ref) = trait_ref { - self.process_path(trait_ref.ref_id, &trait_ref.path); - } - self.process_generic_params(generics, "", item.id); - for impl_item in impl_items { - let map = &self.tcx.hir(); - self.process_impl_item(impl_item, map.local_def_id_from_node_id(item.id)); - } + + let map = &self.tcx.hir(); + self.nest_tables(item.id, |v| { + v.visit_ty(&typ); + if let &Some(ref trait_ref) = trait_ref { + v.process_path(trait_ref.ref_id, &trait_ref.path); + } + v.process_generic_params(generics, "", item.id); + for impl_item in impl_items { + v.process_impl_item(impl_item, map.local_def_id_from_node_id(item.id)); + } + }); } fn process_trait( From ad6ce4698641f57133ea75c379a928c6017b08cf Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 17 Oct 2019 20:49:06 +0200 Subject: [PATCH 17/40] save-analysis: Add a relevant test case --- src/test/ui/save-analysis/issue-65411.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/save-analysis/issue-65411.rs diff --git a/src/test/ui/save-analysis/issue-65411.rs b/src/test/ui/save-analysis/issue-65411.rs new file mode 100644 index 000000000000..9e58b8da5d27 --- /dev/null +++ b/src/test/ui/save-analysis/issue-65411.rs @@ -0,0 +1,15 @@ +// check-pass +// compile-flags: -Zsave-analysis + +trait Trait { type Assoc; } +trait GenericTrait {} +struct Wrapper { b: B } + +fn func() { + // Processing associated path in impl block definition inside a function + // body does not ICE + impl GenericTrait for Wrapper {} +} + + +fn main() {} From 4e6efe48110a5e09ee87b0aa8cea31d511bb5708 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Oct 2019 21:22:46 +0200 Subject: [PATCH 18/40] reorder fmt docs for more clarity --- src/liballoc/fmt.rs | 103 ++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 1e39b7f822e9..4d3523da7fc0 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -86,18 +86,53 @@ //! parameters (corresponding to `format_spec` in the syntax above). These //! parameters affect the string representation of what's being formatted. //! +//! ## Width +//! +//! ``` +//! // All of these print "Hello x !" +//! println!("Hello {:5}!", "x"); +//! println!("Hello {:1$}!", "x", 5); +//! println!("Hello {1:0$}!", 5, "x"); +//! println!("Hello {:width$}!", "x", width = 5); +//! ``` +//! +//! This is a parameter for the "minimum width" that the format should take up. +//! If the value's string does not fill up this many characters, then the +//! padding specified by fill/alignment will be used to take up the required +//! space (see below). +//! +//! The value for the width can also be provided as a [`usize`] in the list of +//! parameters by adding a postfix `$`, indicating that the second argument is +//! a [`usize`] specifying the width. +//! +//! Referring to an argument with the dollar syntax does not affect the "next +//! argument" counter, so it's usually a good idea to refer to arguments by +//! position, or use named arguments. +//! //! ## Fill/Alignment //! -//! The fill character is provided normally in conjunction with the -//! [`width`](#width) -//! parameter. This indicates that if the value being formatted is smaller than -//! `width` some extra characters will be printed around it. The extra -//! characters are specified by `fill`, and the alignment can be one of the -//! following options: +//! ``` +//! assert_eq!(format!("Hello {:<5}!", "x"), "Hello x !"); +//! assert_eq!(format!("Hello {:-<5}!", "x"), "Hello x----!"); +//! assert_eq!(format!("Hello {:^5}!", "x"), "Hello x !"); +//! assert_eq!(format!("Hello {:>5}!", "x"), "Hello x!"); +//! ``` +//! +//! The optional fill character and alignment is provided normally in conjunction with the +//! [`width`](#width) parameter. It must be defined before `width`, right after the `:`. +//! This indicates that if the value being formatted is smaller than +//! `width` some extra characters will be printed around it. +//! Filling comes in the following variants for different alignments: //! -//! * `<` - the argument is left-aligned in `width` columns -//! * `^` - the argument is center-aligned in `width` columns -//! * `>` - the argument is right-aligned in `width` columns +//! * `[fill]<` - the argument is left-aligned in `width` columns +//! * `[fill]^` - the argument is center-aligned in `width` columns +//! * `[fill]>` - the argument is right-aligned in `width` columns +//! +//! The default [fill/alignment](#fillalignment) for non-numerics is a space and +//! left-aligned. The +//! defaults for numeric formatters is also a space but with right-alignment. If +//! the `0` flag (see below) is specified for numerics, then the implicit fill character is +//! `0`. //! //! Note that alignment may not be implemented by some types. In particular, it //! is not generally implemented for the `Debug` trait. A good way to ensure @@ -106,7 +141,15 @@ //! //! ## Sign/`#`/`0` //! -//! These can all be interpreted as flags for a particular formatter. +//! ``` +//! assert_eq!(format!("Hello {:+}!", 5), "Hello +5!"); +//! assert_eq!(format!("{:#x}!", 27), "0x1b!"); +//! assert_eq!(format!("Hello {:05}!", 5), "Hello 00005!"); +//! assert_eq!(format!("Hello {:05}!", -5), "Hello -0005!"); +//! assert_eq!(format!("{:#010x}!", 27), "0x0000001b!"); +//! ``` +//! +//! These are all flags altering the behavior of the formatter. //! //! * `+` - This is intended for numeric types and indicates that the sign //! should always be printed. Positive signs are never printed by @@ -121,7 +164,7 @@ //! * `#X` - precedes the argument with a `0x` //! * `#b` - precedes the argument with a `0b` //! * `#o` - precedes the argument with a `0o` -//! * `0` - This is used to indicate for integer formats that the padding should +//! * `0` - This is used to indicate for integer formats that the padding to `width` should //! both be done with a `0` character as well as be sign-aware. A format //! like `{:08}` would yield `00000001` for the integer `1`, while the //! same format would yield `-0000001` for the integer `-1`. Notice that @@ -129,36 +172,7 @@ //! Note that padding zeroes are always placed after the sign (if any) //! and before the digits. When used together with the `#` flag, a similar //! rule applies: padding zeroes are inserted after the prefix but before -//! the digits. -//! -//! ## Width -//! -//! This is a parameter for the "minimum width" that the format should take up. -//! If the value's string does not fill up this many characters, then the -//! padding specified by fill/alignment will be used to take up the required -//! space. -//! -//! The default [fill/alignment](#fillalignment) for non-numerics is a space and -//! left-aligned. The -//! defaults for numeric formatters is also a space but with right-alignment. If -//! the `0` flag is specified for numerics, then the implicit fill character is -//! `0`. -//! -//! The value for the width can also be provided as a [`usize`] in the list of -//! parameters by using the dollar syntax indicating that the second argument is -//! a [`usize`] specifying the width, for example: -//! -//! ``` -//! // All of these print "Hello x !" -//! println!("Hello {:5}!", "x"); -//! println!("Hello {:1$}!", "x", 5); -//! println!("Hello {1:0$}!", 5, "x"); -//! println!("Hello {:width$}!", "x", width = 5); -//! ``` -//! -//! Referring to an argument with the dollar syntax does not affect the "next -//! argument" counter, so it's usually a good idea to refer to arguments by -//! position, or use named arguments. +//! the digits. The prefix is included in the total width. //! //! ## Precision //! @@ -235,9 +249,14 @@ //! them with the same character. For example, the `{` character is escaped with //! `{{` and the `}` character is escaped with `}}`. //! +//! ``` +//! assert_eq!(format!("Hello {{}}"), "Hello {}"); +//! assert_eq!(format!("{{ Hello"), "{ Hello"); +//! ``` +//! //! # Syntax //! -//! To summarize, you can find the full grammar of format strings. +//! To summarize, here you can find the full grammar of format strings. //! The syntax for the formatting language used is drawn from other languages, //! so it should not be too alien. Arguments are formatted with Python-like //! syntax, meaning that arguments are surrounded by `{}` instead of the C-like From 54879949f18ed44dc4db4b9c450d6c09551a2e0d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Oct 2019 16:53:47 -0400 Subject: [PATCH 19/40] Update triagebot.toml Co-Authored-By: Mark Rousskov --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index b39c95f68361..f0e3a99037b0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -9,7 +9,7 @@ allow-unauthenticated = [ [assign] -[ping.icebreaker-llvm] +[ping.icebreakers-llvm] message = """\ Hey LLVM ICE-breakers! This bug has been identified as a good "LLVM ICE-breaking candidate". In case it's useful, here are some From c0b7e769a0f76a76fc5d239d886e5b8a69648b10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Oct 2019 23:00:46 +0200 Subject: [PATCH 20/40] example for padding any format --- src/liballoc/fmt.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 4d3523da7fc0..cbfc55233a1e 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -136,8 +136,12 @@ //! //! Note that alignment may not be implemented by some types. In particular, it //! is not generally implemented for the `Debug` trait. A good way to ensure -//! padding is applied is to format your input, then use this resulting string -//! to pad your output. +//! padding is applied is to format your input, then pad this resulting string +//! to obtain your output: +//! +//! ``` +//! println!("Hello {:^15}!", format!("{:?}", Some("hi"))); // => "Hello Some("hi") !" +//! ``` //! //! ## Sign/`#`/`0` //! From c9b27d1236d68f9f5c86ca4db015ddeca6a1e39a Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 18 Oct 2019 01:16:30 +0200 Subject: [PATCH 21/40] doc: make BitSet intro more short Also, add a link to the growable type --- src/librustc_index/bit_set.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index d8c6e4c33e2f..9ed5ef5a539a 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -13,8 +13,9 @@ pub type Word = u64; pub const WORD_BYTES: usize = mem::size_of::(); pub const WORD_BITS: usize = WORD_BYTES * 8; -/// A fixed-size bitset type with a dense representation. It does not support -/// resizing after creation; use `GrowableBitSet` for that. +/// A fixed-size bitset type with a dense representation. +/// +/// NOTE: Use [`GrowableBitSet`] if you need support for resizing after creation. /// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also /// just be `usize`. @@ -22,6 +23,8 @@ pub const WORD_BITS: usize = WORD_BYTES * 8; /// All operations that involve an element will panic if the element is equal /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. +/// +/// [`GrowableBitSet`]: struct.GrowableBitSet.html #[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)] pub struct BitSet { domain_size: usize, From 5de9cb0703555ee6e2e0af8305be138f09545485 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 19:36:48 -0300 Subject: [PATCH 22/40] super_ty on MutVisitor is empty so avoid the call --- src/librustc_mir/transform/erase_regions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 38a04ce8f381..e9ce84a25838 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -25,7 +25,6 @@ impl EraseRegionsVisitor<'tcx> { impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { *ty = self.tcx.erase_regions(ty); - self.super_ty(ty); } fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { From e069e9ccacbe92de1c893be5ad77fd5d6173f937 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 16:39:20 -0300 Subject: [PATCH 23/40] Prepare promote_consts MutVisitor to have projections interned --- src/librustc_mir/transform/promote_consts.rs | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 5d241ffe1c06..d1c79c5ae2ad 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -191,6 +191,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }); } + fn is_temp_kind(&self, local: Local) -> bool { + self.source.local_kind(local) == LocalKind::Temp + } + /// Copies the initialization of this temp to the /// promoted MIR, recursing through temps. fn promote_temp(&mut self, temp: Local) -> Local { @@ -396,10 +400,30 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { local: &mut Local, _: PlaceContext, _: Location) { - if self.source.local_kind(*local) == LocalKind::Temp { + if self.is_temp_kind(*local) { *local = self.promote_temp(*local); } } + + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + match elem { + PlaceElem::Index(local) if self.is_temp_kind(*local) => { + PlaceElem::Index(self.promote_temp(*local)) + } + _ => elem.clone(), + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } pub fn promote_candidates<'tcx>( From 591cc9aede4aec9b8816b8489eb98c2f2a3bfe90 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 17:58:28 -0300 Subject: [PATCH 24/40] Prepare simplify MutVisitor to have projections interned --- src/librustc_mir/transform/simplify.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 9ffff9a92fa5..57bc1c8fab96 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -366,7 +366,27 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { }); self.super_basic_block_data(block, data); } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } + + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + if let PlaceElem::Index(local) = elem { + PlaceElem::Index(self.map[*local].unwrap()) + } else { + elem.clone() + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } From bb7d6d1c70964d1d3efd5fb448538b7de50bbe3c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 18:15:19 -0300 Subject: [PATCH 25/40] Prepare renumber MutVisitor to have projections interned --- src/librustc_mir/borrow_check/nll/renumber.rs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 88ad1fb12950..6eb5735cb16b 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,7 +1,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::mir::{Location, Body, Promoted}; -use rustc::mir::visit::{MutVisitor, TyContext}; +use rustc::mir::{Body, Location, Place, PlaceElem, Promoted}; +use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_index::vec::IndexVec; @@ -62,6 +62,25 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { debug!("visit_ty: ty={:?}", ty); } + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + if let PlaceElem::Field(field, ty) = elem { + PlaceElem::Field(*field, self.renumber_regions(ty)) + } else { + elem.clone() + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } + fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { debug!("visit_substs(substs={:?}, location={:?})", substs, location); From e3e99516730f72fa05cb964ae341156e1ca85c39 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 18:23:39 -0300 Subject: [PATCH 26/40] Prepare inline MutVisitor to have projections interned --- src/librustc_mir/transform/inline.rs | 51 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 9830ed35ffc3..3a71d22da787 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -647,38 +647,45 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { debug!("updating target `{:?}`, new: `{:?}`", tgt, new); new } -} -impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { - fn visit_local(&mut self, - local: &mut Local, - _ctxt: PlaceContext, - _location: Location) { + fn make_integrate_local(&self, local: &Local) -> Local { if *local == RETURN_PLACE { match self.destination { Place { base: PlaceBase::Local(l), projection: box [], } => { - *local = l; - return; + return l; }, ref place => bug!("Return place is {:?}, not local", place) } } + let idx = local.index() - 1; if idx < self.args.len() { - *local = self.args[idx]; - return; + return self.args[idx]; } - *local = self.local_map[Local::new(idx - self.args.len())]; + + self.local_map[Local::new(idx - self.args.len())] } +} - fn visit_place(&mut self, - place: &mut Place<'tcx>, - _ctxt: PlaceContext, - _location: Location) { +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn visit_local( + &mut self, + local: &mut Local, + _ctxt: PlaceContext, + _location: Location, + ) { + *local = self.make_integrate_local(local); + } + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { match place { Place { base: PlaceBase::Local(RETURN_PLACE), @@ -687,7 +694,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { // Return pointer; update the place itself *place = self.destination.clone(); }, - _ => self.super_place(place, _ctxt, _location) + _ => { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + if let PlaceElem::Index(local) = elem { + PlaceElem::Index(self.make_integrate_local(local)) + } else { + elem.clone() + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } } From 0fc063f15936761024183a3bb3790684d5de3bd3 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 19:14:35 -0300 Subject: [PATCH 27/40] Prepare generator MutVisitor to have projections interned --- src/librustc_mir/transform/generator.rs | 52 +++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 865fa012c299..a801548efab0 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -88,6 +88,24 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { *local = self.to; } } + + fn visit_place(&mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + match elem { + PlaceElem::Index(local) if *local == self.from => { + PlaceElem::Index(self.to) + } + _ => elem.clone(), + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } struct DerefArgVisitor; @@ -110,7 +128,13 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { projection: Box::new([ProjectionElem::Deref]), }); } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } } @@ -137,7 +161,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), }); } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } } @@ -247,17 +277,25 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { assert_eq!(self.remap.get(local), None); } - fn visit_place(&mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location) { + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { if let PlaceBase::Local(l) = place.base { // Replace an Local in the remap with a generator struct access if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { replace_base(place, self.make_field(variant_index, idx, ty)); } } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } From 39c9ed3ac19b3f6c79069d32a317daa763371369 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 7 Oct 2019 19:35:41 -0300 Subject: [PATCH 28/40] Prepare erase_regions MutVisitor to have projections interned --- src/librustc_mir/transform/erase_regions.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index e9ce84a25838..132149d5d433 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -7,7 +7,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, TyContext}; +use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext}; use crate::transform::{MirPass, MirSource}; struct EraseRegionsVisitor<'tcx> { @@ -38,6 +38,25 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) { *substs = self.tcx.erase_regions(substs); } + + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + if let PlaceElem::Field(field, ty) = elem { + PlaceElem::Field(*field, self.tcx.erase_regions(ty)) + } else { + elem.clone() + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } pub struct EraseRegions; From 2b2e35bfc34618cff7b62a7726ee3a97101d3fa2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 8 Oct 2019 00:24:18 -0300 Subject: [PATCH 29/40] Prepare def_use MutVisitor to have projections interned --- src/librustc_mir/util/def_use.rs | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 3aea25fa8769..d90be90bd9d4 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,6 +1,6 @@ //! Def-use analysis. -use rustc::mir::{Local, Location, Body}; +use rustc::mir::{Body, Local, Location, Place, PlaceElem}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc_index::vec::IndexVec; use std::mem; @@ -47,13 +47,13 @@ impl DefUseAnalysis { &self.info[local] } - fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, mut callback: F) - where F: for<'a> FnMut(&'a mut Local, + fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, callback: F) + where F: for<'a> Fn(&'a Local, PlaceContext, - Location) { + Location) -> Local { for place_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, - &mut callback, + &callback, body).visit_location(body, place_use.location) } } @@ -63,7 +63,7 @@ impl DefUseAnalysis { local: Local, body: &mut Body<'_>, new_local: Local) { - self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local) + self.mutate_defs_and_uses(local, body, |_, _, _| new_local) } } @@ -125,7 +125,7 @@ struct MutateUseVisitor { impl MutateUseVisitor { fn new(query: Local, callback: F, _: &Body<'_>) -> MutateUseVisitor - where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { + where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local { MutateUseVisitor { query, callback, @@ -134,13 +134,31 @@ impl MutateUseVisitor { } impl MutVisitor<'_> for MutateUseVisitor - where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { + where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local { fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) { if *local == self.query { - (self.callback)(local, context, location) + *local = (self.callback)(local, context, location) } } + + fn visit_place(&mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + match elem { + PlaceElem::Index(local) if *local == self.query => { + PlaceElem::Index((self.callback)(&local, context, location)) + } + _ => elem.clone(), + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } From 4f2a11036d085227e261824a1aa76dd752c84267 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 8 Oct 2019 00:33:47 -0300 Subject: [PATCH 30/40] Remove unneeded callback and just use the new_local value --- src/librustc_mir/util/def_use.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index d90be90bd9d4..5b5f7d83f074 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -47,13 +47,10 @@ impl DefUseAnalysis { &self.info[local] } - fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, callback: F) - where F: for<'a> Fn(&'a Local, - PlaceContext, - Location) -> Local { + fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) { for place_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, - &callback, + new_local, body).visit_location(body, place_use.location) } } @@ -63,7 +60,7 @@ impl DefUseAnalysis { local: Local, body: &mut Body<'_>, new_local: Local) { - self.mutate_defs_and_uses(local, body, |_, _, _| new_local) + self.mutate_defs_and_uses(local, body, new_local) } } @@ -117,30 +114,27 @@ impl Info { } } -struct MutateUseVisitor { +struct MutateUseVisitor { query: Local, - callback: F, + new_local: Local, } -impl MutateUseVisitor { - fn new(query: Local, callback: F, _: &Body<'_>) - -> MutateUseVisitor - where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local { +impl MutateUseVisitor { + fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor { MutateUseVisitor { query, - callback, + new_local, } } } -impl MutVisitor<'_> for MutateUseVisitor - where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local { +impl MutVisitor<'_> for MutateUseVisitor { fn visit_local(&mut self, local: &mut Local, - context: PlaceContext, - location: Location) { + _context: PlaceContext, + _location: Location) { if *local == self.query { - *local = (self.callback)(local, context, location) + *local = self.new_local; } } @@ -153,7 +147,7 @@ impl MutVisitor<'_> for MutateUseVisitor let new_projection: Vec<_> = place.projection.iter().map(|elem| match elem { PlaceElem::Index(local) if *local == self.query => { - PlaceElem::Index((self.callback)(&local, context, location)) + PlaceElem::Index(self.new_local) } _ => elem.clone(), } From 7fa3425ef675b4bf4177dc2ea232078f4556b4c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 8 Oct 2019 12:16:26 -0300 Subject: [PATCH 31/40] Setup a different visit place set of methods for mutable and immutable visitors In particular, use a blank visit_place for mutable visitor to be sure, non modified visitors are not trying to mutating place. --- src/librustc/mir/visit.rs | 180 ++++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 77 deletions(-) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index edc7922f46ee..0fb43c7f98d1 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -158,22 +158,7 @@ macro_rules! make_mir_visitor { self.super_place_base(base, context, location); } - fn visit_projection(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - projection: & $($mutability)? [PlaceElem<'tcx>], - context: PlaceContext, - location: Location) { - self.super_projection(base, projection, context, location); - } - - fn visit_projection_elem(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - proj_base: & $($mutability)? [PlaceElem<'tcx>], - elem: & $($mutability)? PlaceElem<'tcx>, - context: PlaceContext, - location: Location) { - self.super_projection_elem(base, proj_base, elem, context, location); - } + visit_place_fns!($($mutability)?); fn visit_constant(&mut self, constant: & $($mutability)? Constant<'tcx>, @@ -681,28 +666,6 @@ macro_rules! make_mir_visitor { ); } - fn super_place(&mut self, - place: & $($mutability)? Place<'tcx>, - context: PlaceContext, - location: Location) { - let mut context = context; - - if !place.projection.is_empty() { - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } - - self.visit_place_base(& $($mutability)? place.base, context, location); - - self.visit_projection(& $($mutability)? place.base, - & $($mutability)? place.projection, - context, - location); - } - fn super_place_base(&mut self, place_base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, @@ -717,45 +680,6 @@ macro_rules! make_mir_visitor { } } - fn super_projection(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - projection: & $($mutability)? [PlaceElem<'tcx>], - context: PlaceContext, - location: Location) { - let mut cursor = projection; - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - self.visit_projection_elem(base, cursor, elem, context, location); - } - } - - fn super_projection_elem(&mut self, - _base: & $($mutability)? PlaceBase<'tcx>, - _proj_base: & $($mutability)? [PlaceElem<'tcx>], - elem: & $($mutability)? PlaceElem<'tcx>, - _context: PlaceContext, - location: Location) { - match elem { - ProjectionElem::Field(_field, ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - ProjectionElem::Index(local) => { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _ } | - ProjectionElem::ConstantIndex { offset: _, - min_length: _, - from_end: _ } | - ProjectionElem::Downcast(_, _) => { - } - } - } - fn super_local_decl(&mut self, local: Local, local_decl: & $($mutability)? LocalDecl<'tcx>) { @@ -858,6 +782,108 @@ macro_rules! make_mir_visitor { } } +macro_rules! visit_place_fns { + (mut) => ( + fn super_place( + &mut self, + _place: &mut Place<'tcx>, + _context: PlaceContext, + _location: Location, + ) { + } + ); + + () => ( + fn visit_projection( + &mut self, + base: &PlaceBase<'tcx>, + projection: &[PlaceElem<'tcx>], + context: PlaceContext, + location: Location, + ) { + self.super_projection(base, projection, context, location); + } + + fn visit_projection_elem( + &mut self, + base: &PlaceBase<'tcx>, + proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.super_projection_elem(base, proj_base, elem, context, location); + } + + fn super_place( + &mut self, + place: &Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + let mut context = context; + + if !place.projection.is_empty() { + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } + + self.visit_place_base(&place.base, context, location); + + self.visit_projection(&place.base, + &place.projection, + context, + location); + } + + fn super_projection( + &mut self, + base: &PlaceBase<'tcx>, + projection: &[PlaceElem<'tcx>], + context: PlaceContext, + location: Location, + ) { + let mut cursor = projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + self.visit_projection_elem(base, cursor, elem, context, location); + } + } + + fn super_projection_elem( + &mut self, + _base: &PlaceBase<'tcx>, + _proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, + _context: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Field(_field, ty) => { + self.visit_ty(ty, TyContext::Location(location)); + } + ProjectionElem::Index(local) => { + self.visit_local( + local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + } + ProjectionElem::Deref | + ProjectionElem::Subslice { from: _, to: _ } | + ProjectionElem::ConstantIndex { offset: _, + min_length: _, + from_end: _ } | + ProjectionElem::Downcast(_, _) => { + } + } + } + ); +} + make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); From d53fc9cae5b17c138be09383dea8b8f10d3df3a1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 8 Oct 2019 15:33:19 -0300 Subject: [PATCH 32/40] Add process_* place hooks to improve code reutilization --- src/librustc/mir/visit.rs | 28 +++++++++++++++++-- src/librustc_mir/borrow_check/nll/renumber.rs | 28 +++++++------------ src/librustc_mir/transform/erase_regions.rs | 26 ++++++----------- src/librustc_mir/transform/inline.rs | 23 +++++++-------- src/librustc_mir/transform/promote_consts.rs | 24 ++++++---------- src/librustc_mir/transform/simplify.rs | 24 ++++++---------- src/librustc_mir/util/def_use.rs | 26 +++++++---------- 7 files changed, 82 insertions(+), 97 deletions(-) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 0fb43c7f98d1..c8a6367899ba 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -786,10 +786,32 @@ macro_rules! visit_place_fns { (mut) => ( fn super_place( &mut self, - _place: &mut Place<'tcx>, - _context: PlaceContext, - _location: Location, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, ) { + self.visit_place_base(&mut place.base, context, location); + + place.projection = self.process_projection(&place.projection); + } + + fn process_projection( + &mut self, + projection: &Box<[PlaceElem<'tcx>]>, + ) -> Box<[PlaceElem<'tcx>]> { + let new_projection: Vec<_> = projection.iter().map(|elem| + self.process_projection_elem(elem) + ).collect(); + + new_projection.into_boxed_slice() + } + + fn process_projection_elem( + &mut self, + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + // FIXME: avoid cloning here + elem.clone() } ); diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 6eb5735cb16b..c4a19ce5128b 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,7 +1,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::mir::{Body, Location, Place, PlaceElem, Promoted}; -use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext}; +use rustc::mir::{Body, Location, PlaceElem, Promoted}; +use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_index::vec::IndexVec; @@ -62,23 +62,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { debug!("visit_ty: ty={:?}", ty); } - fn visit_place( + fn process_projection_elem( &mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - if let PlaceElem::Field(field, ty) = elem { - PlaceElem::Field(*field, self.renumber_regions(ty)) - } else { - elem.clone() - } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + if let PlaceElem::Field(field, ty) = elem { + PlaceElem::Field(*field, self.renumber_regions(ty)) + } else { + elem.clone() + } } fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 132149d5d433..725a8de8fe7d 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -7,7 +7,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext}; +use rustc::mir::visit::{MutVisitor, TyContext}; use crate::transform::{MirPass, MirSource}; struct EraseRegionsVisitor<'tcx> { @@ -39,23 +39,15 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { *substs = self.tcx.erase_regions(substs); } - fn visit_place( + fn process_projection_elem( &mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - if let PlaceElem::Field(field, ty) = elem { - PlaceElem::Field(*field, self.tcx.erase_regions(ty)) - } else { - elem.clone() - } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + if let PlaceElem::Field(field, ty) = elem { + PlaceElem::Field(*field, self.tcx.erase_regions(ty)) + } else { + elem.clone() + } } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 3a71d22da787..dd13d0c96557 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -695,21 +695,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *place = self.destination.clone(); }, _ => { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - if let PlaceElem::Index(local) = elem { - PlaceElem::Index(self.make_integrate_local(local)) - } else { - elem.clone() - } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + self.super_place(place, context, location); } } } + fn process_projection_elem( + &mut self, + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + if let PlaceElem::Index(local) = elem { + PlaceElem::Index(self.make_integrate_local(local)) + } else { + elem.clone() + } + } + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { self.in_cleanup_block = data.is_cleanup; self.super_basic_block_data(block, data); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index d1c79c5ae2ad..565f260546bc 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -405,24 +405,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } - fn visit_place( + fn process_projection_elem( &mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - match elem { - PlaceElem::Index(local) if self.is_temp_kind(*local) => { - PlaceElem::Index(self.promote_temp(*local)) - } - _ => elem.clone(), + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + match elem { + PlaceElem::Index(local) if self.is_temp_kind(*local) => { + PlaceElem::Index(self.promote_temp(*local)) } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + _ => elem.clone(), + } } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 57bc1c8fab96..7dca3e357cc9 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -371,22 +371,14 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { *l = self.map[*l].unwrap(); } - fn visit_place( + fn process_projection_elem( &mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location, - ) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - if let PlaceElem::Index(local) = elem { - PlaceElem::Index(self.map[*local].unwrap()) - } else { - elem.clone() - } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + if let PlaceElem::Index(local) = elem { + PlaceElem::Index(self.map[*local].unwrap()) + } else { + elem.clone() + } } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 5b5f7d83f074..25930df020aa 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,6 +1,6 @@ //! Def-use analysis. -use rustc::mir::{Body, Local, Location, Place, PlaceElem}; +use rustc::mir::{Body, Local, Location, PlaceElem}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc_index::vec::IndexVec; use std::mem; @@ -138,21 +138,15 @@ impl MutVisitor<'_> for MutateUseVisitor { } } - fn visit_place(&mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - match elem { - PlaceElem::Index(local) if *local == self.query => { - PlaceElem::Index(self.new_local) - } - _ => elem.clone(), + fn process_projection_elem( + &mut self, + elem: &PlaceElem<'tcx>, + ) -> PlaceElem<'tcx> { + match elem { + PlaceElem::Index(local) if *local == self.query => { + PlaceElem::Index(self.new_local) } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + _ => elem.clone(), + } } } From d0eaf60d5e4bd0d5be63a41ed9ff861dca95c932 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 16 Oct 2019 09:30:28 +1100 Subject: [PATCH 33/40] Remove two no-op `into()` calls. --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9cb410a8ae31..6bbd8be0cb98 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -285,10 +285,10 @@ impl TokenCursor { token::NoDelim, &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] - .iter().cloned().collect::().into() + .iter().cloned().collect::() } else { [TokenTree::token(token::Pound, sp), body] - .iter().cloned().collect::().into() + .iter().cloned().collect::() }, ))); From a6eef299d3b0ca24f8ffc0c3dc03283c09ec7945 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Oct 2019 10:37:21 +1100 Subject: [PATCH 34/40] Make `TokenStream::from_iter` less general and more efficient. The current code has this impl: ``` impl> iter::FromIterator for TokenStream ``` If given an `IntoIterator`, it will convert each individual `TokenTree` to a `TokenStream` (at the cost of two allocations: a `Vec` and an `Lrc`). It will then merge those `TokenStream`s into a single `TokenStream`. This is inefficient. This commit changes the impl to this less general one: ``` impl iter::FromIterator for TokenStream ``` It collects the `TokenTree`s into a single `Vec` first and then converts that to a `TokenStream` by wrapping it in a single `Lrc`. The previous generality was unnecessary; no other code needs changing. This change speeds up several benchmarks by up to 4%. --- src/libsyntax/tokenstream.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index db6832d64232..3d89e73d729f 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -202,9 +202,9 @@ impl From for TreeAndJoint { } } -impl> iter::FromIterator for TokenStream { - fn from_iter>(iter: I) -> Self { - TokenStream::from_streams(iter.into_iter().map(Into::into).collect::>()) +impl iter::FromIterator for TokenStream { + fn from_iter>(iter: I) -> Self { + TokenStream::new(iter.into_iter().map(Into::into).collect::>()) } } From 212ae58f36e4c9f2e0f46153f1c50a657e6c25db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Oct 2019 11:24:46 +1100 Subject: [PATCH 35/40] Change `Lit::tokens()` to `Lit::token_tree()`. Because most of the call sites have an easier time working with a `TokenTree` instead of a `TokenStream`. --- src/libsyntax/attr/mod.rs | 9 +++++---- src/libsyntax/parse/literal.rs | 8 ++++---- src/libsyntax/parse/parser/attr.rs | 9 ++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 402c2cad72f9..8786c850bfdd 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -541,9 +541,10 @@ impl MetaItemKind { match *self { MetaItemKind::Word => TokenStream::default(), MetaItemKind::NameValue(ref lit) => { - let mut vec = vec![TokenTree::token(token::Eq, span).into()]; - lit.tokens().append_to_tree_and_joint_vec(&mut vec); - TokenStream::new(vec) + TokenStream::new(vec![ + TokenTree::token(token::Eq, span).into(), + lit.token_tree().into(), + ]) } MetaItemKind::List(ref list) => { let mut tokens = Vec::new(); @@ -606,7 +607,7 @@ impl NestedMetaItem { fn tokens(&self) -> TokenStream { match *self { NestedMetaItem::MetaItem(ref item) => item.tokens(), - NestedMetaItem::Literal(ref lit) => lit.tokens(), + NestedMetaItem::Literal(ref lit) => lit.token_tree().into(), } } diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 14e1696610a4..7952e293a532 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -3,7 +3,7 @@ use crate::ast::{self, Lit, LitKind}; use crate::parse::token::{self, Token}; use crate::symbol::{kw, sym, Symbol}; -use crate::tokenstream::{TokenStream, TokenTree}; +use crate::tokenstream::TokenTree; use log::debug; use rustc_data_structures::sync::Lrc; @@ -216,13 +216,13 @@ impl Lit { Lit { token: kind.to_lit_token(), kind, span } } - /// Losslessly convert an AST literal into a token stream. - crate fn tokens(&self) -> TokenStream { + /// Losslessly convert an AST literal into a token tree. + crate fn token_tree(&self) -> TokenTree { let token = match self.token.kind { token::Bool => token::Ident(self.token.symbol, false), _ => token::Literal(self.token), }; - TokenTree::token(token, self.span).into() + TokenTree::token(token, self.span) } } diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 6f7d1ead4c17..188a144cac9d 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -6,7 +6,6 @@ use crate::tokenstream::{TokenStream, TokenTree}; use crate::source_map::Span; use log::debug; -use smallvec::smallvec; #[derive(Debug)] enum InnerAttributeParsePolicy<'a> { @@ -193,15 +192,15 @@ impl<'a> Parser<'a> { is_interpolated_expr = true; } } - let tokens = if is_interpolated_expr { + let token_tree = if is_interpolated_expr { // We need to accept arbitrary interpolated expressions to continue // supporting things like `doc = $expr` that work on stable. // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree().into() + self.parse_token_tree() } else { - self.parse_unsuffixed_lit()?.tokens() + self.parse_unsuffixed_lit()?.token_tree() }; - TokenStream::from_streams(smallvec![eq.into(), tokens]) + TokenStream::new(vec![eq.into(), token_tree.into()]) } else { TokenStream::default() }; From e4ec4a6da350ae2564971ae826a1bc3ec9a41988 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Oct 2019 14:06:00 +1100 Subject: [PATCH 36/40] Change `MetaItem::tokens()` to `MetaItem::token_trees_and_joints()`. Likewise for `NestedMetaItem::tokens()`. Also, add `MetaItemKind::token_trees_and_joints()`, which `MetaItemKind::tokens()` now calls. This avoids some unnecessary `TokenTree` to `TokenStream` conversions, and removes the need for the clumsy `TokenStream::append_to_tree_and_joint_vec()`. --- src/libsyntax/attr/mod.rs | 43 ++++++++++++++++++++++-------------- src/libsyntax/tokenstream.rs | 4 ---- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 8786c850bfdd..4aec50408812 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -22,7 +22,7 @@ use crate::ptr::P; use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::ThinVec; -use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; +use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use crate::GLOBALS; use log::debug; @@ -463,7 +463,7 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option } impl MetaItem { - fn tokens(&self) -> TokenStream { + fn token_trees_and_joints(&self) -> Vec { let mut idents = vec![]; let mut last_pos = BytePos(0 as u32); for (i, segment) in self.path.segments.iter().enumerate() { @@ -477,8 +477,8 @@ impl MetaItem { idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } - self.kind.tokens(self.span).append_to_tree_and_joint_vec(&mut idents); - TokenStream::new(idents) + idents.extend(self.kind.token_trees_and_joints(self.span)); + idents } fn from_tokens(tokens: &mut iter::Peekable) -> Option @@ -537,14 +537,14 @@ impl MetaItem { } impl MetaItemKind { - pub fn tokens(&self, span: Span) -> TokenStream { + pub fn token_trees_and_joints(&self, span: Span) -> Vec { match *self { - MetaItemKind::Word => TokenStream::default(), + MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { - TokenStream::new(vec![ + vec![ TokenTree::token(token::Eq, span).into(), lit.token_tree().into(), - ]) + ] } MetaItemKind::List(ref list) => { let mut tokens = Vec::new(); @@ -552,17 +552,26 @@ impl MetaItemKind { if i > 0 { tokens.push(TokenTree::token(token::Comma, span).into()); } - item.tokens().append_to_tree_and_joint_vec(&mut tokens); + tokens.extend(item.token_trees_and_joints()) } - TokenTree::Delimited( - DelimSpan::from_single(span), - token::Paren, - TokenStream::new(tokens).into(), - ).into() + vec![ + TokenTree::Delimited( + DelimSpan::from_single(span), + token::Paren, + TokenStream::new(tokens).into(), + ).into() + ] } } } + // Premature conversions of `TokenTree`s to `TokenStream`s can hurt + // performance. Do not use this function if `token_trees_and_joints()` can + // be used instead. + pub fn tokens(&self, span: Span) -> TokenStream { + TokenStream::new(self.token_trees_and_joints(span)) + } + fn from_tokens(tokens: &mut iter::Peekable) -> Option where I: Iterator, { @@ -604,10 +613,10 @@ impl NestedMetaItem { } } - fn tokens(&self) -> TokenStream { + fn token_trees_and_joints(&self) -> Vec { match *self { - NestedMetaItem::MetaItem(ref item) => item.tokens(), - NestedMetaItem::Literal(ref lit) => lit.token_tree().into(), + NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(), + NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()], } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 3d89e73d729f..ac155556cdae 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -271,10 +271,6 @@ impl TokenStream { } } - pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec) { - vec.extend(self.0.iter().cloned()); - } - pub fn trees(&self) -> Cursor { self.clone().into_trees() } From 769e75b40c53b5113e8206b70692fef8846de77a Mon Sep 17 00:00:00 2001 From: Tobias Rapp Date: Fri, 18 Oct 2019 08:29:18 +0200 Subject: [PATCH 37/40] Fix left/right shift typo in wrapping rotate docs This makes the note similar to the one found on rotate functions for primitive types like i32/u32. --- src/libcore/num/wrapping.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 59a10ae99bb6..5fe9895d8d24 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -437,7 +437,7 @@ assert_eq!(n.trailing_zeros(), 3); /// wrapping the truncated bits to the end of the resulting /// integer. /// - /// Please note this isn't the same operation as the `>>` shifting + /// Please note this isn't the same operation as the `<<` shifting /// operator! /// /// # Examples @@ -463,7 +463,7 @@ assert_eq!(n.trailing_zeros(), 3); /// wrapping the truncated bits to the beginning of the resulting /// integer. /// - /// Please note this isn't the same operation as the `<<` shifting + /// Please note this isn't the same operation as the `>>` shifting /// operator! /// /// # Examples From 4e3f4ca517c5c790944860d775f2ad2c720e0b3e Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Fri, 18 Oct 2019 10:58:05 +0200 Subject: [PATCH 38/40] Update error_codes.rs --- src/librustc_resolve/error_codes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 23bea5196d71..5cdf3c3fdf46 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -26,7 +26,7 @@ struct Foo { } ``` -Please also verify \hat this wasn't because of a name-clash and rename the type +Please also verify that this wasn't because of a name-clash and rename the type parameter if so. "##, From 9617014aa6c1d95bf4f59fc333b10f6b33dbe1ee Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Oct 2019 18:15:16 +0900 Subject: [PATCH 39/40] Clarify diagnostics when using `~` as a unary op --- src/libsyntax/parse/parser/expr.rs | 2 +- .../issue-41679-tilde-bitwise-negation-attempt.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 273f5a5ffa36..67a530ec6831 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -423,7 +423,7 @@ impl<'a> Parser<'a> { self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator") .span_suggestion_short( span_of_tilde, - "use `!` to perform bitwise negation", + "use `!` to perform bitwise not", "!".to_owned(), Applicability::MachineApplicable ) diff --git a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr index 84235ca4d637..79bc7d2565be 100644 --- a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr +++ b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr @@ -2,7 +2,7 @@ error: `~` cannot be used as a unary operator --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:2:13 | LL | let x = ~1; - | ^ help: use `!` to perform bitwise negation + | ^ help: use `!` to perform bitwise not error: aborting due to previous error From 48349960e68a9d19b17ac54cd12e939a9a46ea7d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 8 Oct 2019 23:46:14 -0300 Subject: [PATCH 40/40] Use Cow to handle modifications of projection in preparation for interning --- src/librustc/mir/visit.rs | 33 ++++++++++++------- src/librustc_mir/borrow_check/nll/renumber.rs | 12 ++++--- src/librustc_mir/transform/erase_regions.rs | 12 ++++--- src/librustc_mir/transform/generator.rs | 24 +++++--------- src/librustc_mir/transform/inline.rs | 12 ++++--- src/librustc_mir/transform/promote_consts.rs | 6 ++-- src/librustc_mir/transform/simplify.rs | 11 ++++--- src/librustc_mir/util/def_use.rs | 6 ++-- 8 files changed, 67 insertions(+), 49 deletions(-) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c8a6367899ba..fef406e89878 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -792,26 +792,37 @@ macro_rules! visit_place_fns { ) { self.visit_place_base(&mut place.base, context, location); - place.projection = self.process_projection(&place.projection); + if let Some(new_projection) = self.process_projection(&place.projection) { + place.projection = new_projection; + } } fn process_projection( &mut self, - projection: &Box<[PlaceElem<'tcx>]>, - ) -> Box<[PlaceElem<'tcx>]> { - let new_projection: Vec<_> = projection.iter().map(|elem| - self.process_projection_elem(elem) - ).collect(); + projection: &'a [PlaceElem<'tcx>], + ) -> Option]>> { + let mut projection = Cow::Borrowed(projection); + + for i in 0..projection.len() { + if let Some(elem) = projection.get(i) { + if let Some(elem) = self.process_projection_elem(elem) { + let vec = projection.to_mut(); + vec[i] = elem; + } + } + } - new_projection.into_boxed_slice() + match projection { + Cow::Borrowed(_) => None, + Cow::Owned(vec) => Some(vec.into_boxed_slice()), + } } fn process_projection_elem( &mut self, - elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { - // FIXME: avoid cloning here - elem.clone() + _elem: &PlaceElem<'tcx>, + ) -> Option> { + None } ); diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index c4a19ce5128b..9ecd6f837750 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -65,12 +65,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { + ) -> Option> { if let PlaceElem::Field(field, ty) = elem { - PlaceElem::Field(*field, self.renumber_regions(ty)) - } else { - elem.clone() + let new_ty = self.renumber_regions(ty); + + if new_ty != *ty { + return Some(PlaceElem::Field(*field, new_ty)); + } } + + None } fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 725a8de8fe7d..439cae2093ae 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -42,12 +42,16 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { + ) -> Option> { if let PlaceElem::Field(field, ty) = elem { - PlaceElem::Field(*field, self.tcx.erase_regions(ty)) - } else { - elem.clone() + let new_ty = self.tcx.erase_regions(ty); + + if new_ty != *ty { + return Some(PlaceElem::Field(*field, new_ty)); + } } + + None } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index a801548efab0..6533e3c5ba81 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -89,22 +89,16 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { } } - fn visit_place(&mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location) { - self.visit_place_base(&mut place.base, context, location); - - let new_projection: Vec<_> = place.projection.iter().map(|elem| - match elem { - PlaceElem::Index(local) if *local == self.from => { - PlaceElem::Index(self.to) - } - _ => elem.clone(), + fn process_projection_elem( + &mut self, + elem: &PlaceElem<'tcx>, + ) -> Option> { + match elem { + PlaceElem::Index(local) if *local == self.from => { + Some(PlaceElem::Index(self.to)) } - ).collect(); - - place.projection = new_projection.into_boxed_slice(); + _ => None, + } } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index dd13d0c96557..0cbdcedff478 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -703,12 +703,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { + ) -> Option> { if let PlaceElem::Index(local) = elem { - PlaceElem::Index(self.make_integrate_local(local)) - } else { - elem.clone() + let new_local = self.make_integrate_local(local); + + if new_local != *local { + return Some(PlaceElem::Index(new_local)) + } } + + None } fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 565f260546bc..ad1785417cd9 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -408,12 +408,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { + ) -> Option> { match elem { PlaceElem::Index(local) if self.is_temp_kind(*local) => { - PlaceElem::Index(self.promote_temp(*local)) + Some(PlaceElem::Index(self.promote_temp(*local))) } - _ => elem.clone(), + _ => None, } } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 7dca3e357cc9..606c1a3a1cc0 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -374,11 +374,12 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { - if let PlaceElem::Index(local) = elem { - PlaceElem::Index(self.map[*local].unwrap()) - } else { - elem.clone() + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + Some(PlaceElem::Index(self.map[*local].unwrap())) + } + _ => None } } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 25930df020aa..cdd07ad4b8ff 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -141,12 +141,12 @@ impl MutVisitor<'_> for MutateUseVisitor { fn process_projection_elem( &mut self, elem: &PlaceElem<'tcx>, - ) -> PlaceElem<'tcx> { + ) -> Option> { match elem { PlaceElem::Index(local) if *local == self.query => { - PlaceElem::Index(self.new_local) + Some(PlaceElem::Index(self.new_local)) } - _ => elem.clone(), + _ => None, } } }