From 9ef90158f760a3c80fd0f5cc2ecfb2feabb6adc9 Mon Sep 17 00:00:00 2001 From: PirateDragon Date: Wed, 11 Dec 2019 14:29:47 +0800 Subject: [PATCH 01/47] Improve Style Used Self for uniform style --- src/libcore/task/wake.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 0759ff93ea85f..277df332b4ad5 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -39,8 +39,8 @@ impl RawWaker { /// function in the `vtable` of the underlying `RawWaker` will be called. #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] - pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { - RawWaker { data, vtable } + pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self { + Self { data, vtable } } } @@ -180,7 +180,7 @@ impl<'a> Context<'a> { #[stable(feature = "futures_api", since = "1.36.0")] #[inline] pub fn from_waker(waker: &'a Waker) -> Self { - Context { waker, _marker: PhantomData } + Self { waker, _marker: PhantomData } } /// Returns a reference to the `Waker` for the current task. @@ -277,8 +277,8 @@ impl Waker { /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] - pub unsafe fn from_raw(waker: RawWaker) -> Waker { - Waker { waker } + pub unsafe fn from_raw(waker: RawWaker) -> Self { + Self { waker } } } @@ -286,7 +286,7 @@ impl Waker { impl Clone for Waker { #[inline] fn clone(&self) -> Self { - Waker { + Self { // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `clone` and `data` requiring the user to acknowledge // that the contract of [`RawWaker`] is upheld. From b45e03ce04acb07e7494741cfb749545ab83c62f Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Mon, 8 Jul 2019 21:34:36 -0700 Subject: [PATCH 02/47] Clarify `Box` representation and its use in FFI This officializes what was only shown as a code example in [the unsafe code guidelines](https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html?highlight=box#use) and follows [the discussion](https://github.com/rust-lang/unsafe-code-guidelines/issues/157) in the corresponding repository. It is also related to [the issue](https://github.com/rust-lang/rust/issues/52976) regarding marking `Box` `#[repr(transparent)]`. --- src/liballoc/boxed.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 51ad3a04e87fe..7cd449bf561d0 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -61,6 +61,28 @@ //! T` obtained from [`Box::::into_raw`] may be deallocated using the //! [`Global`] allocator with [`Layout::for_value(&*value)`]. //! +//! `Box` has the same representation as `*mut T`. In particular, when +//! `T: Sized`, this means that `Box` has the same representation as +//! a C pointer, making the following code valid in FFI: +//! +//! ```c +//! /* C header */ +//! struct Foo* foo(); /* Returns ownership */ +//! void bar(struct Foo*); /* `bar` takes ownership */ +//! ``` +//! +//! ``` +//! #[repr(C)] +//! pub struct Foo; +//! +//! #[no_mangle] +//! pub extern "C" fn foo() -> Box { +//! Box::new(Foo) +//! } +//! +//! #[no_mangle] +//! pub extern "C" fn bar(_: Option>) {} +//! ``` //! //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html From f39b86479b8650d212f0f88702b531688b09dc0c Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Sun, 25 Aug 2019 23:25:56 -0700 Subject: [PATCH 03/47] Update Box representation comment based on reviews --- src/liballoc/boxed.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 7cd449bf561d0..44890d37c102c 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -61,9 +61,8 @@ //! T` obtained from [`Box::::into_raw`] may be deallocated using the //! [`Global`] allocator with [`Layout::for_value(&*value)`]. //! -//! `Box` has the same representation as `*mut T`. In particular, when -//! `T: Sized`, this means that `Box` has the same representation as -//! a C pointer, making the following code valid in FFI: +//! `Box` has the same ABI as `&mut T`. In particular, when `T: Sized`, +//! this allows using `Box` in FFI: //! //! ```c //! /* C header */ From 1ce980e5418c09a45fcad986a4f03e42730745c7 Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Wed, 30 Oct 2019 09:43:04 -0700 Subject: [PATCH 04/47] Update FFI example - Use meaningful names - Clarify comments - Fix C function declaration --- src/liballoc/boxed.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 44890d37c102c..cea96f65ada62 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,8 +66,8 @@ //! //! ```c //! /* C header */ -//! struct Foo* foo(); /* Returns ownership */ -//! void bar(struct Foo*); /* `bar` takes ownership */ +//! struct Foo* foo_new(void); /* Returns ownership to the caller */ +//! void foo_delete(struct Foo*); /* Takes ownership from the caller */ //! ``` //! //! ``` @@ -75,12 +75,12 @@ //! pub struct Foo; //! //! #[no_mangle] -//! pub extern "C" fn foo() -> Box { +//! pub extern "C" fn foo_new() -> Box { //! Box::new(Foo) //! } //! //! #[no_mangle] -//! pub extern "C" fn bar(_: Option>) {} +//! pub extern "C" fn foo_delete(_: Option>) {} //! ``` //! //! [dereferencing]: ../../std/ops/trait.Deref.html From c404b4ce6e2302dc181ccaa576f300b4c99d22cc Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Fri, 29 Nov 2019 15:22:44 -0700 Subject: [PATCH 05/47] Optimize Ord trait implementation for bool Casting the booleans to `i8`s and converting their difference into `Ordering` generates better assembly than casting them to `u8`s and comparing them. --- src/libcore/cmp.rs | 11 ++++++++++- src/libcore/tests/cmp.rs | 8 ++++++++ src/test/codegen/bool-cmp.rs | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/bool-cmp.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index a5f355cd9a73e..f81f297ef07a7 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1005,6 +1005,7 @@ pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { + use crate::hint::unreachable_unchecked; use crate::cmp::Ordering::{self, Less, Greater, Equal}; macro_rules! partial_eq_impl { @@ -1125,7 +1126,15 @@ mod impls { impl Ord for bool { #[inline] fn cmp(&self, other: &bool) -> Ordering { - (*self as u8).cmp(&(*other as u8)) + // Casting to i8's and converting the difference to an Ordering generates + // more optimal assembly. + // See for more info. + match (*self as i8) - (*other as i8) { + -1 => Less, + 0 => Equal, + 1 => Greater, + _ => unsafe { unreachable_unchecked() }, + } } } diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs index 5e6778e222a29..56a2f4acf6eaa 100644 --- a/src/libcore/tests/cmp.rs +++ b/src/libcore/tests/cmp.rs @@ -9,6 +9,14 @@ fn test_int_totalord() { assert_eq!(12.cmp(&-5), Greater); } +#[test] +fn test_bool_totalord() { + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); +} + #[test] fn test_mut_int_totalord() { assert_eq!((&mut 5).cmp(&&mut 10), Less); diff --git a/src/test/codegen/bool-cmp.rs b/src/test/codegen/bool-cmp.rs new file mode 100644 index 0000000000000..8769a4cb5e189 --- /dev/null +++ b/src/test/codegen/bool-cmp.rs @@ -0,0 +1,17 @@ +// This is a test for optimal Ord trait implementation for bool. +// See for more info. + +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +// CHECK-LABEL: @cmp_bool +#[no_mangle] +pub fn cmp_bool(a: bool, b: bool) -> Ordering { +// CHECK: zext i1 +// CHECK: zext i1 +// CHECK: sub nsw + a.cmp(&b) +} From 2845b5559450baadf7852639abd71b696f9deddc Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Mon, 2 Dec 2019 08:45:35 -0700 Subject: [PATCH 06/47] Document usage of unsafe block --- src/libcore/cmp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f81f297ef07a7..26616a2d18bae 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1133,6 +1133,7 @@ mod impls { -1 => Less, 0 => Equal, 1 => Greater, + // SAFETY: Unreachable code _ => unsafe { unreachable_unchecked() }, } } From 69a2249b25eaf54b8e4e0fdde7912e10658b1fdf Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 21:12:19 +0200 Subject: [PATCH 07/47] rustc: include ParamEnv in global trait select/eval cache keys. --- src/librustc/traits/project.rs | 10 +++----- src/librustc/traits/select.rs | 25 +++++++++++-------- .../type-alias-impl-trait/bound_reduction2.rs | 1 + .../bound_reduction2.stderr | 14 +++++++++-- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index c345b9a969c90..1fdec5f015251 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1079,12 +1079,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( if !is_default { true } else if obligation.param_env.reveal == Reveal::All { - debug_assert!(!poly_trait_ref.needs_infer()); - if !poly_trait_ref.needs_subst() { - true - } else { - false - } + // NOTE(eddyb) inference variables can resolve to parameters, so + // assume `poly_trait_ref` isn't monomorphic, if it contains any. + let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); + !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() } else { false } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 5f324527a2725..4e172f50b8f2d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -204,7 +204,10 @@ struct TraitObligationStack<'prev, 'tcx> { #[derive(Clone, Default)] pub struct SelectionCache<'tcx> { hashmap: Lock< - FxHashMap, WithDepNode>>>, + FxHashMap< + ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, + WithDepNode>>, + >, >, } @@ -490,7 +493,9 @@ impl<'tcx> From for SelectionError<'tcx> { #[derive(Clone, Default)] pub struct EvaluationCache<'tcx> { - hashmap: Lock, WithDepNode>>, + hashmap: Lock< + FxHashMap>, WithDepNode>, + >, } impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -1143,7 +1148,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); if self.can_use_global_caches(param_env) { let cache = tcx.evaluation_cache.hashmap.borrow(); - if let Some(cached) = cache.get(&trait_ref) { + if let Some(cached) = cache.get(¶m_env.and(trait_ref)) { return Some(cached.get(tcx)); } } @@ -1151,7 +1156,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .evaluation_cache .hashmap .borrow() - .get(&trait_ref) + .get(¶m_env.and(trait_ref)) .map(|v| v.get(tcx)) } @@ -1182,7 +1187,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .evaluation_cache .hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, result)); + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); return; } } @@ -1195,7 +1200,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .evaluation_cache .hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, result)); + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); } /// For various reasons, it's possible for a subobligation @@ -1602,7 +1607,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; if self.can_use_global_caches(param_env) { let cache = tcx.selection_cache.hashmap.borrow(); - if let Some(cached) = cache.get(&trait_ref) { + if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) { return Some(cached.get(tcx)); } } @@ -1610,7 +1615,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .selection_cache .hashmap .borrow() - .get(trait_ref) + .get(¶m_env.and(*trait_ref)) .map(|v| v.get(tcx)) } @@ -1671,7 +1676,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx.selection_cache .hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, candidate)); + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); return; } } @@ -1685,7 +1690,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .selection_cache .hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, candidate)); + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); } fn assemble_candidates<'o>( diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index 919446877a142..1becb1e83a5ac 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -9,6 +9,7 @@ trait TraitWithAssoc { type Foo = impl Trait; //~^ ERROR could not find defining uses +//~| ERROR the trait bound `T: TraitWithAssoc` is not satisfied trait Trait {} diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index bb22d582f2167..1eb4cf2a80255 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,5 +1,14 @@ +error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied + --> $DIR/bound_reduction2.rs:10:1 + | +LL | type Foo = impl Trait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` +... +LL | fn foo_desugared(_: T) -> Foo { + | -- help: consider further restricting this bound: `T: TraitWithAssoc +` + error: defining opaque type use does not fully define opaque type: generic parameter `V` is specified as concrete type `::Assoc` - --> $DIR/bound_reduction2.rs:17:1 + --> $DIR/bound_reduction2.rs:18:1 | LL | / fn foo_desugared(_: T) -> Foo { LL | | () @@ -12,5 +21,6 @@ error: could not find defining uses LL | type Foo = impl Trait; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0277`. From e05236b20919abf4b87b1cf1b8f424c02cb7bf52 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 2 Dec 2019 17:44:16 +0200 Subject: [PATCH 08/47] rustc: allow non-empty ParamEnv's in global trait select/eval caches. --- src/librustc/traits/select.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4e172f50b8f2d..94a77c553e53a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1572,14 +1572,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Do note that if the type itself is not in the /// global tcx, the local caches will be used. fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { - // If there are any where-clauses in scope, then we always use - // a cache local to this particular scope. Otherwise, we - // switch to a global cache. We used to try and draw - // finer-grained distinctions, but that led to a serious of - // annoying and weird bugs like #22019 and #18290. This simple - // rule seems to be pretty clearly safe and also still retains - // a very high hit rate (~95% when compiling rustc). - if !param_env.caller_bounds.is_empty() { + // If there are any e.g. inference variables in the `ParamEnv`, then we + // always use a cache local to this particular scope. Otherwise, we + // switch to a global cache. + if param_env.has_local_value() { return false; } From eac3b0ad2dca1934c3317c4671942c47fba6a3c3 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 3 Dec 2019 12:35:09 +0100 Subject: [PATCH 09/47] Fix #66295 --- src/librustc_lint/unused.rs | 8 +++++-- src/test/ui/lint/lint-unnecessary-parens.rs | 9 ++++++++ .../ui/lint/lint-unnecessary-parens.stderr | 22 +++++++++---------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f7de7ec7e18f4..25c351f623488 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -17,7 +17,7 @@ use syntax::print::pprust; use syntax::symbol::{kw, sym}; use syntax::symbol::Symbol; use syntax::util::parser; -use syntax_pos::{Span, BytePos}; +use syntax_pos::{MultiSpan, Span, BytePos}; use log::debug; @@ -355,7 +355,11 @@ impl UnusedParens { match value.kind { ast::ExprKind::Paren(ref inner) => { if !Self::is_expr_parens_necessary(inner, followed_by_block) && - value.attrs.is_empty() { + value.attrs.is_empty() && + !MultiSpan::from(value.span).primary_span() + .map(|span| span.from_expansion()) + .unwrap_or(false) + { let expr_text = if let Ok(snippet) = cx.sess().source_map() .span_to_snippet(value.span) { snippet diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs index 9f42b855a870d..12ffb6d3c6655 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.rs +++ b/src/test/ui/lint/lint-unnecessary-parens.rs @@ -25,6 +25,12 @@ fn passes_unused_parens_lint() -> &'static (dyn Trait) { panic!() } +macro_rules! baz { + ($($foo:expr),+) => { + ($($foo),*) + } +} + fn main() { foo(); bar((true)); //~ ERROR unnecessary parentheses around function argument @@ -55,4 +61,7 @@ fn main() { let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value _a = (0); //~ ERROR unnecessary parentheses around assigned value _a += (1); //~ ERROR unnecessary parentheses around assigned value + + let _a = baz!(3, 4); + let _b = baz!(3); } diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr index adc1069b64d62..541ae7aa4b54a 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.stderr +++ b/src/test/ui/lint/lint-unnecessary-parens.stderr @@ -23,25 +23,25 @@ LL | fn unused_parens_around_return_type() -> (u32) { | ^^^^^ help: remove these parentheses error: unnecessary parentheses around function argument - --> $DIR/lint-unnecessary-parens.rs:30:9 + --> $DIR/lint-unnecessary-parens.rs:36:9 | LL | bar((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:32:8 + --> $DIR/lint-unnecessary-parens.rs:38:8 | LL | if (true) {} | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:33:11 + --> $DIR/lint-unnecessary-parens.rs:39:11 | LL | while (true) {} | ^^^^^^ help: remove these parentheses warning: denote infinite loops with `loop { ... }` - --> $DIR/lint-unnecessary-parens.rs:33:5 + --> $DIR/lint-unnecessary-parens.rs:39:5 | LL | while (true) {} | ^^^^^^^^^^^^ help: use `loop` @@ -49,43 +49,43 @@ LL | while (true) {} = note: `#[warn(while_true)]` on by default error: unnecessary parentheses around `match` head expression - --> $DIR/lint-unnecessary-parens.rs:35:11 + --> $DIR/lint-unnecessary-parens.rs:41:11 | LL | match (true) { | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `let` head expression - --> $DIR/lint-unnecessary-parens.rs:38:16 + --> $DIR/lint-unnecessary-parens.rs:44:16 | LL | if let 1 = (1) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around `let` head expression - --> $DIR/lint-unnecessary-parens.rs:39:19 + --> $DIR/lint-unnecessary-parens.rs:45:19 | LL | while let 1 = (2) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:53:24 + --> $DIR/lint-unnecessary-parens.rs:59:24 | LL | X { y: false }.foo((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:55:18 + --> $DIR/lint-unnecessary-parens.rs:61:18 | LL | let mut _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:56:10 + --> $DIR/lint-unnecessary-parens.rs:62:10 | LL | _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:57:11 + --> $DIR/lint-unnecessary-parens.rs:63:11 | LL | _a += (1); | ^^^ help: remove these parentheses From dcd0468768745edb963f5c82c8816e4d4a2df673 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 3 Dec 2019 14:07:45 +0000 Subject: [PATCH 10/47] Apply suggestions from code review Co-Authored-By: lzutao --- src/librustc_lint/unused.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 25c351f623488..ee644acd09974 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -357,8 +357,7 @@ impl UnusedParens { if !Self::is_expr_parens_necessary(inner, followed_by_block) && value.attrs.is_empty() && !MultiSpan::from(value.span).primary_span() - .map(|span| span.from_expansion()) - .unwrap_or(false) + .map_or(false, |span| span.from_expansion()) { let expr_text = if let Ok(snippet) = cx.sess().source_map() .span_to_snippet(value.span) { From 5d320c632c45613f0f69976c8af544ec459bcacc Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 6 Dec 2019 15:09:01 +0100 Subject: [PATCH 11/47] Remove failing test case --- ...e-47775-nested-macro-unnecessary-parens-arg.rs | 3 --- ...775-nested-macro-unnecessary-parens-arg.stderr | 15 --------------- 2 files changed, 18 deletions(-) delete mode 100644 src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs index ab9baa79b8b77..0a951cfa91c58 100644 --- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs +++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs @@ -17,10 +17,7 @@ macro_rules! the_worship_the_heart_lifts_above { macro_rules! and_the_heavens_reject_not { () => { - // ↓ But let's test that we still lint for unused parens around - // function args inside of simple, one-deep macros. #[allow(dead_code)] fn the_night_for_the_morrow() -> Option { Some((2)) } - //~^ WARN unnecessary parentheses around function argument } } diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr deleted file mode 100644 index 57cdcd70e9db4..0000000000000 --- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr +++ /dev/null @@ -1,15 +0,0 @@ -warning: unnecessary parentheses around function argument - --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:22:83 - | -LL | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option { Some((2)) } - | ^^^ help: remove these parentheses -... -LL | and_the_heavens_reject_not!(); - | ------------------------------ in this macro invocation - | -note: lint level defined here - --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:3:9 - | -LL | #![warn(unused_parens)] - | ^^^^^^^^^^^^^ - From c14ad54e8486b5b7d4c126f0f1086a170e870e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Thu, 5 Dec 2019 10:40:24 +0300 Subject: [PATCH 12/47] const-prop: Restrict scalar pair propagation We now only propagate a scalar pair if the Rvalue is a tuple with two scalars. This for example avoids propagating a (u8, u8) value when Rvalue has type `((), u8, u8)` (see the regression test). While this is a correct thing to do, implementation is tricky and will be done later. Fixes #66971 Fixes #66339 Fixes #67019 --- src/librustc_mir/transform/const_prop.rs | 48 +++++++++++++++++----- src/librustc_target/abi/mod.rs | 8 ++++ src/test/mir-opt/const_prop/issue-66971.rs | 38 +++++++++++++++++ src/test/mir-opt/const_prop/issue-67019.rs | 34 +++++++++++++++ src/test/ui/mir/issue66339.rs | 13 ++++++ 5 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 src/test/mir-opt/const_prop/issue-66971.rs create mode 100644 src/test/mir-opt/const_prop/issue-67019.rs create mode 100644 src/test/ui/mir/issue66339.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 884312514e47e..aff91ac5af910 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -636,19 +636,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ScalarMaybeUndef::Scalar(one), ScalarMaybeUndef::Scalar(two) ) => { + // Found a value represented as a pair. For now only do cont-prop if type of + // Rvalue is also a pair with two scalars. The more general case is more + // complicated to implement so we'll do it later. let ty = &value.layout.ty.kind; + // Only do it for tuples if let ty::Tuple(substs) = ty { - *rval = Rvalue::Aggregate( - Box::new(AggregateKind::Tuple), - vec![ - self.operand_from_scalar( - one, substs[0].expect_ty(), source_info.span - ), - self.operand_from_scalar( - two, substs[1].expect_ty(), source_info.span - ), - ], - ); + // Only do it if tuple is also a pair with two scalars + if substs.len() == 2 { + let opt_ty1_ty2 = self.use_ecx(source_info, |this| { + let ty1 = substs[0].expect_ty(); + let ty2 = substs[1].expect_ty(); + let ty_is_scalar = |ty| { + this.ecx + .layout_of(ty) + .ok() + .map(|ty| ty.details.abi.is_scalar()) + == Some(true) + }; + if ty_is_scalar(ty1) && ty_is_scalar(ty2) { + Ok(Some((ty1, ty2))) + } else { + Ok(None) + } + }); + + if let Some(Some((ty1, ty2))) = opt_ty1_ty2 { + *rval = Rvalue::Aggregate( + Box::new(AggregateKind::Tuple), + vec![ + self.operand_from_scalar( + one, ty1, source_info.span + ), + self.operand_from_scalar( + two, ty2, source_info.span + ), + ], + ); + } + } } }, _ => { } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index ac781819cc35e..b0bc052929768 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -802,6 +802,14 @@ impl Abi { _ => false, } } + + /// Returns `true` is this is a scalar type + pub fn is_scalar(&self) -> bool { + match *self { + Abi::Scalar(_) => true, + _ => false, + } + } } rustc_index::newtype_index! { diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs new file mode 100644 index 0000000000000..30c75303b3e53 --- /dev/null +++ b/src/test/mir-opt/const_prop/issue-66971.rs @@ -0,0 +1,38 @@ +// compile-flags: -Z mir-opt-level=2 + +// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected +// outputs below, after ConstProp this is how _2 would look like with the bug: +// +// _2 = (const Scalar(0x00) : (), const 0u8); +// +// Which has the wrong type. + +fn encode(this: ((), u8, u8)) { + assert!(this.2 == 0); +} + +fn main() { + encode(((), 0, 0)); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = (); +// _2 = (move _3, const 0u8, const 0u8); +// ... +// _1 = const encode(move _2) -> bb1; +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = const Scalar() : (); +// _2 = (move _3, const 0u8, const 0u8); +// ... +// _1 = const encode(move _2) -> bb1; +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs new file mode 100644 index 0000000000000..c6d753a1209cd --- /dev/null +++ b/src/test/mir-opt/const_prop/issue-67019.rs @@ -0,0 +1,34 @@ +// compile-flags: -Z mir-opt-level=2 + +// This used to ICE in const-prop + +fn test(this: ((u8, u8),)) { + assert!((this.0).0 == 1); +} + +fn main() { + test(((1, 2),)); +} + +// Important bit is parameter passing so we only check that below +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = (const 1u8, const 2u8); +// _2 = (move _3,); +// ... +// _1 = const test(move _2) -> bb1; +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = (const 1u8, const 2u8); +// _2 = (move _3,); +// ... +// _1 = const test(move _2) -> bb1; +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/ui/mir/issue66339.rs b/src/test/ui/mir/issue66339.rs new file mode 100644 index 0000000000000..98e178c055146 --- /dev/null +++ b/src/test/ui/mir/issue66339.rs @@ -0,0 +1,13 @@ +// compile-flags: -Z mir-opt-level=2 +// build-pass + +// This used to ICE in const-prop + +fn foo() { + let bar = |_| { }; + let _ = bar("a"); +} + +fn main() { + foo(); +} From 6e4788a91afc11255c50e434685d220c93d0891b Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 6 Oct 2019 23:14:34 +0100 Subject: [PATCH 13/47] async/await: more improvements to non-send errors Signed-off-by: David Wood --- src/libcore/marker.rs | 2 + src/librustc/traits/error_reporting.rs | 294 +++++++++++++----- src/librustc_errors/diagnostic.rs | 10 + src/libstd/future.rs | 1 - src/libsyntax_pos/symbol.rs | 2 + src/test/ui/async-await/async-fn-nonsend.rs | 8 +- .../ui/async-await/async-fn-nonsend.stderr | 91 +++--- src/test/ui/async-await/issue-64130-1-sync.rs | 23 ++ .../ui/async-await/issue-64130-1-sync.stderr | 22 ++ src/test/ui/async-await/issue-64130-2-send.rs | 23 ++ .../ui/async-await/issue-64130-2-send.stderr | 22 ++ .../ui/async-await/issue-64130-3-other.rs | 25 ++ .../ui/async-await/issue-64130-3-other.stderr | 24 ++ .../async-await/issue-64130-4-async-move.rs | 28 ++ .../issue-64130-4-async-move.stderr | 22 ++ .../issue-64130-non-send-future-diags.rs | 12 +- .../issue-64130-non-send-future-diags.stderr | 11 +- src/test/ui/generator/not-send-sync.rs | 2 +- src/test/ui/generator/not-send-sync.stderr | 15 +- 19 files changed, 490 insertions(+), 147 deletions(-) create mode 100644 src/test/ui/async-await/issue-64130-1-sync.rs create mode 100644 src/test/ui/async-await/issue-64130-1-sync.stderr create mode 100644 src/test/ui/async-await/issue-64130-2-send.rs create mode 100644 src/test/ui/async-await/issue-64130-2-send.stderr create mode 100644 src/test/ui/async-await/issue-64130-3-other.rs create mode 100644 src/test/ui/async-await/issue-64130-3-other.stderr create mode 100644 src/test/ui/async-await/issue-64130-4-async-move.rs create mode 100644 src/test/ui/async-await/issue-64130-4-async-move.stderr diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 86ee673cea941..288017b7ca53e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -29,6 +29,7 @@ use crate::hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")] #[rustc_on_unimplemented( message="`{Self}` cannot be sent between threads safely", label="`{Self}` cannot be sent between threads safely" @@ -440,6 +441,7 @@ pub macro Copy($item:item) { /* compiler built-in */ } /// [ub]: ../../reference/behavior-considered-undefined.html /// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")] #[lang = "sync"] #[rustc_on_unimplemented( message="`{Self}` cannot be shared between threads safely", diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 35017d6330da3..53dbd186e6670 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -25,6 +25,7 @@ use crate::infer::{self, InferCtxt}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::session::DiagnosticMessageId; use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use crate::ty::TypeckTables; use crate::ty::GenericParamDefKind; use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; @@ -2104,52 +2105,69 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. - if !self.note_obligation_cause_for_async_await(err, obligation) { + if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code, &mut vec![]); } } - /// Adds an async-await specific note to the diagnostic: + /// Adds an async-await specific note to the diagnostic when the future does not implement + /// an auto trait because of a captured type. /// /// ```ignore (diagnostic) - /// note: future does not implement `std::marker::Send` because this value is used across an - /// await - /// --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + /// note: future does not implement `Qux` as this value is used across an await + /// --> $DIR/issue-64130-3-other.rs:17:5 /// | - /// LL | let g = x.lock().unwrap(); - /// | - has type `std::sync::MutexGuard<'_, u32>` + /// LL | let x = Foo; + /// | - has type `Foo` /// LL | baz().await; - /// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later + /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later /// LL | } - /// | - `g` is later dropped here + /// | - `x` is later dropped here + /// ``` + /// + /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic + /// is "replaced" with a different message and a more specific error. + /// + /// ```ignore (diagnostic) + /// error: future cannot be sent between threads safely + /// --> $DIR/issue-64130-2-send.rs:21:5 + /// | + /// LL | fn is_send(t: T) { } + /// | ------- ---- required by this bound in `is_send` + /// ... + /// LL | is_send(bar()); + /// | ^^^^^^^ future returned by `bar` is not send + /// | + /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not + /// implemented for `Foo` + /// note: future is not send as this value is used across an await + /// --> $DIR/issue-64130-2-send.rs:15:5 + /// | + /// LL | let x = Foo; + /// | - has type `Foo` + /// LL | baz().await; + /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + /// LL | } + /// | - `x` is later dropped here /// ``` /// /// Returns `true` if an async-await specific note was added to the diagnostic. - fn note_obligation_cause_for_async_await( + fn maybe_note_obligation_cause_for_async_await( &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, ) -> bool { - debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \ + debug!("maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \ obligation.cause.span={:?}", obligation.predicate, obligation.cause.span); let source_map = self.tcx.sess.source_map(); - // Look into the obligation predicate to determine the type in the generator which meant - // that the predicate was not satisifed. - let (trait_ref, target_ty) = match obligation.predicate { - ty::Predicate::Trait(trait_predicate) => - (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()), - _ => return false, - }; - debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty); - // Attempt to detect an async-await error by looking at the obligation causes, looking - // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to - // be present. + // for a generator to be present. // // When a future does not implement a trait because of a captured type in one of the // generators somewhere in the call stack, then the result is a chain of obligations. + // // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that // future is passed as an argument to a function C which requires a `Send` type, then the // chain looks something like this: @@ -2166,100 +2184,210 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) // - `BindingObligation` with `impl_send (Send requirement) // - // The first obligations in the chain can be used to get the details of the type that is - // captured but the entire chain must be inspected to detect this case. + // The first obligation in the chain is the most useful and has the generator that captured + // the type. The last generator has information about where the bound was introduced. At + // least one generator should be present for this diagnostic to be modified. + let (mut trait_ref, mut target_ty) = match obligation.predicate { + ty::Predicate::Trait(p) => + (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())), + _ => (None, None), + }; let mut generator = None; + let mut last_generator = None; let mut next_code = Some(&obligation.cause.code); while let Some(code) = next_code { - debug!("note_obligation_cause_for_async_await: code={:?}", code); + debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); match code { ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { - debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}", - derived_obligation.parent_trait_ref.self_ty().kind); - match derived_obligation.parent_trait_ref.self_ty().kind { - ty::Adt(ty::AdtDef { did, .. }, ..) if - self.tcx.is_diagnostic_item(sym::gen_future, *did) => {}, - ty::Generator(did, ..) => generator = generator.or(Some(did)), - ty::GeneratorWitness(_) | ty::Opaque(..) => {}, - _ => return false, + let ty = derived_obligation.parent_trait_ref.self_ty(); + debug!("maybe_note_obligation_cause_for_async_await: \ + parent_trait_ref={:?} self_ty.kind={:?}", + derived_obligation.parent_trait_ref, ty.kind); + + match ty.kind { + ty::Generator(did, ..) => { + generator = generator.or(Some(did)); + last_generator = Some(did); + }, + ty::GeneratorWitness(..) => {}, + _ if generator.is_none() => { + trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder()); + target_ty = Some(ty); + }, + _ => {}, } next_code = Some(derived_obligation.parent_code.as_ref()); }, - ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..) - if generator.is_some() => break, - _ => return false, + _ => break, } } - let generator_did = generator.expect("can only reach this if there was a generator"); - - // Only continue to add a note if the generator is from an `async` function. - let parent_node = self.tcx.parent(generator_did) - .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did)); - debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node); - if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, _), - .. - })) = parent_node { - debug!("note_obligation_cause_for_async_await: header={:?}", sig.header); - if sig.header.asyncness != hir::IsAsync::Async { - return false; - } - } + // Only continue if a generator was found. + debug!("maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \ + target_ty={:?}", generator, trait_ref, target_ty); + let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) { + (Some(generator_did), Some(trait_ref), Some(target_ty)) => + (generator_did, trait_ref, target_ty), + _ => return false, + }; let span = self.tcx.def_span(generator_did); + // Do not ICE on closure typeck (#66868). if let None = self.tcx.hir().as_local_hir_id(generator_did) { return false; } - let tables = self.tcx.typeck_tables_of(generator_did); - debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ", - generator_did, span); + + // Get the tables from the infcx if the generator is the function we are + // currently type-checking; otherwise, get them by performing a query. + // This is needed to avoid cycles. + let in_progress_tables = self.in_progress_tables.map(|t| t.borrow()); + let generator_did_root = self.tcx.closure_base_def_id(generator_did); + debug!("maybe_note_obligation_cause_for_async_await: generator_did={:?} \ + generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}", + generator_did, generator_did_root, + in_progress_tables.as_ref().map(|t| t.local_id_root), span); + let query_tables; + let tables: &TypeckTables<'tcx> = match &in_progress_tables { + Some(t) if t.local_id_root == Some(generator_did_root) => t, + _ => { + query_tables = self.tcx.typeck_tables_of(generator_did); + &query_tables + } + }; // Look for a type inside the generator interior that matches the target type to get // a span. let target_span = tables.generator_interior_types.iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty)) + .find(|ty::GeneratorInteriorTypeCause { ty, .. }| { + let ty = ty.builtin_deref(false).map(|ty_and_mut| ty_and_mut.ty).unwrap_or(ty); + let target_ty = target_ty.builtin_deref(false) + .map(|ty_and_mut| ty_and_mut.ty) + .unwrap_or(target_ty); + let eq = ty::TyS::same_type(ty, target_ty); + debug!("maybe_note_obligation_cause_for_async_await: ty={:?} \ + target_ty={:?} eq={:?}", ty, target_ty, eq); + eq + }) .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| (span, source_map.span_to_snippet(*span), scope_span)); + debug!("maybe_note_obligation_cause_for_async_await: target_ty={:?} \ + generator_interior_types={:?} target_span={:?}", + target_ty, tables.generator_interior_types, target_span); if let Some((target_span, Ok(snippet), scope_span)) = target_span { - // Look at the last interior type to get a span for the `.await`. - let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap(); - let mut span = MultiSpan::from_span(await_span); - span.push_span_label( - await_span, format!("await occurs here, with `{}` maybe used later", snippet)); - - span.push_span_label(*target_span, format!("has type `{}`", target_ty)); + self.note_obligation_cause_for_async_await( + err, *target_span, scope_span, snippet, generator_did, last_generator, + trait_ref, target_ty, tables, obligation, next_code, + ); + true + } else { + false + } + } - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - span.push_span_label( - source_map.end_point(*scope_span), - format!("`{}` is later dropped here", snippet), - ); - } + /// Unconditionally adds the diagnostic note described in + /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. + fn note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + target_span: Span, + scope_span: &Option, + snippet: String, + first_generator: DefId, + last_generator: Option, + trait_ref: ty::TraitRef<'_>, + target_ty: Ty<'tcx>, + tables: &ty::TypeckTables<'_>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ) { + let source_map = self.tcx.sess.source_map(); - err.span_note(span, &format!( - "future does not implement `{}` as this value is used across an await", - trait_ref.print_only_trait_path(), - )); + let is_async_fn = self.tcx.parent(first_generator) + .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did)) + .and_then(|parent_node| match parent_node { + Node::Item(item) => Some(&item.kind), + _ => None, + }) + .and_then(|parent_item_kind| match parent_item_kind { + hir::ItemKind::Fn(_, hir::FnHeader { asyncness, .. }, _, _) => Some(asyncness), + _ => None, + }) + .map(|parent_asyncness| *parent_asyncness == hir::IsAsync::Async) + .unwrap_or(false); + let await_or_yield = if is_async_fn { "await" } else { "yield" }; + + // Special case the primary error message when send or sync is the trait that was + // not implemented. + let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); + let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); + let trait_explanation = if is_send || is_sync { + let (trait_name, trait_verb) = if is_send { + ("`Send`", "sent") + } else { + ("`Sync`", "shared") + }; - // Add a note for the item obligation that remains - normally a note pointing to the - // bound that introduced the obligation (e.g. `T: Send`). - debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); - self.note_obligation_cause_code( - err, - &obligation.predicate, - next_code.unwrap(), - &mut Vec::new(), + err.clear_code(); + err.set_primary_message( + format!("future cannot be {} between threads safely", trait_verb) ); - true + let original_span = err.span.primary_span().unwrap(); + let mut span = MultiSpan::from_span(original_span); + + let message = if let Some(name) = last_generator + .and_then(|generator_did| self.tcx.parent(generator_did)) + .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did)) + .map(|parent_hir_id| self.tcx.hir().name(parent_hir_id)) + { + format!("future returned by `{}` is not {}", name, trait_name) + } else { + format!("future is not {}", trait_name) + }; + + span.push_span_label(original_span, message); + err.set_span(span); + + format!("is not {}", trait_name) } else { - false + format!("does not implement `{}`", trait_ref.print_only_trait_path()) + }; + + // Look at the last interior type to get a span for the `.await`. + let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap(); + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, + format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet)); + + span.push_span_label(target_span, format!("has type `{}`", target_ty)); + + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(*scope_span), + format!("`{}` is later dropped here", snippet), + ); } + + err.span_note(span, &format!( + "future {} as this value is used across an {}", + trait_explanation, + await_or_yield, + )); + + // Add a note for the item obligation that remains - normally a note pointing to the + // bound that introduced the obligation (e.g. `T: Send`). + debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); + self.note_obligation_cause_code( + err, + &obligation.predicate, + next_code.unwrap(), + &mut Vec::new(), + ); } fn note_obligation_cause_code(&self, diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index abec979054e16..744f4a47b6035 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -498,10 +498,20 @@ impl Diagnostic { self } + pub fn clear_code(&mut self) -> &mut Self { + self.code = None; + self + } + pub fn get_code(&self) -> Option { self.code.clone() } + pub fn set_primary_message>(&mut self, msg: M) -> &mut Self { + self.message[0] = (msg.into(), Style::NoStyle); + self + } + pub fn message(&self) -> String { self.message.iter().map(|i| i.0.as_str()).collect::() } diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 6de3f1d545b57..ac1ef3e1d8b72 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -26,7 +26,6 @@ pub fn from_generator>(x: T) -> impl Future>(T); // We rely on the fact that async/await futures are immovable in order to create diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index e8f7a125739ac..92de56bd09a7a 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -660,6 +660,7 @@ symbols! { _Self, self_in_typedefs, self_struct_ctor, + send_trait, should_panic, simd, simd_extract, @@ -697,6 +698,7 @@ symbols! { sty, sub_with_overflow, suggestion, + sync_trait, target_feature, target_has_atomic, target_has_atomic_load_store, diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs index 1f1bf4250eadf..645c903c6bab2 100644 --- a/src/test/ui/async-await/async-fn-nonsend.rs +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -48,10 +48,10 @@ fn assert_send(_: impl Send) {} pub fn pass_assert() { assert_send(local_dropped_before_await()); - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR future cannot be sent between threads safely assert_send(non_send_temporary_in_match()); - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR future cannot be sent between threads safely assert_send(non_sync_with_method_call()); - //~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely - //~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + //~^ ERROR future cannot be sent between threads safely + //~^^ ERROR future cannot be sent between threads safely } diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 6e89deb407e92..5c870ca2d0276 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -1,79 +1,88 @@ -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error: future cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:50:5 | LL | fn assert_send(_: impl Send) {} | ----------- ---- required by this bound in `assert_send` ... LL | assert_send(local_dropped_before_await()); - | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send` | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` - = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:25:5 + | +LL | let x = non_send(); + | - has type `impl std::fmt::Debug` +LL | drop(x); +LL | fut().await; + | ^^^^^^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error: future cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:52:5 | LL | fn assert_send(_: impl Send) {} | ----------- ---- required by this bound in `assert_send` ... LL | assert_send(non_send_temporary_in_match()); - | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` - = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{impl std::fmt::Debug, std::option::Option, impl std::future::Future, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option, impl std::future::Future, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option, impl std::future::Future, impl std::future::Future, ()}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:34:20 + | +LL | match Some(non_send()) { + | ---------- has type `impl std::fmt::Debug` +LL | Some(_) => fut().await, + | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later +... +LL | } + | - `non_send()` is later dropped here -error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely +error: future cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:54:5 | LL | fn assert_send(_: impl Send) {} | ----------- ---- required by this bound in `assert_send` ... LL | assert_send(non_sync_with_method_call()); - | ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely + | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | = help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write` - = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write` - = note: required because it appears within the type `std::fmt::Formatter<'_>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:43:9 + | +LL | let f: &mut std::fmt::Formatter = panic!(); + | - has type `&mut std::fmt::Formatter<'_>` +LL | if non_sync().fmt(f).unwrap() == () { +LL | fut().await; + | ^^^^^^^^^^^ await occurs here, with `f` maybe used later +LL | } +LL | } + | - `f` is later dropped here -error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +error: future cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:54:5 | LL | fn assert_send(_: impl Send) {} | ----------- ---- required by this bound in `assert_send` ... LL | assert_send(non_sync_with_method_call()); - | ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | = help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` - = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` - = note: required because it appears within the type `core::fmt::Void` - = note: required because it appears within the type `&core::fmt::Void` - = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>` - = note: required because it appears within the type `std::fmt::Formatter<'_>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:43:9 + | +LL | let f: &mut std::fmt::Formatter = panic!(); + | - has type `&mut std::fmt::Formatter<'_>` +LL | if non_sync().fmt(f).unwrap() == () { +LL | fut().await; + | ^^^^^^^^^^^ await occurs here, with `f` maybe used later +LL | } +LL | } + | - `f` is later dropped here error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64130-1-sync.rs b/src/test/ui/async-await/issue-64130-1-sync.rs new file mode 100644 index 0000000000000..cc5ca89f03af0 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-1-sync.rs @@ -0,0 +1,23 @@ +#![feature(optin_builtin_traits)] +// edition:2018 + +// This tests the the specialized async-await-specific error when futures don't implement an +// auto trait (which is specifically Sync) due to some type that was captured. + +struct Foo; + +impl !Sync for Foo {} + +fn is_sync(t: T) { } + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() { } + +fn main() { + is_sync(bar()); + //~^ ERROR future cannot be shared between threads safely +} diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr new file mode 100644 index 0000000000000..8beb31f152a9d --- /dev/null +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -0,0 +1,22 @@ +error: future cannot be shared between threads safely + --> $DIR/issue-64130-1-sync.rs:21:5 + | +LL | fn is_sync(t: T) { } + | ------- ---- required by this bound in `is_sync` +... +LL | is_sync(bar()); + | ^^^^^^^ future returned by `bar` is not `Sync` + | + = help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo` +note: future is not `Sync` as this value is used across an await + --> $DIR/issue-64130-1-sync.rs:15:5 + | +LL | let x = Foo; + | - has type `Foo` +LL | baz().await; + | ^^^^^^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-2-send.rs b/src/test/ui/async-await/issue-64130-2-send.rs new file mode 100644 index 0000000000000..1efe2ab3f85e2 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-2-send.rs @@ -0,0 +1,23 @@ +#![feature(optin_builtin_traits)] +// edition:2018 + +// This tests the the specialized async-await-specific error when futures don't implement an +// auto trait (which is specifically Send) due to some type that was captured. + +struct Foo; + +impl !Send for Foo {} + +fn is_send(t: T) { } + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() { } + +fn main() { + is_send(bar()); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr new file mode 100644 index 0000000000000..823b88e18c5b6 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -0,0 +1,22 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-2-send.rs:21:5 + | +LL | fn is_send(t: T) { } + | ------- ---- required by this bound in `is_send` +... +LL | is_send(bar()); + | ^^^^^^^ future returned by `bar` is not `Send` + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-2-send.rs:15:5 + | +LL | let x = Foo; + | - has type `Foo` +LL | baz().await; + | ^^^^^^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs new file mode 100644 index 0000000000000..901544edba18a --- /dev/null +++ b/src/test/ui/async-await/issue-64130-3-other.rs @@ -0,0 +1,25 @@ +#![feature(optin_builtin_traits)] +// edition:2018 + +// This tests the the unspecialized async-await-specific error when futures don't implement an +// auto trait (which is not Send or Sync) due to some type that was captured. + +auto trait Qux { } + +struct Foo; + +impl !Qux for Foo {} + +fn is_qux(t: T) { } + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() { } + +fn main() { + is_qux(bar()); + //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` +} diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr new file mode 100644 index 0000000000000..155c5cc8ea137 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` + --> $DIR/issue-64130-3-other.rs:23:5 + | +LL | fn is_qux(t: T) { } + | ------ --- required by this bound in `is_qux` +... +LL | is_qux(bar()); + | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo` + | + = help: the following implementations were found: + +note: future does not implement `Qux` as this value is used across an await + --> $DIR/issue-64130-3-other.rs:17:5 + | +LL | let x = Foo; + | - has type `Foo` +LL | baz().await; + | ^^^^^^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64130-4-async-move.rs b/src/test/ui/async-await/issue-64130-4-async-move.rs new file mode 100644 index 0000000000000..2538f34351e5a --- /dev/null +++ b/src/test/ui/async-await/issue-64130-4-async-move.rs @@ -0,0 +1,28 @@ +// edition:2018 +use std::any::Any; +use std::future::Future; + +struct Client(Box); + +impl Client { + fn status(&self) -> u16 { + 200 + } +} + +async fn get() { } + +pub fn foo() -> impl Future + Send { + //~^ ERROR future cannot be sent between threads safely + let client = Client(Box::new(true)); + async move { + match client.status() { + 200 => { + let _x = get().await; + }, + _ => (), + } + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr new file mode 100644 index 0000000000000..3def984972f84 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -0,0 +1,22 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-4-async-move.rs:15:17 + | +LL | pub fn foo() -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)` +note: future is not `Send` as this value is used across an yield + --> $DIR/issue-64130-4-async-move.rs:21:26 + | +LL | match client.status() { + | ------ has type `&Client` +LL | 200 => { +LL | let _x = get().await; + | ^^^^^^^^^^^ yield occurs here, with `client` maybe used later +... +LL | } + | - `client` is later dropped here + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs index 1936d1a2ed56e..656ade67c71a7 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs @@ -1,10 +1,10 @@ // edition:2018 -use std::sync::Mutex; +// This tests the basic example case for the async-await-specific error. -fn is_send(t: T) { +use std::sync::Mutex; -} +fn is_send(t: T) { } async fn foo() { bar(&Mutex::new(22)).await; @@ -15,11 +15,9 @@ async fn bar(x: &Mutex) { baz().await; } -async fn baz() { - -} +async fn baz() { } fn main() { is_send(foo()); - //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277] + //~^ ERROR future cannot be sent between threads safely } diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr index 9e9fc52e30b7f..662407f7017f5 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -1,14 +1,14 @@ -error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely - --> $DIR/issue-64130-non-send-future-diags.rs:23:5 +error: future cannot be sent between threads safely + --> $DIR/issue-64130-non-send-future-diags.rs:21:5 | -LL | fn is_send(t: T) { +LL | fn is_send(t: T) { } | ------- ---- required by this bound in `is_send` ... LL | is_send(foo()); - | ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely + | ^^^^^^^ future returned by `foo` is not `Send` | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>` -note: future does not implement `std::marker::Send` as this value is used across an await +note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-non-send-future-diags.rs:15:5 | LL | let g = x.lock().unwrap(); @@ -20,4 +20,3 @@ LL | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs index ae0a288bbb496..0db01c6f756ac 100644 --- a/src/test/ui/generator/not-send-sync.rs +++ b/src/test/ui/generator/not-send-sync.rs @@ -7,7 +7,7 @@ fn main() { fn assert_send(_: T) {} assert_sync(|| { - //~^ ERROR: E0277 + //~^ ERROR: future cannot be shared between threads safely let a = Cell::new(2); yield; }); diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 620db245d3e57..0ac1d189b79b0 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -11,18 +11,25 @@ LL | assert_send(|| { = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error: future cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | LL | fn assert_sync(_: T) {} | ----------- ---- required by this bound in `main::assert_sync` ... LL | assert_sync(|| { - | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^^^^^^^ future returned by `main` is not `Sync` | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because it appears within the type `{std::cell::Cell, ()}` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]` +note: future is not `Sync` as this value is used across an yield + --> $DIR/not-send-sync.rs:12:9 + | +LL | let a = Cell::new(2); + | - has type `std::cell::Cell` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | }); + | - `a` is later dropped here error: aborting due to 2 previous errors From 891ab30a103a1e6510e6ed04cbde828b5628b0c1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Oct 2019 14:36:41 +0000 Subject: [PATCH 14/47] async/await: correct diag note for `async move` This commit corrects the diagnostic note for `async move {}` so that `await` is mentioned, rather than `yield`. Signed-off-by: David Wood --- src/librustc/traits/error_reporting.rs | 21 ++++++++++--------- .../issue-64130-4-async-move.stderr | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 53dbd186e6670..84ffb74045eff 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2306,18 +2306,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let source_map = self.tcx.sess.source_map(); let is_async_fn = self.tcx.parent(first_generator) - .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did)) - .and_then(|parent_node| match parent_node { - Node::Item(item) => Some(&item.kind), - _ => None, - }) - .and_then(|parent_item_kind| match parent_item_kind { - hir::ItemKind::Fn(_, hir::FnHeader { asyncness, .. }, _, _) => Some(asyncness), - _ => None, + .map(|parent_did| self.tcx.asyncness(parent_did)) + .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async) + .unwrap_or(false); + let is_async_move = self.tcx.hir().as_local_hir_id(first_generator) + .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) + .map(|body_id| self.tcx.hir().body(body_id)) + .and_then(|body| body.generator_kind()) + .map(|generator_kind| match generator_kind { + hir::GeneratorKind::Async(..) => true, + _ => false, }) - .map(|parent_asyncness| *parent_asyncness == hir::IsAsync::Async) .unwrap_or(false); - let await_or_yield = if is_async_fn { "await" } else { "yield" }; + let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" }; // Special case the primary error message when send or sync is the trait that was // not implemented. diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index 3def984972f84..ddbb469b99c24 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -5,14 +5,14 @@ LL | pub fn foo() -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)` -note: future is not `Send` as this value is used across an yield +note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-4-async-move.rs:21:26 | LL | match client.status() { | ------ has type `&Client` LL | 200 => { LL | let _x = get().await; - | ^^^^^^^^^^^ yield occurs here, with `client` maybe used later + | ^^^^^^^^^^^ await occurs here, with `client` maybe used later ... LL | } | - `client` is later dropped here From 95f2ca0a4fa3254a9749956d0fb68d297fe0627b Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 9 Dec 2019 09:46:55 +0100 Subject: [PATCH 15/47] Bootstrap: change logic for choosing linker and rpath --- src/bootstrap/builder.rs | 7 ++----- src/bootstrap/lib.rs | 8 ++------ src/bootstrap/util.rs | 13 +++++++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 5c0b43c1d24e1..fc1e1cf2b1dce 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -981,7 +981,7 @@ impl<'a> Builder<'a> { // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it // fun to pass a flag to a tool to pass a flag to pass a flag to a tool // to change a flag in a binary? - if self.config.rust_rpath { + if self.config.rust_rpath && util::use_host_linker(&target) { let rpath = if target.contains("apple") { // Note that we need to take one extra step on macOS to also pass @@ -991,10 +991,7 @@ impl<'a> Builder<'a> { // flesh out rpath support more fully in the future. rustflags.arg("-Zosx-rpath-install-name"); Some("-Wl,-rpath,@loader_path/../lib") - } else if !target.contains("windows") && - !target.contains("wasm32") && - !target.contains("emscripten") && - !target.contains("fuchsia") { + } else if !target.contains("windows") { Some("-Wl,-rpath,$ORIGIN/../lib") } else { None diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1f4a4f923e048..7f7e29108a875 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -805,12 +805,8 @@ impl Build { .and_then(|c| c.linker.as_ref()) { Some(linker) } else if target != self.config.build && - !target.contains("msvc") && - !target.contains("emscripten") && - !target.contains("wasm32") && - !target.contains("nvptx") && - !target.contains("fortanix") && - !target.contains("fuchsia") { + util::use_host_linker(&target) && + !target.contains("msvc") { Some(self.cc(target)) } else { None diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 6f8a630874570..6824b7a58c480 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -15,6 +15,7 @@ use build_helper::t; use crate::config::Config; use crate::builder::Builder; +use crate::cache::Interned; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { @@ -306,3 +307,15 @@ pub fn forcing_clang_based_tests() -> bool { false } } + +pub fn use_host_linker(target: &Interned) -> bool { + // FIXME: this information should be gotten by checking the linker flavor + // of the rustc target + !( + target.contains("emscripten") || + target.contains("wasm32") || + target.contains("nvptx") || + target.contains("fortanix") || + target.contains("fuchsia") + ) +} From cac6e98a410f17ab339805bc3d1c130137e13780 Mon Sep 17 00:00:00 2001 From: Matthew Kraai Date: Mon, 9 Dec 2019 06:49:37 -0800 Subject: [PATCH 16/47] Remove `checked_add` in `Layout::repeat` --- src/libcore/alloc.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 4cfd6527deb0a..5c24e3d8f5d5a 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -239,8 +239,11 @@ impl Layout { #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { - let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) - .ok_or(LayoutErr { private: () })?; + // This cannot overflow. Quoting from the invariant of Layout: + // > `size`, when rounded up to the nearest multiple of `align`, + // > must not overflow (i.e., the rounded value must be less than + // > `usize::MAX`) + let padded_size = self.size() + self.padding_needed_for(self.align()); let alloc_size = padded_size.checked_mul(n) .ok_or(LayoutErr { private: () })?; From e3e3e0f8cf7cd351f800d7d0270979ea69882f75 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 5 Dec 2019 14:43:53 -0800 Subject: [PATCH 17/47] Add options to --extern flag. --- src/librustc_interface/tests.rs | 23 +-- src/librustc_metadata/creader.rs | 15 +- src/librustc_metadata/locator.rs | 5 +- src/librustc_resolve/lib.rs | 6 +- src/librustc_session/config.rs | 169 ++++++++++++++---- src/librustdoc/config.rs | 33 +--- src/librustdoc/core.rs | 4 +- src/librustdoc/lib.rs | 4 - .../extern-flag-noprelude/Makefile | 11 ++ .../extern-flag-noprelude/dep.rs | 3 + .../extern-flag-noprelude/foo.rs | 3 + src/test/ui/extern-flag/multiple-opts.rs | 20 +++ src/test/ui/extern-flag/multiple-opts.stderr | 9 + .../ui/extern-flag/noprelude-and-prelude.rs | 10 ++ src/test/ui/extern-flag/public-and-private.rs | 13 ++ .../ui/extern-flag/public-and-private.stderr | 14 ++ src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/runtest.rs | 10 +- 18 files changed, 254 insertions(+), 100 deletions(-) create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/Makefile create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs create mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs create mode 100644 src/test/ui/extern-flag/multiple-opts.rs create mode 100644 src/test/ui/extern-flag/multiple-opts.stderr create mode 100644 src/test/ui/extern-flag/noprelude-and-prelude.rs create mode 100644 src/test/ui/extern-flag/public-and-private.rs create mode 100644 src/test/ui/extern-flag/public-and-private.stderr diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 4c630b56cb4ce..d4b5e833dfb23 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -7,7 +7,7 @@ use rustc::middle::cstore; use rustc::session::config::{build_configuration, build_session_options, to_crate_config}; use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry}; use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; -use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes}; +use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes, ExternLocation}; use rustc::session::{build_session, Session}; use rustc::session::search_paths::SearchPath; use std::collections::{BTreeMap, BTreeSet}; @@ -38,14 +38,15 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { fn new_public_extern_entry(locations: I) -> ExternEntry where S: Into, - I: IntoIterator>, + I: IntoIterator, { - let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into())) + let locations: BTreeSet<_> = locations.into_iter().map(|s| s.into()) .collect(); ExternEntry { - locations, - is_private_dep: false + location: ExternLocation::ExactPaths(locations), + is_private_dep: false, + add_prelude: true, } } @@ -160,33 +161,33 @@ fn test_externs_tracking_hash_different_construction_order() { v1.externs = Externs::new(mk_map(vec![ ( String::from("a"), - new_public_extern_entry(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec!["b", "c"]) ), ( String::from("d"), - new_public_extern_entry(vec![Some("e"), Some("f")]) + new_public_extern_entry(vec!["e", "f"]) ), ])); v2.externs = Externs::new(mk_map(vec![ ( String::from("d"), - new_public_extern_entry(vec![Some("e"), Some("f")]) + new_public_extern_entry(vec!["e", "f"]) ), ( String::from("a"), - new_public_extern_entry(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec!["b", "c"]) ), ])); v3.externs = Externs::new(mk_map(vec![ ( String::from("a"), - new_public_extern_entry(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec!["b", "c"]) ), ( String::from("d"), - new_public_extern_entry(vec![Some("f"), Some("e")]) + new_public_extern_entry(vec!["f", "e"]) ), ])); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 25bd2c45da5f5..0a0f2560b994f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -218,13 +218,14 @@ impl<'a> CrateLoader<'a> { let source = self.cstore.get_crate_data(cnum).source(); if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. - let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| { - let l = fs::canonicalize(l).ok(); - source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || - source.rlib.as_ref().map(|p| &p.0) == l.as_ref() - }); - if found { - ret = Some(cnum); + if let Some(mut files) = entry.files() { + if files.any(|l| { + let l = fs::canonicalize(l).ok(); + source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || + source.rlib.as_ref().map(|p| &p.0) == l.as_ref() + }) { + ret = Some(cnum); + } } return } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index c6fb80eca055a..8a1eeea02512e 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -328,8 +328,9 @@ impl<'a> CrateLocator<'a> { crate_name, exact_paths: if hash.is_none() { sess.opts.externs.get(&crate_name.as_str()).into_iter() - .flat_map(|entry| entry.locations.iter()) - .filter_map(|location| location.clone().map(PathBuf::from)).collect() + .filter_map(|entry| entry.files()) + .flatten() + .map(|location| PathBuf::from(location)).collect() } else { // SVH being specified means this is a transitive dependency, // so `--extern` options do not apply. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9db89c8273d9c..d3656248b1b09 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1136,8 +1136,10 @@ impl<'a> Resolver<'a> { definitions.create_root_def(crate_name, session.local_crate_disambiguator()); let mut extern_prelude: FxHashMap> = - session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) - .collect(); + session.opts.externs.iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| (Ident::from_str(name), Default::default())) + .collect(); if !attr::contains_name(&krate.attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 58113bb8cd6cb..7f3bab8f23299 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. @@ -31,7 +33,7 @@ use std::fmt; use std::str::{self, FromStr}; use std::hash::Hasher; use std::collections::hash_map::DefaultHasher; -use std::iter::FromIterator; +use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; pub struct Config { @@ -322,10 +324,35 @@ impl OutputTypes { #[derive(Clone)] pub struct Externs(BTreeMap); -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ExternEntry { - pub locations: BTreeSet>, - pub is_private_dep: bool + pub location: ExternLocation, + /// Indicates this is a "private" dependency for the + /// `exported_private_dependencies` lint. + /// + /// This can be set with the `priv` option like + /// `--extern priv:name=foo.rlib`. + pub is_private_dep: bool, + /// Add the extern entry to the extern prelude. + /// + /// This can be disabled with the `noprelude` option like + /// `--extern noprelude:name`. + pub add_prelude: bool, +} + +#[derive(Clone, Debug)] +pub enum ExternLocation { + /// Indicates to look for the library in the search paths. + /// + /// Added via `--extern name`. + FoundInLibrarySearchDirectories, + /// The locations where this extern entry must be found. + /// + /// The `CrateLoader` is responsible for loading these and figuring out + /// which one to use. + /// + /// Added via `--extern prelude_name=some_file.rlib` + ExactPaths(BTreeSet), } impl Externs { @@ -342,6 +369,18 @@ impl Externs { } } +impl ExternEntry { + fn new(location: ExternLocation) -> ExternEntry { + ExternEntry { location, is_private_dep: false, add_prelude: false } + } + + pub fn files(&self) -> Option> { + match &self.location { + ExternLocation::ExactPaths(set) => Some(set.iter()), + _ => None, + } + } +} macro_rules! hash_option { ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({}); @@ -1869,12 +1908,6 @@ pub fn rustc_optgroups() -> Vec { "Specify where an external rust library is located", "NAME[=PATH]", ), - opt::multi_s( - "", - "extern-private", - "Specify where an extern rust library is located, marking it as a private dependency", - "NAME=PATH", - ), opt::opt_s("", "sysroot", "Override the system root", "PATH"), opt::multi("Z", "", "Set internal debugging options", "FLAG"), opt::opt_s( @@ -2435,43 +2468,105 @@ fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) } } -fn parse_externs( +pub fn parse_externs( matches: &getopts::Matches, debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> Externs { - if matches.opt_present("extern-private") && !debugging_opts.unstable_options { - early_error( - ErrorOutputType::default(), - "'--extern-private' is unstable and only \ - available for nightly builds of rustc." - ) - } - - // We start out with a `Vec<(Option, bool)>>`, - // and later convert it into a `BTreeSet<(Option, bool)>` - // This allows to modify entries in-place to set their correct - // 'public' value. + let is_unstable_enabled = debugging_opts.unstable_options; let mut externs: BTreeMap = BTreeMap::new(); - for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false)) - .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) { - + for arg in matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); - let name = parts.next().unwrap_or_else(|| - early_error(error_format, "--extern value must not be empty")); - let location = parts.next().map(|s| s.to_string()); + let name = parts + .next() + .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty")); + let path = parts.next().map(|s| s.to_string()); + + let mut name_parts = name.splitn(2, ':'); + let first_part = name_parts.next(); + let second_part = name_parts.next(); + let (options, name) = match (first_part, second_part) { + (Some(opts), Some(name)) => (Some(opts), name), + (Some(name), None) => (None, name), + (None, None) => early_error(error_format, "--extern name must not be empty"), + _ => unreachable!(), + }; + + let entry = externs.entry(name.to_owned()); - let entry = externs - .entry(name.to_owned()) - .or_default(); + use std::collections::btree_map::Entry; + let entry = if let Some(path) = path { + // --extern prelude_name=some_file.rlib + match entry { + Entry::Vacant(vacant) => { + let files = BTreeSet::from_iter(iter::once(path)); + vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files))) + } + Entry::Occupied(occupied) => { + let ext_ent = occupied.into_mut(); + match ext_ent { + ExternEntry { location: ExternLocation::ExactPaths(files), .. } => { + files.insert(path); + } + ExternEntry { + location: location @ ExternLocation::FoundInLibrarySearchDirectories, + .. + } => { + // Exact paths take precedence over search directories. + let files = BTreeSet::from_iter(iter::once(path)); + *location = ExternLocation::ExactPaths(files); + } + } + ext_ent + } + } + } else { + // --extern prelude_name + match entry { + Entry::Vacant(vacant) => { + vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories)) + } + Entry::Occupied(occupied) => { + // Ignore if already specified. + occupied.into_mut() + } + } + }; - entry.locations.insert(location.clone()); + let mut is_private_dep = false; + let mut add_prelude = true; + if let Some(opts) = options { + if !is_unstable_enabled { + early_error( + error_format, + "the `-Z unstable-options` flag must also be passed to \ + enable `--extern options", + ); + } + for opt in opts.split(',') { + match opt { + "priv" => is_private_dep = true, + "noprelude" => { + if let ExternLocation::ExactPaths(_) = &entry.location { + add_prelude = false; + } else { + early_error( + error_format, + "the `noprelude` --extern option requires a file path", + ); + } + } + _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)), + } + } + } - // Crates start out being not private, - // and go to being private if we see an '--extern-private' - // flag - entry.is_private_dep |= private; + // Crates start out being not private, and go to being private `priv` + // is specified. + entry.is_private_dep |= is_private_dep; + // If any flag is missing `noprelude`, then add to the prelude. + entry.add_prelude |= add_prelude; } Externs(externs) } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index cdb1a1f6997c9..0db3d28bf0e37 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -7,10 +7,10 @@ use errors; use getopts; use rustc::lint::Level; use rustc::session; -use rustc::session::config::{CrateType, parse_crate_types_from_list}; +use rustc::session::config::{CrateType, parse_crate_types_from_list, parse_externs}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options, host_triple, ExternEntry}; + get_cmd_lint_options, host_triple}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; @@ -320,13 +320,7 @@ impl Options { let libs = matches.opt_strs("L").iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); - let externs = match parse_externs(&matches) { - Ok(ex) => ex, - Err(err) => { - diag.struct_err(&err).emit(); - return Err(1); - } - }; + let externs = parse_externs(&matches, &debugging_options, error_format); let extern_html_root_urls = match parse_extern_html_roots(&matches) { Ok(ex) => ex, Err(err) => { @@ -617,24 +611,3 @@ fn parse_extern_html_roots( Ok(externs) } - -/// Extracts `--extern CRATE=PATH` arguments from `matches` and -/// returns a map mapping crate names to their paths or else an -/// error message. -/// Also handles `--extern-private` which for the purposes of rustdoc -/// we can treat as `--extern` -// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`. -fn parse_externs(matches: &getopts::Matches) -> Result { - let mut externs: BTreeMap<_, ExternEntry> = BTreeMap::new(); - for arg in matches.opt_strs("extern").iter().chain(matches.opt_strs("extern-private").iter()) { - let mut parts = arg.splitn(2, '='); - let name = parts.next().ok_or("--extern value must not be empty".to_string())?; - let location = parts.next().map(|s| s.to_string()); - let name = name.to_string(); - // For Rustdoc purposes, we can treat all externs as public - externs.entry(name) - .or_default() - .locations.insert(location.clone()); - } - Ok(Externs::new(externs)) -} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b77b1c720cfdf..a524801bea6bf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -248,7 +248,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .. } = options; - let extern_names: Vec = externs.iter().map(|(s,_)| s).cloned().collect(); + let extern_names: Vec = externs.iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| name).cloned().collect(); // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index be3644ecf96a7..a4be3dee938ed 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -145,10 +145,6 @@ fn opts() -> Vec { stable("extern", |o| { o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]") }), - unstable("extern-private", |o| { - o.optmulti("", "extern-private", - "pass an --extern to rustc (compatibility only)", "NAME=PATH") - }), unstable("extern-html-root-url", |o| { o.optmulti("", "extern-html-root-url", "base URL to use for dependencies", "NAME=URL") diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile new file mode 100644 index 0000000000000..18f9d8bab6004 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile @@ -0,0 +1,11 @@ +-include ../tools.mk + +# Test --extern noprelude + +all: + $(RUSTC) dep.rs --crate-name=dep --crate-type=rlib + $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ + --extern noprelude:dep=$(TMPDIR)/libdep.rlib 2>&1 | \ + $(CGREP) -e 'failed to resolve.*`dep`' + $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ + --extern dep=$(TMPDIR)/libdep.rlib diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs new file mode 100644 index 0000000000000..dd2f373f849c6 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs @@ -0,0 +1,3 @@ +pub fn somefun() {} + +pub struct S; diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs new file mode 100644 index 0000000000000..9bb1b78409f86 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs @@ -0,0 +1,3 @@ +fn main() { + dep::somefun(); +} diff --git a/src/test/ui/extern-flag/multiple-opts.rs b/src/test/ui/extern-flag/multiple-opts.rs new file mode 100644 index 0000000000000..3dc2f1d73f8e4 --- /dev/null +++ b/src/test/ui/extern-flag/multiple-opts.rs @@ -0,0 +1,20 @@ +// aux-crate:priv,noprelude:somedep=somedep.rs +// compile-flags: -Zunstable-options +// edition:2018 + +// Test for multiple options to --extern. Can't test for errors from both +// options at the same time, so this only checks that noprelude is honored. + +#![warn(exported_private_dependencies)] + +// Module to avoid adding to prelude. +pub mod m { + extern crate somedep; + pub struct PublicType { + pub field: somedep::S, + } +} + +fn main() { + somedep::somefun(); //~ ERROR failed to resolve +} diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr new file mode 100644 index 0000000000000..3bf73d11cfd22 --- /dev/null +++ b/src/test/ui/extern-flag/multiple-opts.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared type or module `somedep` + --> $DIR/multiple-opts.rs:19:5 + | +LL | somedep::somefun(); + | ^^^^^^^ use of undeclared type or module `somedep` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/extern-flag/noprelude-and-prelude.rs b/src/test/ui/extern-flag/noprelude-and-prelude.rs new file mode 100644 index 0000000000000..e6a150b9e8b9e --- /dev/null +++ b/src/test/ui/extern-flag/noprelude-and-prelude.rs @@ -0,0 +1,10 @@ +// check-pass +// aux-crate:noprelude:somedep=somedep.rs +// compile-flags: -Zunstable-options --extern somedep +// edition:2018 + +// Having a flag with `noprelude` and one without, will add to the prelude. + +fn main() { + somedep::somefun(); +} diff --git a/src/test/ui/extern-flag/public-and-private.rs b/src/test/ui/extern-flag/public-and-private.rs new file mode 100644 index 0000000000000..a3a81cbf37223 --- /dev/null +++ b/src/test/ui/extern-flag/public-and-private.rs @@ -0,0 +1,13 @@ +// aux-crate:priv:somedep=somedep.rs +// compile-flags: -Zunstable-options --extern somedep +// edition:2018 + +#![deny(exported_private_dependencies)] + +// Having a flag with `priv` and one without, will remain private (it is sticky). + +pub struct PublicType { + pub field: somedep::S, //~ ERROR from private dependency +} + +fn main() {} diff --git a/src/test/ui/extern-flag/public-and-private.stderr b/src/test/ui/extern-flag/public-and-private.stderr new file mode 100644 index 0000000000000..72f1bb2d26f1a --- /dev/null +++ b/src/test/ui/extern-flag/public-and-private.stderr @@ -0,0 +1,14 @@ +error: type `somedep::S` from private dependency 'somedep' in public interface + --> $DIR/public-and-private.rs:10:5 + | +LL | pub field: somedep::S, + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/public-and-private.rs:5:9 + | +LL | #![deny(exported_private_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc4811e5d24ce..ca30e782c5056 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -311,7 +311,7 @@ pub struct TestProps { // directory as the test, but for backwards compatibility reasons // we also check the auxiliary directory) pub aux_builds: Vec, - // A list of crates to pass '--extern-private name:PATH' flags for + // A list of crates to pass '--extern priv:name=PATH' flags for // This should be a subset of 'aux_build' // FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020 pub extern_private: Vec, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 15ae67fb12c51..ca68fe3e39b96 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1782,8 +1782,8 @@ impl<'test> TestCx<'test> { let mut add_extern_priv = |priv_dep: &str, dylib: bool| { let lib_name = get_lib_name(priv_dep, dylib); rustc - .arg("--extern-private") - .arg(format!("{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap())); + .arg("--extern") + .arg(format!("priv:{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap())); }; for rel_ab in &self.props.aux_builds { @@ -1829,9 +1829,9 @@ impl<'test> TestCx<'test> { let trimmed = rel_ab.trim_end_matches(".rs").to_string(); - // Normally, every 'extern-private' has a correspodning 'aux-build' + // Normally, every 'extern-private' has a corresponding 'aux-build' // entry. If so, we remove it from our list of private crates, - // and add an '--extern-private' flag to rustc + // and add an '--extern priv:NAME=PATH' flag to rustc if extern_priv.remove_item(&trimmed).is_some() { add_extern_priv(&trimmed, dylib); } @@ -1859,7 +1859,7 @@ impl<'test> TestCx<'test> { } } - // Add any '--extern-private' entries without a matching + // Add any '--extern' private entries without a matching // 'aux-build' for private_lib in extern_priv { add_extern_priv(&private_lib, true); From 5ee69bb54cf821106c725a6b2f3582024bfd5b2a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 5 Dec 2019 16:26:21 -0800 Subject: [PATCH 18/47] compiletest: add aux-crate directive --- .../extern-flag-noprelude/Makefile | 11 -- .../extern-flag-noprelude/foo.rs | 3 - src/test/rustdoc/issue-66159.rs | 3 +- .../extern-flag/auxiliary/somedep.rs} | 0 src/test/ui/extern-flag/noprelude-resolves.rs | 11 ++ src/test/ui/extern-flag/noprelude.rs | 7 + src/test/ui/extern-flag/noprelude.stderr | 9 + src/test/ui/privacy/pub-priv-dep/pub-priv1.rs | 5 +- .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 8 +- src/tools/compiletest/src/header.rs | 29 +++- src/tools/compiletest/src/runtest.rs | 159 +++++++++--------- 11 files changed, 129 insertions(+), 116 deletions(-) delete mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/Makefile delete mode 100644 src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs rename src/test/{run-make-fulldeps/extern-flag-noprelude/dep.rs => ui/extern-flag/auxiliary/somedep.rs} (100%) create mode 100644 src/test/ui/extern-flag/noprelude-resolves.rs create mode 100644 src/test/ui/extern-flag/noprelude.rs create mode 100644 src/test/ui/extern-flag/noprelude.stderr diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile b/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile deleted file mode 100644 index 18f9d8bab6004..0000000000000 --- a/src/test/run-make-fulldeps/extern-flag-noprelude/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../tools.mk - -# Test --extern noprelude - -all: - $(RUSTC) dep.rs --crate-name=dep --crate-type=rlib - $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ - --extern noprelude:dep=$(TMPDIR)/libdep.rlib 2>&1 | \ - $(CGREP) -e 'failed to resolve.*`dep`' - $(RUSTC) foo.rs --edition=2018 -Zunstable-options \ - --extern dep=$(TMPDIR)/libdep.rlib diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs b/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs deleted file mode 100644 index 9bb1b78409f86..0000000000000 --- a/src/test/run-make-fulldeps/extern-flag-noprelude/foo.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - dep::somefun(); -} diff --git a/src/test/rustdoc/issue-66159.rs b/src/test/rustdoc/issue-66159.rs index a69ba61a283d0..003d079a470c0 100644 --- a/src/test/rustdoc/issue-66159.rs +++ b/src/test/rustdoc/issue-66159.rs @@ -1,6 +1,5 @@ -// aux-build:issue-66159-1.rs +// aux-crate:priv:issue_66159_1=issue-66159-1.rs // compile-flags:-Z unstable-options -// extern-private:issue_66159_1 // The issue was an ICE which meant that we never actually generated the docs // so if we have generated the docs, we're okay. diff --git a/src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs b/src/test/ui/extern-flag/auxiliary/somedep.rs similarity index 100% rename from src/test/run-make-fulldeps/extern-flag-noprelude/dep.rs rename to src/test/ui/extern-flag/auxiliary/somedep.rs diff --git a/src/test/ui/extern-flag/noprelude-resolves.rs b/src/test/ui/extern-flag/noprelude-resolves.rs new file mode 100644 index 0000000000000..f69f552b69d8a --- /dev/null +++ b/src/test/ui/extern-flag/noprelude-resolves.rs @@ -0,0 +1,11 @@ +// check-pass +// aux-crate:noprelude:somedep=somedep.rs +// compile-flags: -Zunstable-options +// edition:2018 + +// `extern crate` can be used to add to prelude. +extern crate somedep; + +fn main() { + somedep::somefun(); +} diff --git a/src/test/ui/extern-flag/noprelude.rs b/src/test/ui/extern-flag/noprelude.rs new file mode 100644 index 0000000000000..cdbf34091007e --- /dev/null +++ b/src/test/ui/extern-flag/noprelude.rs @@ -0,0 +1,7 @@ +// aux-crate:noprelude:somedep=somedep.rs +// compile-flags: -Zunstable-options +// edition:2018 + +fn main() { + somedep::somefun(); //~ ERROR failed to resolve +} diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr new file mode 100644 index 0000000000000..beb9200dddabc --- /dev/null +++ b/src/test/ui/extern-flag/noprelude.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared type or module `somedep` + --> $DIR/noprelude.rs:6:5 + | +LL | somedep::somefun(); + | ^^^^^^^ use of undeclared type or module `somedep` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index 784615354a95c..feab72b3efa42 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -1,11 +1,10 @@ - // aux-build:priv_dep.rs + // aux-crate:priv:priv_dep=priv_dep.rs // aux-build:pub_dep.rs - // extern-private:priv_dep #![deny(exported_private_dependencies)] // This crate is a private dependency extern crate priv_dep; -// This crate is a public dependenct +// This crate is a public dependency extern crate pub_dep; use priv_dep::{OtherType, OtherTrait}; diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index b31efdbd781dc..f21b11f5b32f8 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,23 +1,23 @@ error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:21:5 + --> $DIR/pub-priv1.rs:20:5 | LL | pub field: OtherType, | ^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/pub-priv1.rs:4:9 + --> $DIR/pub-priv1.rs:3:9 | LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:28:5 + --> $DIR/pub-priv1.rs:27:5 | LL | pub fn pub_fn(param: OtherType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:34:1 + --> $DIR/pub-priv1.rs:33:1 | LL | / pub trait MyPubTrait { LL | | type Foo: OtherTrait; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ca30e782c5056..46cce6394e617 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -71,6 +71,7 @@ pub struct EarlyProps { pub ignore: Ignore, pub should_fail: bool, pub aux: Vec, + pub aux_crate: Vec<(String, String)>, pub revisions: Vec, } @@ -80,6 +81,7 @@ impl EarlyProps { ignore: Ignore::Run, should_fail: false, aux: Vec::new(), + aux_crate: Vec::new(), revisions: vec![], }; @@ -157,6 +159,10 @@ impl EarlyProps { props.aux.push(s); } + if let Some(ac) = config.parse_aux_crate(ln) { + props.aux_crate.push(ac); + } + if let Some(r) = config.parse_revisions(ln) { props.revisions.extend(r); } @@ -311,10 +317,9 @@ pub struct TestProps { // directory as the test, but for backwards compatibility reasons // we also check the auxiliary directory) pub aux_builds: Vec, - // A list of crates to pass '--extern priv:name=PATH' flags for - // This should be a subset of 'aux_build' - // FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020 - pub extern_private: Vec, + // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies + // to build and pass with the `--extern` flag. + pub aux_crates: Vec<(String, String)>, // Environment settings to use for compiling pub rustc_env: Vec<(String, String)>, // Environment variables to unset prior to compiling. @@ -387,7 +392,7 @@ impl TestProps { run_flags: None, pp_exact: None, aux_builds: vec![], - extern_private: vec![], + aux_crates: vec![], revisions: vec![], rustc_env: vec![], unset_rustc_env: vec![], @@ -514,8 +519,8 @@ impl TestProps { self.aux_builds.push(ab); } - if let Some(ep) = config.parse_extern_private(ln) { - self.extern_private.push(ep); + if let Some(ac) = config.parse_aux_crate(ln) { + self.aux_crates.push(ac); } if let Some(ee) = config.parse_env(ln, "exec-env") { @@ -713,8 +718,14 @@ impl Config { .map(|r| r.trim().to_string()) } - fn parse_extern_private(&self, line: &str) -> Option { - self.parse_name_value_directive(line, "extern-private") + fn parse_aux_crate(&self, line: &str) -> Option<(String, String)> { + self.parse_name_value_directive(line, "aux-crate").map(|r| { + let mut parts = r.trim().splitn(2, '='); + ( + parts.next().expect("aux-crate name").to_string(), + parts.next().expect("aux-crate value").to_string(), + ) + }) } fn parse_compile_flags(&self, line: &str) -> Option { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ca68fe3e39b96..480868440b8dc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1776,93 +1776,16 @@ impl<'test> TestCx<'test> { create_dir_all(&aux_dir).unwrap(); } - // Use a Vec instead of a HashMap to preserve original order - let mut extern_priv = self.props.extern_private.clone(); - - let mut add_extern_priv = |priv_dep: &str, dylib: bool| { - let lib_name = get_lib_name(priv_dep, dylib); - rustc - .arg("--extern") - .arg(format!("priv:{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap())); - }; - for rel_ab in &self.props.aux_builds { - let aux_testpaths = self.compute_aux_test_paths(rel_ab); - let aux_props = - self.props - .from_aux_file(&aux_testpaths.file, self.revision, self.config); - let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name()); - let aux_cx = TestCx { - config: self.config, - props: &aux_props, - testpaths: &aux_testpaths, - revision: self.revision, - }; - // Create the directory for the stdout/stderr files. - create_dir_all(aux_cx.output_base_dir()).unwrap(); - let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output); - - let (dylib, crate_type) = if aux_props.no_prefer_dynamic { - (true, None) - } else if self.config.target.contains("cloudabi") - || self.config.target.contains("emscripten") - || (self.config.target.contains("musl") - && !aux_props.force_host - && !self.config.host.contains("musl")) - || self.config.target.contains("wasm32") - || self.config.target.contains("nvptx") - || self.is_vxworks_pure_static() - { - // We primarily compile all auxiliary libraries as dynamic libraries - // to avoid code size bloat and large binaries as much as possible - // for the test suite (otherwise including libstd statically in all - // executables takes up quite a bit of space). - // - // For targets like MUSL or Emscripten, however, there is no support for - // dynamic libraries so we just go back to building a normal library. Note, - // however, that for MUSL if the library is built with `force_host` then - // it's ok to be a dylib as the host should always support dylibs. - (false, Some("lib")) - } else { - (true, Some("dylib")) - }; - - let trimmed = rel_ab.trim_end_matches(".rs").to_string(); - - // Normally, every 'extern-private' has a corresponding 'aux-build' - // entry. If so, we remove it from our list of private crates, - // and add an '--extern priv:NAME=PATH' flag to rustc - if extern_priv.remove_item(&trimmed).is_some() { - add_extern_priv(&trimmed, dylib); - } - - if let Some(crate_type) = crate_type { - aux_rustc.args(&["--crate-type", crate_type]); - } - - aux_rustc.arg("-L").arg(&aux_dir); - - let auxres = aux_cx.compose_and_run( - aux_rustc, - aux_cx.config.compile_lib_path.to_str().unwrap(), - Some(aux_dir.to_str().unwrap()), - None, - ); - if !auxres.status.success() { - self.fatal_proc_rec( - &format!( - "auxiliary build of {:?} failed to compile: ", - aux_testpaths.file.display() - ), - &auxres, - ); - } + self.build_auxiliary(rel_ab, &aux_dir); } - // Add any '--extern' private entries without a matching - // 'aux-build' - for private_lib in extern_priv { - add_extern_priv(&private_lib, true); + for (aux_name, aux_path) in &self.props.aux_crates { + let is_dylib = self.build_auxiliary(&aux_path, &aux_dir); + let lib_name = get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), + is_dylib); + rustc.arg("--extern") + .arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name)); } self.props.unset_rustc_env.clone() @@ -1877,6 +1800,74 @@ impl<'test> TestCx<'test> { ) } + /// Builds an aux dependency. + /// + /// Returns whether or not it is a dylib. + fn build_auxiliary(&self, source_path: &str, aux_dir: &Path) -> bool { + let aux_testpaths = self.compute_aux_test_paths(source_path); + let aux_props = + self.props + .from_aux_file(&aux_testpaths.file, self.revision, self.config); + let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name()); + let aux_cx = TestCx { + config: self.config, + props: &aux_props, + testpaths: &aux_testpaths, + revision: self.revision, + }; + // Create the directory for the stdout/stderr files. + create_dir_all(aux_cx.output_base_dir()).unwrap(); + let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output); + + let (dylib, crate_type) = if aux_props.no_prefer_dynamic { + (true, None) + } else if self.config.target.contains("cloudabi") + || self.config.target.contains("emscripten") + || (self.config.target.contains("musl") + && !aux_props.force_host + && !self.config.host.contains("musl")) + || self.config.target.contains("wasm32") + || self.config.target.contains("nvptx") + || self.is_vxworks_pure_static() + { + // We primarily compile all auxiliary libraries as dynamic libraries + // to avoid code size bloat and large binaries as much as possible + // for the test suite (otherwise including libstd statically in all + // executables takes up quite a bit of space). + // + // For targets like MUSL or Emscripten, however, there is no support for + // dynamic libraries so we just go back to building a normal library. Note, + // however, that for MUSL if the library is built with `force_host` then + // it's ok to be a dylib as the host should always support dylibs. + (false, Some("lib")) + } else { + (true, Some("dylib")) + }; + + if let Some(crate_type) = crate_type { + aux_rustc.args(&["--crate-type", crate_type]); + } + + aux_rustc.arg("-L").arg(&aux_dir); + + let auxres = aux_cx.compose_and_run( + aux_rustc, + aux_cx.config.compile_lib_path.to_str().unwrap(), + Some(aux_dir.to_str().unwrap()), + None, + ); + if !auxres.status.success() { + self.fatal_proc_rec( + &format!( + "auxiliary build of {:?} failed to compile: ", + aux_testpaths.file.display() + ), + &auxres, + ); + } + dylib + } + fn compose_and_run( &self, mut command: Command, From dd08bf730097cb769bf87fd5c2cc207b8dc05dd8 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 8 Dec 2019 21:50:23 +0000 Subject: [PATCH 19/47] Ensure that unevaluated constants of type `!` are present in the MIR --- src/librustc_mir/build/expr/into.rs | 9 +++++- src/test/mir-opt/retain-never-const.rs | 28 +++++++++++++++++++ .../index-out-of-bounds-never-type.rs | 18 ++++++++++++ .../index-out-of-bounds-never-type.stderr | 22 +++++++++++++++ .../const-eval/panic-assoc-never-type.rs | 15 ++++++++++ .../const-eval/panic-assoc-never-type.stderr | 24 ++++++++++++++++ .../ui/consts/const-eval/panic-never-type.rs | 11 ++++++++ .../consts/const-eval/panic-never-type.stderr | 24 ++++++++++++++++ 8 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/test/mir-opt/retain-never-const.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-never-type.stderr diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index f5dc09ccebc1e..07a44b190b20a 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -65,7 +65,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; - unpack!(block = this.as_local_rvalue(block, source)); + // (#66975) Source could be a const of type `!`, so has to + // exist in the generated MIR. + unpack!(block = this.as_temp( + block, + this.local_scope(), + source, + Mutability::Mut, + )); // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. diff --git a/src/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs new file mode 100644 index 0000000000000..5d59b2f48429d --- /dev/null +++ b/src/test/mir-opt/retain-never-const.rs @@ -0,0 +1,28 @@ +// Regression test for #66975 - ensure that we don't keep unevaluated +// `!`-typed constants until codegen. + +// Force generation of optimized mir for functions that do not reach codegen. +// compile-flags: --emit mir,link + +#![feature(const_panic)] + +struct PrintName(T); + +impl PrintName { + const VOID: ! = panic!(); +} + +fn no_codegen() { + let _ = PrintName::::VOID; +} + +fn main() {} + +// END RUST SOURCE +// START rustc.no_codegen.PreCodegen.after.mir +// bb0: { +// StorageLive(_1); +// _1 = const PrintName::::VOID; +// unreachable; +// } +// END rustc.no_codegen.PreCodegen.after.mir diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs new file mode 100644 index 0000000000000..516ca4f3f77e0 --- /dev/null +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -0,0 +1,18 @@ +// Regression test for #66975 +#![warn(const_err)] + +struct PrintName(T); + +impl PrintName { + const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + //~^ WARN any use of this value will cause an error +} + +fn f() { + let _ = PrintName::::VOID; + //~^ ERROR erroneous constant encountered +} + +pub fn main() { + f::<()>(); +} diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr new file mode 100644 index 0000000000000..e2bd8d0cc85ea --- /dev/null +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -0,0 +1,22 @@ +warning: any use of this value will cause an error + --> $DIR/index-out-of-bounds-never-type.rs:7:61 + | +LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + | --------------------------------------------------------^^^^^--- + | | + | index out of bounds: the len is 0 but the index is 0 + | +note: lint level defined here + --> $DIR/index-out-of-bounds-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + +error: erroneous constant encountered + --> $DIR/index-out-of-bounds-never-type.rs:12:13 + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs new file mode 100644 index 0000000000000..b39d9af5546f8 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -0,0 +1,15 @@ +// Regression test for #66975 +#![warn(const_err)] +#![feature(const_panic)] + +struct PrintName; + +impl PrintName { + const VOID: ! = panic!(); + //~^ WARN any use of this value will cause an error +} + +fn main() { + let _ = PrintName::VOID; + //~^ ERROR erroneous constant used +} diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr new file mode 100644 index 0000000000000..c07c8c65a2f20 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -0,0 +1,24 @@ +warning: any use of this value will cause an error + --> $DIR/panic-assoc-never-type.rs:8:21 + | +LL | const VOID: ! = panic!(); + | ----------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:8:21 + | +note: lint level defined here + --> $DIR/panic-assoc-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> $DIR/panic-assoc-never-type.rs:13:13 + | +LL | let _ = PrintName::VOID; + | ^^^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs new file mode 100644 index 0000000000000..42eabbf58470f --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -0,0 +1,11 @@ +// Regression test for #66975 +#![warn(const_err)] +#![feature(const_panic)] + +const VOID: ! = panic!(); +//~^ WARN any use of this value will cause an error + +fn main() { + let _ = VOID; + //~^ ERROR erroneous constant used +} diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr new file mode 100644 index 0000000000000..4fb11a61525f4 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-never-type.stderr @@ -0,0 +1,24 @@ +warning: any use of this value will cause an error + --> $DIR/panic-never-type.rs:5:17 + | +LL | const VOID: ! = panic!(); + | ----------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17 + | +note: lint level defined here + --> $DIR/panic-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> $DIR/panic-never-type.rs:9:13 + | +LL | let _ = VOID; + | ^^^^ referenced constant has errors + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From c96fd6f27497554b8258293a3fce619ba2bfd98a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 22 Nov 2019 20:28:02 +0000 Subject: [PATCH 20/47] Make const index and subslice array projections more useful * `min_length` is now exact for const index elements. * const index elements are always from the start. * make array `Subslice` `PlaceElems` count both `from` and `to` from the start. --- src/librustc/mir/mod.rs | 24 +++++++---- src/librustc/mir/tcx.rs | 9 ++-- src/librustc/mir/visit.rs | 2 +- src/librustc_codegen_ssa/mir/place.rs | 3 +- .../borrow_check/nll/type_check/mod.rs | 23 ++++------ .../borrow_check/places_conflict.rs | 42 +++++++++++++++---- src/librustc_mir/build/matches/util.rs | 31 ++++++++++---- .../dataflow/move_paths/abs_domain.rs | 4 +- src/librustc_mir/dataflow/move_paths/mod.rs | 5 ++- src/librustc_mir/interpret/place.rs | 14 +++++-- src/librustc_mir/transform/elaborate_drops.rs | 7 ++-- 11 files changed, 110 insertions(+), 54 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a89bc28f40dd2..ba8feb4ee739d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1714,18 +1714,25 @@ pub enum ProjectionElem { ConstantIndex { /// index or -index (in Python terms), depending on from_end offset: u32, - /// thing being indexed must be at least this long + /// The thing being indexed must be at least this long. For arrays this + /// is always the exact length. min_length: u32, - /// counting backwards from end? + /// Counting backwards from end? This is always false when indexing an + /// array. from_end: bool, }, /// These indices are generated by slice patterns. /// - /// slice[from:-to] in Python terms. + /// If `from_end` is true `slice[from..slice.len() - to]`. + /// Otherwise `array[from..to]`. Subslice { from: u32, to: u32, + /// Whether `to` counts from the start or end of the array/slice. + /// For `PlaceElem`s this is `true` if and only if the base is a slice. + /// For `ProjectionKind`, this can also be `true` for arrays. + from_end: bool, }, /// "Downcast" to a variant of an ADT. Currently, we only introduce @@ -1914,15 +1921,18 @@ impl Debug for Place<'_> { ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; } - ProjectionElem::Subslice { from, to } if *to == 0 => { + ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => { write!(fmt, "[{:?}:]", from)?; } - ProjectionElem::Subslice { from, to } if *from == 0 => { + ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => { write!(fmt, "[:-{:?}]", to)?; } - ProjectionElem::Subslice { from, to } => { + ProjectionElem::Subslice { from, to, from_end: true } => { write!(fmt, "[{:?}:-{:?}]", from, to)?; } + ProjectionElem::Subslice { from, to, from_end: false } => { + write!(fmt, "[{:?}..{:?}]", from, to)?; + } } } @@ -2456,7 +2466,7 @@ impl UserTypeProjection { } pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { - self.projs.push(ProjectionElem::Subslice { from, to }); + self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); self } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index a66a49f103f68..445fa6ea8cab3 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -88,14 +88,17 @@ impl<'tcx> PlaceTy<'tcx> { } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => PlaceTy::from_ty(self.ty.builtin_index().unwrap()), - ProjectionElem::Subslice { from, to } => { + ProjectionElem::Subslice { from, to, from_end } => { PlaceTy::from_ty(match self.ty.kind { - ty::Array(inner, size) => { + ty::Slice(..) => self.ty, + ty::Array(inner, _) if !from_end => { + tcx.mk_array(inner, (to - from) as u64) + } + ty::Array(inner, size) if from_end => { let size = size.eval_usize(tcx, param_env); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } - ty::Slice(..) => self.ty, _ => { bug!("cannot subslice non-array type: `{:?}`", self) } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 703e0cc78c207..5d273fe85b6d2 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -954,7 +954,7 @@ macro_rules! visit_place_fns { ); } ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _ } | + ProjectionElem::Subslice { from: _, to: _, from_end: _ } | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } | diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index e60b8861faf85..5e13cabced000 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -565,7 +565,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llindex = bx.sub(lllen, lloffset); cg_base.project_index(bx, llindex) } - mir::ProjectionElem::Subslice { from, to } => { + mir::ProjectionElem::Subslice { from, to, from_end } => { let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(*from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) @@ -573,6 +573,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { + assert!(from_end, "slice subslices should be `from_end`"); subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(), bx.cx().const_usize((*from as u64) + (*to as u64)))); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index cddc3b4a271d4..1e3723edc564f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -675,23 +675,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }), ) } - ProjectionElem::Subslice { from, to } => PlaceTy::from_ty( + ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty( match base_ty.kind { - ty::Array(inner, size) => { - let size = size.eval_usize(tcx, self.cx.param_env); - let min_size = (from as u64) + (to as u64); - if let Some(rest_size) = size.checked_sub(min_size) { - tcx.mk_array(inner, rest_size) - } else { - span_mirbug_and_err!( - self, - place, - "taking too-small slice of {:?}", - base_ty - ) - } + ty::Array(inner, _) => { + assert!(!from_end, "array subslices should not use from_end"); + tcx.mk_array(inner, (to - from) as u64) } - ty::Slice(..) => base_ty, + ty::Slice(..) => { + assert!(from_end, "slice subslices should use from_end"); + base_ty + }, _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }, ), diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 87a431a7fb80d..f0420a2359784 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -503,34 +503,62 @@ fn place_projection_conflict<'tcx>( Overlap::Disjoint } } + ( + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ProjectionElem::Subslice { from, to, from_end: false } + ) + | ( + ProjectionElem::Subslice { from, to, from_end: false }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } + ) => { + if (from..to).contains(&offset) { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, ProjectionElem::Subslice {from, .. }) | (ProjectionElem::Subslice {from, .. }, ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => { if offset >= from { debug!( - "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + "place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE"); Overlap::EqualOrDisjoint } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE"); Overlap::Disjoint } } (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice {from: _, to }) - | (ProjectionElem::Subslice {from: _, to }, + ProjectionElem::Subslice { to, .. }) + | (ProjectionElem::Subslice { to, .. }, ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { if offset > to { debug!("place_element_conflict: \ - DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); Overlap::EqualOrDisjoint } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::Subslice { from: f1, to: t1, from_end: false }, + ProjectionElem::Subslice { from: f2, to: t2, from_end: false } + ) => { + if f2 >= t1 || f1 >= t2 { + debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES"); Overlap::Disjoint + } else { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + Overlap::EqualOrDisjoint } } (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); Overlap::EqualOrDisjoint } (ProjectionElem::Deref, _) diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index aec9e6e57d46c..ec8b3c5e24bf2 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -2,6 +2,7 @@ use crate::build::Builder; use crate::build::matches::MatchPair; use crate::hair::*; use rustc::mir::*; +use rustc::ty; use smallvec::SmallVec; use std::u32; use std::convert::TryInto; @@ -31,9 +32,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { prefix: &'pat [Pat<'tcx>], opt_slice: Option<&'pat Pat<'tcx>>, suffix: &'pat [Pat<'tcx>]) { - let min_length = prefix.len() + suffix.len(); - let min_length = min_length.try_into().unwrap(); let tcx = self.hir.tcx(); + let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind { + ty::Array(_, length) => ( + length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), + true + ), + _ => ( + (prefix.len() + suffix.len()).try_into().unwrap(), + false, + ), + }; match_pairs.extend( prefix.iter() @@ -50,10 +59,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); if let Some(subslice_pat) = opt_slice { - let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice { - from: prefix.len() as u32, - to: suffix.len() as u32 - }); + let suffix_len = suffix.len() as u32; + let subslice = tcx.mk_place_elem( + place.clone(), + ProjectionElem::Subslice { + from: prefix.len() as u32, + to: if exact_size { min_length - suffix_len } else { suffix_len }, + from_end: !exact_size, + }, + ); match_pairs.push(MatchPair::new(subslice, subslice_pat)); } @@ -62,10 +76,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .rev() .enumerate() .map(|(idx, subpattern)| { + let end_offset = (idx + 1) as u32; let elem = ProjectionElem::ConstantIndex { - offset: (idx+1) as u32, + offset: if exact_size { min_length - end_offset } else { end_offset }, min_length, - from_end: true, + from_end: !exact_size, }; let place = tcx.mk_place_elem(place.clone(), elem); MatchPair::new(place, subpattern) diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs index d97f3b7417286..0665c0fb72c46 100644 --- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs +++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs @@ -49,8 +49,8 @@ impl<'tcx> Lift for PlaceElem<'tcx> { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), - ProjectionElem::Subslice { from, to } => { - ProjectionElem::Subslice { from: from, to: to } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::ConstantIndex { offset, min_length, from_end } => { ProjectionElem::ConstantIndex { offset, min_length, from_end } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index b599f4799446d..89ef9b245ce8f 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -1,6 +1,6 @@ use core::slice::Iter; use rustc::mir::*; -use rustc::ty::{Ty, TyCtxt}; +use rustc::ty::{Ty, TyCtxt, ParamEnv}; use rustc::util::nodemap::FxHashMap; use rustc_index::vec::{Enumerated, Idx, IndexVec}; use smallvec::SmallVec; @@ -318,8 +318,9 @@ impl<'tcx> MoveData<'tcx> { pub fn gather_moves( body: &Body<'tcx>, tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, ) -> Result, MoveError<'tcx>)>)> { - builder::gather_moves(body, tcx) + builder::gather_moves(body, tcx, param_env) } /// For the move path `mpi`, returns the root local variable (if any) that starts the path. diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index a600eb11e1d03..42fbfeca3f05d 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -451,9 +451,15 @@ where base: MPlaceTy<'tcx, M::PointerTag>, from: u64, to: u64, + from_end: bool, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let len = base.len(self)?; // also asserts that we have a type where this makes sense - assert!(from <= len - to); + let actual_to = if from_end { + assert!(from <= len - to); + len - to + } else { + to + }; // Not using layout method because that works with usize, and does not work with slices // (that have count 0 in their layout). @@ -464,7 +470,7 @@ where }; // Compute meta and new layout - let inner_len = len - to - from; + let inner_len = actual_to - from; let (meta, ty) = match base.layout.ty.kind { // It is not nice to match on the type, but that seems to be the only way to // implement this. @@ -528,8 +534,8 @@ where self.mplace_field(base, index)? } - Subslice { from, to } => - self.mplace_subslice(base, u64::from(from), u64::from(to))?, + Subslice { from, to, from_end } => + self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?, }) } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 9970752a37698..8cc8883b9019f 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -234,12 +234,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + debug_assert!(size == *min_length, "min_length should be exact for arrays"); + assert!(!from_end, "from_end should not be used for array element ConstantIndex"); *offset == index } - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => { - size - offset == index - } _ => false, }) } From 16785505e4c1ded18767612e62eb1ac7733efa99 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 22 Nov 2019 22:03:25 +0000 Subject: [PATCH 21/47] Remove `uniform_array_move_out` passes These passes were buggy, MIR building is now responsible for canonicalizing `ConstantIndex` projections and `MoveData` is responsible for splitting `Subslice` projections. --- .../diagnostics/conflict_errors.rs | 5 +- src/librustc_mir/borrow_check/mod.rs | 67 ++- .../borrow_check/places_conflict.rs | 4 +- .../dataflow/move_paths/builder.rs | 131 ++++-- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/mod.rs | 3 - src/librustc_mir/transform/rustc_peek.rs | 2 +- .../transform/uniform_array_move_out.rs | 381 ------------------ src/test/mir-opt/const_prop/return_place.rs | 6 - src/test/mir-opt/uniform_array_move_out.rs | 56 +-- 10 files changed, 168 insertions(+), 489 deletions(-) delete mode 100644 src/librustc_mir/transform/uniform_array_move_out.rs diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 252b31e4d3c37..1cd43d4fdd411 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -78,10 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .collect(); if move_out_indices.is_empty() { - let root_place = self - .prefixes(used_place, PrefixSet::All) - .last() - .unwrap(); + let root_place = PlaceRef { projection: &[], ..used_place }; if !self.uninitialized_error_reported.insert(root_place) { debug!( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 427003f24cb14..0cec19394a7f1 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -174,7 +174,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut errors_buffer = Vec::new(); let (move_data, move_errors): (MoveData<'tcx>, Option, MoveError<'tcx>)>>) = - match MoveData::gather_moves(&body, tcx) { + match MoveData::gather_moves(&body, tcx, param_env) { Ok(move_data) => (move_data, None), Err((move_data, move_errors)) => (move_data, Some(move_errors)), }; @@ -1600,7 +1600,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (prefix, place_span.0, place_span.1), mpi, ); - return; // don't bother finding other problems. } } Err(NoMovePathFound::ReachedStatic) => { @@ -1614,6 +1613,46 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + /// Subslices correspond to multiple move paths, so we iterate through the + /// elements of the base array. For each element we check + /// + /// * Does this element overlap with our slice. + /// * Is any part of it uninitialized. + fn check_if_subslice_element_is_moved( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + place_span: (PlaceRef<'cx, 'tcx>, Span), + maybe_uninits: &FlowAtLocation<'tcx, MaybeUninitializedPlaces<'cx, 'tcx>>, + from: u32, + to: u32, + ) { + if let Some(mpi) = self.move_path_for_place(place_span.0) { + let mut child = self.move_data.move_paths[mpi].first_child; + while let Some(child_mpi) = child { + let child_move_place = &self.move_data.move_paths[child_mpi]; + let child_place = &child_move_place.place; + let last_proj = child_place.projection.last().unwrap(); + if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj { + debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`."); + + if (from..to).contains(offset) { + if let Some(uninit_child) = maybe_uninits.has_any_child_of(child_mpi) { + self.report_use_of_moved_or_uninitialized( + location, + desired_action, + (place_span.0, place_span.0, place_span.1), + uninit_child, + ); + return; // don't bother finding other problems. + } + } + } + child = child_move_place.next_sibling; + } + } + } + fn check_if_path_or_subpath_is_moved( &mut self, location: Location, @@ -1640,6 +1679,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); + if let [ + base_proj @ .., + ProjectionElem::Subslice { from, to, from_end: false }, + ] = place_span.0.projection { + let place_ty = Place::ty_from( + place_span.0.base, + base_proj, + self.body(), + self.infcx.tcx, + ); + if let ty::Array(..) = place_ty.ty.kind { + let array_place = PlaceRef { base: place_span.0.base, projection: base_proj }; + self.check_if_subslice_element_is_moved( + location, + desired_action, + (array_place, place_span.1), + maybe_uninits, + *from, + *to, + ); + return; + } + } + // A move of any shallow suffix of `place` also interferes // with an attempt to use `place`. This is scenario 3 above. // diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index f0420a2359784..9245064f87594 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -533,8 +533,8 @@ fn place_projection_conflict<'tcx>( } } (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice { to, .. }) - | (ProjectionElem::Subslice { to, .. }, + ProjectionElem::Subslice { to, from_end: true, .. }) + | (ProjectionElem::Subslice { to, from_end: true, .. }, ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { if offset > to { debug!("place_element_conflict: \ diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 52016d4c9363a..fa0864e0de760 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt}; use rustc_index::vec::IndexVec; use smallvec::{smallvec, SmallVec}; -use std::collections::hash_map::Entry; +use std::convert::TryInto; use std::mem; use super::abs_domain::Lift; @@ -17,12 +17,13 @@ use super::{ struct MoveDataBuilder<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, } impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { - fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { let mut move_paths = IndexVec::new(); let mut path_map = IndexVec::new(); let mut init_path_map = IndexVec::new(); @@ -30,6 +31,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { MoveDataBuilder { body, tcx, + param_env, errors: Vec::new(), data: MoveData { moves: IndexVec::new(), @@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { InteriorOfSliceOrArray { ty: place_ty, is_index: true }, )); } - _ => { - // FIXME: still badly broken - } + _ => {} }, _ => {} }; - let proj = &place.projection[..i+1]; - base = match self - .builder - .data - .rev_lookup - .projections - .entry((base, elem.lift())) - { - Entry::Occupied(ent) => *ent.get(), - Entry::Vacant(ent) => { - let path = MoveDataBuilder::new_move_path( - &mut self.builder.data.move_paths, - &mut self.builder.data.path_map, - &mut self.builder.data.init_path_map, - Some(base), - Place { - base: place.base.clone(), - projection: tcx.intern_place_elems(proj), - }, - ); - ent.insert(path); - path - } - }; + base = self.add_move_path(base, elem, |tcx| { + Place { + base: place.base.clone(), + projection: tcx.intern_place_elems(&place.projection[..i+1]), + } + }); } Ok(base) } + fn add_move_path( + &mut self, + base: MovePathIndex, + elem: &PlaceElem<'tcx>, + mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, + ) -> MovePathIndex { + let MoveDataBuilder { + data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, + tcx, + .. + } = self.builder; + *rev_lookup.projections + .entry((base, elem.lift())) + .or_insert_with(move || { + let path = MoveDataBuilder::new_move_path( + move_paths, + path_map, + init_path_map, + Some(base), + mk_place(*tcx), + ); + path + }) + } + fn create_move_path(&mut self, place: &Place<'tcx>) { // This is an non-moving access (such as an overwrite or // drop), so this not being a valid move path is OK. @@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { pub(super) fn gather_moves<'tcx>( body: &Body<'tcx>, tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { - let mut builder = MoveDataBuilder::new(body, tcx); + let mut builder = MoveDataBuilder::new(body, tcx, param_env); builder.gather_args(); @@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_move(&mut self, place: &Place<'tcx>) { debug!("gather_move({:?}, {:?})", self.loc, place); - let path = match self.move_path_for(place) { - Ok(path) | Err(MoveError::UnionMove { path }) => path, - Err(error @ MoveError::IllegalMove { .. }) => { - self.builder.errors.push((place.clone(), error)); - return; + if let [ + ref base @ .., + ProjectionElem::Subslice { from, to, from_end: false }, + ] = **place.projection { + // Split `Subslice` patterns into the corresponding list of + // `ConstIndex` patterns. This is done to ensure that all move paths + // are disjoint, which is expected by drop elaboration. + let base_place = Place { + base: place.base.clone(), + projection: self.builder.tcx.intern_place_elems(base), + }; + let base_path = match self.move_path_for(&base_place) { + Ok(path) => path, + Err(MoveError::UnionMove { path }) => { + self.record_move(place, path); + return; + } + Err(error @ MoveError::IllegalMove { .. }) => { + self.builder.errors.push((base_place, error)); + return; + } + }; + let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; + let len: u32 = match base_ty.kind { + ty::Array(_, size) => { + let length = size.eval_usize(self.builder.tcx, self.builder.param_env); + length.try_into().expect( + "slice pattern of array with more than u32::MAX elements" + ) + } + _ => bug!("from_end: false slice pattern of non-array type"), + }; + for offset in from..to { + let elem = ProjectionElem::ConstantIndex { + offset, + min_length: len, + from_end: false, + }; + let path = self.add_move_path( + base_path, + &elem, + |tcx| tcx.mk_place_elem(base_place.clone(), elem), + ); + self.record_move(place, path); } - }; - let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc }); + } else { + match self.move_path_for(place) { + Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path), + Err(error @ MoveError::IllegalMove { .. }) => { + self.builder.errors.push((place.clone(), error)); + } + }; + } + } + fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) { + let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc }); debug!( "gather_move({:?}, {:?}): adding move {:?} of {:?}", self.loc, place, move_out, path ); - self.builder.data.path_map[path].push(move_out); self.builder.data.loc_map[self.loc].push(move_out); } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 8cc8883b9019f..1cacf1f3b0a57 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let def_id = src.def_id(); let param_env = tcx.param_env(src.def_id()).with_reveal_all(); - let move_data = match MoveData::gather_moves(body, tcx) { + let move_data = match MoveData::gather_moves(body, tcx, param_env) { Ok(move_data) => move_data, Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"), }; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index bedf2a95c026e..2e1a08a022472 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -35,7 +35,6 @@ pub mod copy_prop; pub mod const_prop; pub mod generator; pub mod inline; -pub mod uniform_array_move_out; pub mod uninhabited_enum_branching; pub(crate) fn provide(providers: &mut Providers<'_>) { @@ -229,7 +228,6 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, - &uniform_array_move_out::UniformArrayMoveOut, ]); body.ensure_predecessors(); tcx.alloc_steal_mir(body) @@ -294,7 +292,6 @@ fn run_optimization_passes<'tcx>( // Optimizations begin. &uninhabited_enum_branching::UninhabitedEnumBranching, &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), - &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx), &inline::Inline, // Lowering generator control-flow and variables diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 2a81e97b8ff25..4345fc66bb95e 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); - let move_data = MoveData::gather_moves(body, tcx).unwrap(); + let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let flow_inits = diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs deleted file mode 100644 index 71dd405386aa7..0000000000000 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ /dev/null @@ -1,381 +0,0 @@ -// This pass converts move out from array by Subslice and -// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin -// of array. It allows detect error by mir borrowck and elaborate -// drops for array without additional work. -// -// Example: -// -// let a = [ box 1,box 2, box 3]; -// if b { -// let [_a.., _] = a; -// } else { -// let [.., _b] = a; -// } -// -// mir statement _10 = move _2[:-1]; replaced by: -// StorageLive(_12); -// _12 = move _2[0 of 3]; -// StorageLive(_13); -// _13 = move _2[1 of 3]; -// _10 = [move _12, move _13] -// StorageDead(_12); -// StorageDead(_13); -// -// and mir statement _11 = move _2[-1 of 1]; replaced by: -// _11 = move _2[2 of 3]; -// -// FIXME: integrate this transformation to the mir build - -use rustc::ty; -use rustc::ty::TyCtxt; -use rustc::mir::*; -use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext}; -use rustc_index::vec::{IndexVec}; -use crate::transform::{MirPass, MirSource}; -use crate::util::patch::MirPatch; - -pub struct UniformArrayMoveOut; - -impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) { - let mut patch = MirPatch::new(body); - let param_env = tcx.param_env(src.def_id()); - { - let read_only_cache = read_only!(body); - let mut visitor - = UniformArrayMoveOutVisitor{ body, patch: &mut patch, tcx, param_env}; - visitor.visit_body(read_only_cache); - } - patch.apply(body); - } -} - -struct UniformArrayMoveOutVisitor<'a, 'tcx> { - body: &'a Body<'tcx>, - patch: &'a mut MirPatch<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { - fn visit_assign(&mut self, - dst_place: &Place<'tcx>, - rvalue: &Rvalue<'tcx>, - location: Location) { - if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { - if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() { - if let ProjectionElem::ConstantIndex{offset: _, - min_length: _, - from_end: false} = elem { - // no need to transformation - } else { - let place_ty = - Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty; - if let ty::Array(item_ty, const_size) = place_ty.kind { - if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) { - assert!(size <= u32::max_value() as u64, - "uniform array move out doesn't supported - for array bigger then u32"); - self.uniform( - location, - dst_place, - &src_place.base, - &src_place.projection, - item_ty, - size as u32, - ); - } - } - - } - } - } - self.super_assign(dst_place, rvalue, location) - } -} - -impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { - fn uniform(&mut self, - location: Location, - dst_place: &Place<'tcx>, - base: &PlaceBase<'tcx>, - proj: &[PlaceElem<'tcx>], - item_ty: &'tcx ty::TyS<'tcx>, - size: u32) { - if let [proj_base @ .., elem] = proj { - match elem { - // uniforms statements like_10 = move _2[:-1]; - ProjectionElem::Subslice{from, to} => { - self.patch.make_nop(location); - let temps : Vec<_> = (*from..(size-*to)).map(|i| { - let temp = - self.patch.new_temp(item_ty, self.body.source_info(location).span); - self.patch.add_statement(location, StatementKind::StorageLive(temp)); - - let mut projection = proj_base.to_vec(); - projection.push(ProjectionElem::ConstantIndex { - offset: i, - min_length: size, - from_end: false, - }); - self.patch.add_assign( - location, - Place::from(temp), - Rvalue::Use(Operand::Move(Place { - base: base.clone(), - projection: self.tcx.intern_place_elems(&projection), - })), - ); - temp - }).collect(); - self.patch.add_assign( - location, - dst_place.clone(), - Rvalue::Aggregate( - box AggregateKind::Array(item_ty), - temps.iter().map( - |x| Operand::Move(Place::from(*x)) - ).collect() - ) - ); - for temp in temps { - self.patch.add_statement(location, StatementKind::StorageDead(temp)); - } - } - // uniforms statements like _11 = move _2[-1 of 1]; - ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { - self.patch.make_nop(location); - - let mut projection = proj_base.to_vec(); - projection.push(ProjectionElem::ConstantIndex { - offset: size - offset, - min_length: size, - from_end: false, - }); - self.patch.add_assign( - location, - dst_place.clone(), - Rvalue::Use(Operand::Move(Place { - base: base.clone(), - projection: self.tcx.intern_place_elems(&projection), - })), - ); - } - _ => {} - } - } - } -} - -// Restore Subslice move out after analysis -// Example: -// -// next statements: -// StorageLive(_12); -// _12 = move _2[0 of 3]; -// StorageLive(_13); -// _13 = move _2[1 of 3]; -// _10 = [move _12, move _13] -// StorageDead(_12); -// StorageDead(_13); -// -// replaced by _10 = move _2[:-1]; - -pub struct RestoreSubsliceArrayMoveOut<'tcx> { - tcx: TyCtxt<'tcx> -} - -impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) { - let mut patch = MirPatch::new(body); - let param_env = tcx.param_env(src.def_id()); - { - let read_only_cache = read_only!(body); - let mut visitor = RestoreDataCollector { - locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls), - candidates: vec![], - }; - visitor.visit_body(read_only_cache); - - for candidate in &visitor.candidates { - let statement = &body[candidate.block].statements[candidate.statement_index]; - if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind { - if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval { - let items : Vec<_> = items.iter().map(|item| { - if let Operand::Move(place) = item { - if let Some(local) = place.as_local() { - let local_use = &visitor.locals_use[local]; - let opt_index_and_place = - Self::try_get_item_source(local_use, body); - // each local should be used twice: - // in assign and in aggregate statements - if local_use.use_count == 2 && opt_index_and_place.is_some() { - let (index, src_place) = opt_index_and_place.unwrap(); - return Some((local_use, index, src_place)); - } - } - } - None - }).collect(); - - let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); - let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = Place::ty_from( - src_place.base, - src_place.projection, - &**body, - tcx - ).ty; - if let ty::Array(_, ref size_o) = src_ty.kind { - size_o.try_eval_usize(tcx, param_env) - } else { - None - } - }); - let restore_subslice = RestoreSubsliceArrayMoveOut { tcx }; - restore_subslice - .check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place); - } - } - } - } - patch.apply(body); - } -} - -impl RestoreSubsliceArrayMoveOut<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - RestoreSubsliceArrayMoveOut { tcx } - } - - // Checks that source has size, all locals are inited from same source place and - // indices is an integer interval. If all checks pass do the replacent. - // items are Vec> - fn check_and_patch(&self, - candidate: Location, - items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>], - opt_size: Option, - patch: &mut MirPatch<'tcx>, - dst_place: &Place<'tcx>) { - let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); - - if opt_size.is_some() && items.iter().all( - |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) { - let src_place = opt_src_place.unwrap(); - - let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect(); - for i in 1..indices.len() { - if indices[i - 1] + 1 != indices[i] { - return; - } - } - - let min = *indices.first().unwrap(); - let max = *indices.last().unwrap(); - - for item in items { - let locals_use = item.unwrap().0; - patch.make_nop(locals_use.alive.unwrap()); - patch.make_nop(locals_use.dead.unwrap()); - patch.make_nop(locals_use.first_use.unwrap()); - } - patch.make_nop(candidate); - let size = opt_size.unwrap() as u32; - - let mut projection = src_place.projection.to_vec(); - projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 }); - patch.add_assign( - candidate, - dst_place.clone(), - Rvalue::Use(Operand::Move(Place { - base: src_place.base.clone(), - projection: self.tcx.intern_place_elems(&projection), - })), - ); - } - } - - fn try_get_item_source<'a>(local_use: &LocalUse, - body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> { - if let Some(location) = local_use.first_use { - let block = &body[location.block]; - if block.statements.len() > location.statement_index { - let statement = &block.statements[location.statement_index]; - if let StatementKind::Assign( - box(place, Rvalue::Use(Operand::Move(src_place))) - ) = &statement.kind { - if let (Some(_), PlaceRef { - base: _, - projection: &[.., ProjectionElem::ConstantIndex { - offset, min_length: _, from_end: false - }], - }) = (place.as_local(), src_place.as_ref()) { - if let StatementKind::Assign( - box(_, Rvalue::Use(Operand::Move(place))) - ) = &statement.kind { - if let PlaceRef { - base, - projection: &[ref proj_base @ .., _], - } = place.as_ref() { - return Some((offset, PlaceRef { - base, - projection: proj_base, - })) - } - } - } - } - } - } - None - } -} - -#[derive(Copy, Clone, Debug)] -struct LocalUse { - alive: Option, - dead: Option, - use_count: u32, - first_use: Option, -} - -impl LocalUse { - pub fn new() -> Self { - LocalUse{alive: None, dead: None, use_count: 0, first_use: None} - } -} - -struct RestoreDataCollector { - locals_use: IndexVec, - candidates: Vec, -} - -impl<'tcx> Visitor<'tcx> for RestoreDataCollector { - fn visit_assign(&mut self, - place: &Place<'tcx>, - rvalue: &Rvalue<'tcx>, - location: Location) { - if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue { - self.candidates.push(location); - } - self.super_assign(place, rvalue, location) - } - - fn visit_local(&mut self, - local: &Local, - context: PlaceContext, - location: Location) { - let local_use = &mut self.locals_use[*local]; - match context { - PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location), - PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location), - PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {} - _ => { - local_use.use_count += 1; - if local_use.first_use.is_none() { - local_use.first_use = Some(location); - } - } - } - } -} diff --git a/src/test/mir-opt/const_prop/return_place.rs b/src/test/mir-opt/const_prop/return_place.rs index cc9951b554dce..ea7c1e7ccd0cb 100644 --- a/src/test/mir-opt/const_prop/return_place.rs +++ b/src/test/mir-opt/const_prop/return_place.rs @@ -21,9 +21,6 @@ fn main() { // _0 = move (_1.0: u32); // return; // } -// bb2 (cleanup): { -// resume; -// } // } // END rustc.add.ConstProp.before.mir // START rustc.add.ConstProp.after.mir @@ -38,9 +35,6 @@ fn main() { // _0 = const 4u32; // return; // } -// bb2 (cleanup): { -// resume; -// } // } // END rustc.add.ConstProp.after.mir // START rustc.add.PreCodegen.before.mir diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs index c249154c71e23..f2e1864096ea9 100644 --- a/src/test/mir-opt/uniform_array_move_out.rs +++ b/src/test/mir-opt/uniform_array_move_out.rs @@ -18,58 +18,12 @@ fn main() { // END RUST SOURCE -// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir -// StorageLive(_6); -// _6 = move _1[-1 of 1]; -// _0 = (); -// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir - -// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir -// StorageLive(_6); +// START rustc.move_out_from_end.mir_map.0.mir // _6 = move _1[1 of 2]; -// nop; // _0 = (); -// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir - -// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir -// StorageLive(_6); -// _6 = move _1[0:]; -// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir - -// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir -// StorageLive(_6); -// StorageLive(_7); -// _7 = move _1[0 of 2]; -// StorageLive(_8); -// _8 = move _1[1 of 2]; -// _6 = [move _7, move _8]; -// StorageDead(_7); -// StorageDead(_8); -// nop; -// _0 = (); -// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir - -// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir -// StorageLive(_6); -// StorageLive(_7); -// _7 = move _1[0 of 2]; -// StorageLive(_8); -// _8 = move _1[1 of 2]; -// _6 = [move _7, move _8]; -// StorageDead(_7); -// StorageDead(_8); -// _0 = (); -// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir +// END rustc.move_out_from_end.mir_map.0.mir -// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir -// StorageLive(_6); -// nop; -// nop; -// nop; -// nop; -// _6 = move _1[0:]; -// nop; -// nop; -// nop; +// START rustc.move_out_by_subslice.mir_map.0.mir +// _6 = move _1[0..2]; // _0 = (); -// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir +// END rustc.move_out_by_subslice.mir_map.0.mir From 4793a345209b1a76105f0227702be81cdec2fc8a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 22 Nov 2019 22:08:03 +0000 Subject: [PATCH 22/47] Check for `ConstantIndex` move paths correctly in borrowck --- src/librustc_mir/borrow_check/mod.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 0cec19394a7f1..b4f2e2377ac7d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1738,25 +1738,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// static variable, as we do not track those in the MoveData. fn move_path_closest_to( &mut self, - place: PlaceRef<'cx, 'tcx>, + place: PlaceRef<'_, 'tcx>, ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> { - let mut last_prefix = place.base; - - for prefix in self.prefixes(place, PrefixSet::All) { - if let Some(mpi) = self.move_path_for_place(prefix) { - return Ok((prefix, mpi)); - } - - last_prefix = prefix.base; - } - - match last_prefix { - PlaceBase::Local(_) => panic!("should have move path for every Local"), - PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic), + match self.move_data.rev_lookup.find(place) { + LookupResult::Parent(Some(mpi)) + | LookupResult::Exact(mpi) => Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi)), + LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic), } } - fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option { + fn move_path_for_place(&mut self, place: PlaceRef<'_, 'tcx>) -> Option { // If returns None, then there is no move path corresponding // to a direct owner of `place` (which means there is nothing // that borrowck tracks for its analysis). From d6f127954e49938059b08917bc51c9c28309b8cf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 22 Nov 2019 23:15:11 +0000 Subject: [PATCH 23/47] Add more tests for borrowck and dropck slice pattern handling --- ...borrowck-move-out-from-array-no-overlap.rs | 69 +++++++++ ...owck-move-out-from-array-use-no-overlap.rs | 69 +++++++++ .../borrowck-move-out-from-array-use.rs | 99 ++++++++++++ .../borrowck-move-out-from-array-use.stderr | 143 ++++++++++++++++++ .../borrowck/borrowck-move-out-from-array.rs | 69 ++++++++- .../borrowck-move-out-from-array.stderr | 100 ++++++++++-- ...e-pattern-element-loan-array-no-overlap.rs | 66 ++++++++ ...rrowck-slice-pattern-element-loan-array.rs | 60 ++++++++ ...ck-slice-pattern-element-loan-array.stderr | 86 +++++++++++ ...e-pattern-element-loan-slice-no-overlap.rs | 61 ++++++++ ...rowck-slice-pattern-element-loan-slice.rs} | 46 ------ ...k-slice-pattern-element-loan-slice.stderr} | 24 ++- src/test/ui/drop/dynamic-drop.rs | 32 ++++ 13 files changed, 849 insertions(+), 75 deletions(-) create mode 100644 src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs create mode 100644 src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs create mode 100644 src/test/ui/borrowck/borrowck-move-out-from-array-use.rs create mode 100644 src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr create mode 100644 src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs create mode 100644 src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs create mode 100644 src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr create mode 100644 src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs rename src/test/ui/borrowck/{borrowck-slice-pattern-element-loan.rs => borrowck-slice-pattern-element-loan-slice.rs} (65%) rename src/test/ui/borrowck/{borrowck-slice-pattern-element-loan.stderr => borrowck-slice-pattern-element-loan-slice.stderr} (89%) diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs new file mode 100644 index 0000000000000..8f274cf73cb0e --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs @@ -0,0 +1,69 @@ +// check-pass + +#![feature(slice_patterns)] + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + let [_, _, _x] = a; + let [.., _y, _] = a; +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_, _y)] = a; +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [_, _y @ ..] = a; +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_y @ .., _] = a; +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_, _y @ ..] = a; +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_y @ .., _] = a; +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + let [_, _y @ ..] = a; + let [(_x, _), _, _] = a; +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + let [_y @ .., _] = a; + let [.., (_x, _)] = a; +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _, _] = a; + let [_, _y @ ..] = a; +} + +fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs new file mode 100644 index 0000000000000..57ce2417570b0 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs @@ -0,0 +1,69 @@ +// check-pass + +#![feature(slice_patterns)] + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + let [_, _, _x] = a; + let [.., ref _y, _] = a; +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_, ref _y)] = a; +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [ref _y @ .., _] = a; +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [ref _y @ .., _] = a; +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + let [_, _y @ ..] = a; + let [(ref _x, _), _, _] = a; +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + let [_y @ .., _] = a; + let [.., (ref _x, _)] = a; +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs new file mode 100644 index 0000000000000..778beefbf2c85 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs @@ -0,0 +1,99 @@ +#![feature(slice_patterns)] + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_end() { + let a = array(); + let [_, _, _x] = a; + let [.., ref _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., ref _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (ref _y, _)] = a; //~ ERROR [E0382] +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [ref _y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_, _, ref _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [ref _y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_, _, ref _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + let [_y @ .., _, _] = a; + let [(ref _x, _), _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + let [_, _, _y @ ..] = a; + let [.., (ref _x, _)] = a; //~ ERROR [E0382] +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _] = a; + let [_, ref _y @ ..] = a; //~ ERROR [E0382] +} + +// Move + Assign + +fn move_out_and_assign_end() { + let mut a = array(); + let [_, _, _x] = a; + a[2] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_and_assign_end_field() { + let mut a = array(); + let [_, _, (_x, _)] = a; + a[2].1 = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end() { + let mut a = array(); + let [_, _, _x @ ..] = a; + a[0] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end_field() { + let mut a = array(); + let [_, _, _x @ ..] = a; + a[0].1 = Default::default(); //~ ERROR [E0382] +} + +fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr new file mode 100644 index 0000000000000..2a7b89132c1b7 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -0,0 +1,143 @@ +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:12:14 + | +LL | let [_, _, _x] = a; + | -- value moved here +LL | let [.., ref _y] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:18:14 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., ref _y] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-use.rs:24:15 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., (ref _y, _)] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:32:10 + | +LL | let [_x, _, _] = a; + | -- value moved here +LL | let [ref _y @ .., _, _] = a; + | ^^^^^^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:38:16 + | +LL | let [.., _x] = a; + | -- value moved here +LL | let [_, _, ref _y @ ..] = a; + | ^^^^^^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:44:10 + | +LL | let [(_x, _), _, _] = a; + | -- value moved here +LL | let [ref _y @ .., _, _] = a; + | ^^^^^^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:50:16 + | +LL | let [.., (_x, _)] = a; + | -- value moved here +LL | let [_, _, ref _y @ ..] = a; + | ^^^^^^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:56:11 + | +LL | let [_y @ .., _, _] = a; + | ------- value moved here +LL | let [(ref _x, _), _, _] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:62:15 + | +LL | let [_, _, _y @ ..] = a; + | ------- value moved here +LL | let [.., (ref _x, _)] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:70:13 + | +LL | let [x @ .., _] = a; + | ------ value moved here +LL | let [_, ref _y @ ..] = a; + | ^^^^^^^^^^^ value borrowed here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:78:5 + | +LL | let [_, _, _x] = a; + | -- value moved here +LL | a[2] = Default::default(); + | ^^^^ value used here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:84:5 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | a[2].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:90:5 + | +LL | let [_, _, _x @ ..] = a; + | ------- value moved here +LL | a[0] = Default::default(); + | ^^^^ value used here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:96:5 + | +LL | let [_, _, _x @ ..] = a; + | ------- value moved here +LL | a[0].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.rs b/src/test/ui/borrowck/borrowck-move-out-from-array.rs index ee6abf407a304..f9d3f6f2c0724 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.rs @@ -1,16 +1,73 @@ -#![feature(box_syntax)] #![feature(slice_patterns)] +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + fn move_out_from_begin_and_end() { - let a = [box 1, box 2]; - let [_, _x] = a; + let a = array(); + let [_, _, _x] = a; + let [.., _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + let [_, _, (_x, _)] = a; let [.., _y] = a; //~ ERROR [E0382] } +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_y, _)] = a; //~ ERROR [E0382] +} + +// Const Index + Slice + fn move_out_by_const_index_and_subslice() { - let a = [box 1, box 2]; - let [_x, _] = a; - let [_y @ ..] = a; //~ ERROR [E0382] + let a = array(); + let [_x, _, _] = a; + let [_y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_, _, _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_, _, _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + let [_y @ .., _, _] = a; + let [(_x, _), _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + let [_, _, _y @ ..] = a; + let [.., (_x, _)] = a; //~ ERROR [E0382] +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _] = a; + let [_, _y @ ..] = a; //~ ERROR [E0382] } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index b34c03e6deff8..08134a2a323e7 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -1,23 +1,103 @@ error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:7:14 + --> $DIR/borrowck-move-out-from-array.rs:12:14 | -LL | let [_, _x] = a; - | -- value moved here +LL | let [_, _, _x] = a; + | -- value moved here LL | let [.., _y] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:13:10 + --> $DIR/borrowck-move-out-from-array.rs:18:14 | -LL | let [_x, _] = a; +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., _y] = a; + | ^^ value used here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:24:15 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., (_y, _)] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:32:10 + | +LL | let [_x, _, _] = a; | -- value moved here -LL | let [_y @ ..] = a; - | ^^^^^^^ value used here after move +LL | let [_y @ .., _, _] = a; + | ^^^^^^^ value used here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:38:16 + | +LL | let [.., _x] = a; + | -- value moved here +LL | let [_, _, _y @ ..] = a; + | ^^^^^^^ value used here after partial move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:44:10 + | +LL | let [(_x, _), _, _] = a; + | -- value moved here +LL | let [_y @ .., _, _] = a; + | ^^^^^^^ value used here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:50:16 + | +LL | let [.., (_x, _)] = a; + | -- value moved here +LL | let [_, _, _y @ ..] = a; + | ^^^^^^^ value used here after partial move + | + = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:56:11 + | +LL | let [_y @ .., _, _] = a; + | ------- value moved here +LL | let [(_x, _), _, _] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:62:15 + | +LL | let [_, _, _y @ ..] = a; + | ------- value moved here +LL | let [.., (_x, _)] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:70:13 + | +LL | let [x @ .., _] = a; + | ------ value moved here +LL | let [_, _y @ ..] = a; + | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait -error: aborting due to 2 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs new file mode 100644 index 0000000000000..7d91a21264723 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs @@ -0,0 +1,66 @@ +// check-pass + +#![feature(slice_patterns)] + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_ok(s: &mut [i32; 4]) { + let [ref first, ref second, _, ref fourth, ..] = *s; + let [_, _, ref mut third, ..] = *s; + nop(&[first, second, third, fourth]); +} + +fn const_index_from_end_ok(s: &mut [i32; 4]) { + let [.., ref fourth, ref third, _, ref first] = *s; + let [.., ref mut second, _] = *s; + nop(&[first, second, third, fourth]); +} + +fn const_index_mixed(s: &mut [i32; 6]) { + let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + + let [ref mut from_begin0, ..] = *s; + nop(&[from_begin0, from_end1, from_end3, from_end4]); + let [_, ref mut from_begin1, ..] = *s; + nop(&[from_begin1, from_end1, from_end3, from_end4]); + + let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + + let [.., ref mut from_end1] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end1]); + let [.., ref mut from_end2, _] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + let [.., ref mut from_end4, _, _, _] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end4]); +} + +fn const_index_and_subslice_ok(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, _, ref mut tail @ ..] = *s; + nop(&[first, second]); + nop_subslice(tail); +} + +fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) { + let [.., ref second, ref first] = *s; + let [ref mut tail @ .., _, _] = *s; + nop(&[first, second]); + nop_subslice(tail); +} + +fn subslices(s: &mut [i32; 4]) { + let [_, _, ref s1 @ ..] = *s; + let [ref mut s2 @ .., _, _] = *s; + nop_subslice(s1); + nop_subslice(s2); +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_ok(&mut v); + const_index_from_end_ok(&mut v); + const_index_and_subslice_ok(&mut v); + const_index_and_subslice_from_end_ok(&mut v); + subslices(&mut v); +} diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs new file mode 100644 index 0000000000000..f03a2ab8fa8e4 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs @@ -0,0 +1,60 @@ +#![feature(slice_patterns)] + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_err(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, ref mut second2, ref mut third, ..] = *s; //~ERROR + nop(&[first, second, second2, third]); +} + +fn const_index_from_end_err(s: &mut [i32; 4]) { + let [.., ref fourth, ref third, _, ref first] = *s; + let [.., ref mut third2, _, _] = *s; //~ERROR + nop(&[first, third, third2, fourth]); +} + +fn const_index_mixed(s: &mut [i32; 6]) { + let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + + let [_, _, ref mut from_begin2, ..] = *s; //~ERROR + nop(&[from_begin2, from_end1, from_end3, from_end4]); + let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR + nop(&[from_begin3, from_end1, from_end3, from_end4]); + + let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + + let [.., ref mut from_end3, _, _] = *s; //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end3]); +} + +fn const_index_and_subslice_err(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, ref mut tail @ ..] = *s; //~ERROR + nop(&[first, second]); + nop_subslice(tail); +} + +fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) { + let [.., ref second, ref first] = *s; + let [ref mut tail @ .., _] = *s; //~ERROR + nop(&[first, second]); + nop_subslice(tail); +} + +fn subslices_overlap(s: &mut [i32; 4]) { + let [_, ref s1 @ ..] = *s; + let [ref mut s2 @ .., _, _] = *s; //~ERROR + nop_subslice(s1); + nop_subslice(s2); +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_err(&mut v); + const_index_from_end_err(&mut v); + const_index_and_subslice_err(&mut v); + const_index_and_subslice_from_end_err(&mut v); + subslices_overlap(&mut v); +} diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr new file mode 100644 index 0000000000000..e50e7eb3e2230 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr @@ -0,0 +1,86 @@ +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:8:13 + | +LL | let [ref first, ref second, ..] = *s; + | ---------- immutable borrow occurs here +LL | let [_, ref mut second2, ref mut third, ..] = *s; + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second, second2, third]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:14:14 + | +LL | let [.., ref fourth, ref third, _, ref first] = *s; + | --------- immutable borrow occurs here +LL | let [.., ref mut third2, _, _] = *s; + | ^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, third, third2, fourth]); + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:16 + | +LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + | ------------- immutable borrow occurs here +LL | +LL | let [_, _, ref mut from_begin2, ..] = *s; + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:23:19 + | +LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + | ------------- immutable borrow occurs here +... +LL | let [_, _, _, ref mut from_begin3, ..] = *s; + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:28:14 + | +LL | let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + | --------------- immutable borrow occurs here +LL | +LL | let [.., ref mut from_end3, _, _] = *s; + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:34:13 + | +LL | let [ref first, ref second, ..] = *s; + | ---------- immutable borrow occurs here +LL | let [_, ref mut tail @ ..] = *s; + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:41:10 + | +LL | let [.., ref second, ref first] = *s; + | ---------- immutable borrow occurs here +LL | let [ref mut tail @ .., _] = *s; + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:48:10 + | +LL | let [_, ref s1 @ ..] = *s; + | ----------- immutable borrow occurs here +LL | let [ref mut s2 @ .., _, _] = *s; + | ^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop_subslice(s1); + | -- immutable borrow later used here + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs new file mode 100644 index 0000000000000..e69071f87720b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs @@ -0,0 +1,61 @@ +// check-pass + +#![feature(slice_patterns)] + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_ok(s: &mut [i32]) { + if let [ref first, ref second, _, ref fourth, ..] = *s { + if let [_, _, ref mut third, ..] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_from_end_ok(s: &mut [i32]) { + if let [.., ref fourth, ref third, _, ref first] = *s { + if let [.., ref mut second, _] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_mixed(s: &mut [i32]) { + if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + if let [ref mut from_begin0, ..] = *s { + nop(&[from_begin0, from_end1, from_end3, from_end4]); + } + } + if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + if let [.., ref mut from_end1] = *s { + nop(&[from_begin0, from_begin1, from_begin3, from_end1]); + } + } +} + +fn const_index_and_subslice_ok(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, _, ref mut tail @ ..] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_from_end_ok(s: &mut [i32]) { + if let [.., ref second, ref first] = *s { + if let [ref mut tail @ .., _, _] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_ok(&mut v); + const_index_from_end_ok(&mut v); + const_index_and_subslice_ok(&mut v); + const_index_and_subslice_from_end_ok(&mut v); +} diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs similarity index 65% rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs index a6b54f9537ddc..2ef98741dc35a 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs @@ -1,18 +1,8 @@ -//compile-flags: -Z borrowck=mir - #![feature(slice_patterns)] fn nop(_s: &[& i32]) {} fn nop_subslice(_s: &[i32]) {} -fn const_index_ok(s: &mut [i32]) { - if let [ref first, ref second, _, ref fourth, ..] = *s { - if let [_, _, ref mut third, ..] = *s { - nop(&[first, second, third, fourth]); - } - } -} - fn const_index_err(s: &mut [i32]) { if let [ref first, ref second, ..] = *s { if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR @@ -21,14 +11,6 @@ fn const_index_err(s: &mut [i32]) { } } -fn const_index_from_end_ok(s: &mut [i32]) { - if let [.., ref fourth, ref third, _, ref first] = *s { - if let [.., ref mut second, _] = *s { - nop(&[first, second, third, fourth]); - } - } -} - fn const_index_from_end_err(s: &mut [i32]) { if let [.., ref fourth, ref third, _, ref first] = *s { if let [.., ref mut third2, _, _] = *s { //~ERROR @@ -39,9 +21,6 @@ fn const_index_from_end_err(s: &mut [i32]) { fn const_index_mixed(s: &mut [i32]) { if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { - if let [ref mut from_begin0, ..] = *s { - nop(&[from_begin0, from_end1, from_end3, from_end4]); - } if let [_, ref mut from_begin1, ..] = *s { //~ERROR nop(&[from_begin1, from_end1, from_end3, from_end4]); } @@ -53,9 +32,6 @@ fn const_index_mixed(s: &mut [i32]) { } } if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { - if let [.., ref mut from_end1] = *s { - nop(&[from_begin0, from_begin1, from_begin3, from_end1]); - } if let [.., ref mut from_end2, _] = *s { //~ERROR nop(&[from_begin0, from_begin1, from_begin3, from_end2]); } @@ -68,15 +44,6 @@ fn const_index_mixed(s: &mut [i32]) { } } -fn const_index_and_subslice_ok(s: &mut [i32]) { - if let [ref first, ref second, ..] = *s { - if let [_, _, ref mut tail @ ..] = *s { - nop(&[first, second]); - nop_subslice(tail); - } - } -} - fn const_index_and_subslice_err(s: &mut [i32]) { if let [ref first, ref second, ..] = *s { if let [_, ref mut tail @ ..] = *s { //~ERROR @@ -86,15 +53,6 @@ fn const_index_and_subslice_err(s: &mut [i32]) { } } -fn const_index_and_subslice_from_end_ok(s: &mut [i32]) { - if let [.., ref second, ref first] = *s { - if let [ref mut tail @ .., _, _] = *s { - nop(&[first, second]); - nop_subslice(tail); - } - } -} - fn const_index_and_subslice_from_end_err(s: &mut [i32]) { if let [.., ref second, ref first] = *s { if let [ref mut tail @ .., _] = *s { //~ERROR @@ -115,13 +73,9 @@ fn subslices(s: &mut [i32]) { fn main() { let mut v = [1,2,3,4]; - const_index_ok(&mut v); const_index_err(&mut v); - const_index_from_end_ok(&mut v); const_index_from_end_err(&mut v); - const_index_and_subslice_ok(&mut v); const_index_and_subslice_err(&mut v); - const_index_and_subslice_from_end_ok(&mut v); const_index_and_subslice_from_end_err(&mut v); subslices(&mut v); } diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr similarity index 89% rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr index 2c019f4461182..b6f5ac64b2061 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:18:20 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:8:20 | LL | if let [ref first, ref second, ..] = *s { | ---------- immutable borrow occurs here @@ -9,7 +9,7 @@ LL | nop(&[first, second, second2, third]); | ------ immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:34:21 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:16:21 | LL | if let [.., ref fourth, ref third, _, ref first] = *s { | --------- immutable borrow occurs here @@ -19,18 +19,17 @@ LL | nop(&[first, third, third2, fourth]); | ----- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:45:20 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:24:20 | LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here -... LL | if let [_, ref mut from_begin1, ..] = *s { | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin1, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:48:23 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:27:23 | LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here @@ -41,7 +40,7 @@ LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:51:26 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:30:26 | LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here @@ -52,18 +51,17 @@ LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:59:21 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:35:21 | LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here -... LL | if let [.., ref mut from_end2, _] = *s { | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]); | ----------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:62:21 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:38:21 | LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here @@ -74,7 +72,7 @@ LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); | ----------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:65:21 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:41:21 | LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here @@ -85,7 +83,7 @@ LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]); | ----------- immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:82:20 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:49:20 | LL | if let [ref first, ref second, ..] = *s { | ---------- immutable borrow occurs here @@ -95,7 +93,7 @@ LL | nop(&[first, second]); | ------ immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:100:17 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:58:17 | LL | if let [.., ref second, ref first] = *s { | ---------- immutable borrow occurs here @@ -105,7 +103,7 @@ LL | nop(&[first, second]); | ------ immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-slice-pattern-element-loan.rs:109:17 + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:67:17 | LL | if let [_, _, _, ref s1 @ ..] = *s { | ----------- immutable borrow occurs here diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 29dcbfe9609a0..0f0ec0ba460c8 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -269,6 +269,28 @@ fn subslice_pattern_reassign(a: &Allocator) { let[_, _y @ ..] = ar; } +fn index_field_mixed_ends(a: &Allocator) { + let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; + let[(_x, _), ..] = ar; + let[(_, _y), _] = ar; + let[_, (_, _w)] = ar; + let[.., (_z, _)] = ar; +} + +fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { + let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; + match c { + 0 => { let[_x, ..] = ar; } + 1 => { let[_x, _, ..] = ar; } + 2 => { let[_x, _] = ar; } + 3 => { let[(_x, _), _, ..] = ar; } + 4 => { let[.., (_x, _)] = ar; } + 5 => { let[.., (_x, _), _] = ar; } + 6 => { let [_y @ ..] = ar; } + _ => { let [_y @ .., _] = ar; } + } +} + fn panic_after_return(a: &Allocator) -> Ptr<'_> { // Panic in the drop of `p` or `q` can leak let exceptions = vec![8, 9]; @@ -422,6 +444,16 @@ fn main() { run_test(|a| slice_pattern_reassign(a)); run_test(|a| subslice_pattern_reassign(a)); + run_test(|a| index_field_mixed_ends(a)); + run_test(|a| subslice_mixed_min_lengths(a, 0)); + run_test(|a| subslice_mixed_min_lengths(a, 1)); + run_test(|a| subslice_mixed_min_lengths(a, 2)); + run_test(|a| subslice_mixed_min_lengths(a, 3)); + run_test(|a| subslice_mixed_min_lengths(a, 4)); + run_test(|a| subslice_mixed_min_lengths(a, 5)); + run_test(|a| subslice_mixed_min_lengths(a, 6)); + run_test(|a| subslice_mixed_min_lengths(a, 7)); + run_test(|a| { panic_after_return(a); }); From 4e2ac6725f00ead648a8c265014f8bc2a81b6d08 Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Mon, 9 Dec 2019 22:49:59 -0800 Subject: [PATCH 24/47] Use Niko's wording --- src/liballoc/boxed.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index cea96f65ada62..f3baa37efbb1f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -61,14 +61,25 @@ //! T` obtained from [`Box::::into_raw`] may be deallocated using the //! [`Global`] allocator with [`Layout::for_value(&*value)`]. //! -//! `Box` has the same ABI as `&mut T`. In particular, when `T: Sized`, -//! this allows using `Box` in FFI: +//! So long as `T: Sized`, a `Box` is guaranteed to be represented as a +//! single pointer and is also ABI-compatible with C pointers (i.e. the C type +//! `T*`). This means that you have Rust code which passes ownership of a +//! `Box` to C code by using `Box` as the type on the Rust side, and +//! `T*` as the corresponding type on the C side. As an example, consider this +//! C header which declares functions that create and destroy some kind of +//! `Foo` value: //! //! ```c //! /* C header */ //! struct Foo* foo_new(void); /* Returns ownership to the caller */ //! void foo_delete(struct Foo*); /* Takes ownership from the caller */ //! ``` +//! +//! These two functions might be implemented in Rust as follows. Here, the +//! `struct Foo*` type from C is translated to `Box`, which captures +//! the ownership constraints. Note also that the nullable argument to +//! `foo_delete` is represented in Rust as `Option>`, since `Box` +//! cannot be null. //! //! ``` //! #[repr(C)] @@ -82,6 +93,14 @@ //! #[no_mangle] //! pub extern "C" fn foo_delete(_: Option>) {} //! ``` +//! +//! Even though `Box` has the same representation and C ABI as a C pointer, +//! this does not mean that you can convert an arbitrary `T*` into a `Box` +//! and expect things to work. `Box` values will always be fully aligned, +//! non-null pointers. Moreover, the destructor for `Box` will attempt to +//! free the value with the global allocator. In general, the best practice +//! is to only use `Box` for pointers that originated from the global +//! allocator. //! //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html From 6699d58ffde2ffad7d5cee535e412afd05a86c18 Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Mon, 9 Dec 2019 22:56:37 -0800 Subject: [PATCH 25/47] Specify behavior when passed a null pointer --- src/liballoc/boxed.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index f3baa37efbb1f..9089474b6e50a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -71,8 +71,12 @@ //! //! ```c //! /* C header */ -//! struct Foo* foo_new(void); /* Returns ownership to the caller */ -//! void foo_delete(struct Foo*); /* Takes ownership from the caller */ +//! +//! /* Returns ownership to the caller */ +//! struct Foo* foo_new(void); +//! +//! /* Takes ownership from the caller; no-op when invoked with NULL */ +//! void foo_delete(struct Foo*); //! ``` //! //! These two functions might be implemented in Rust as follows. Here, the From 182becc50d4a97fd93cc42a3eafff75c30eb61bf Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Tue, 10 Dec 2019 00:00:25 -0800 Subject: [PATCH 26/47] Remove trailing whitespace --- src/liballoc/boxed.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 9089474b6e50a..0c336b0495393 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -71,14 +71,14 @@ //! //! ```c //! /* C header */ -//! +//! //! /* Returns ownership to the caller */ //! struct Foo* foo_new(void); -//! +//! //! /* Takes ownership from the caller; no-op when invoked with NULL */ //! void foo_delete(struct Foo*); //! ``` -//! +//! //! These two functions might be implemented in Rust as follows. Here, the //! `struct Foo*` type from C is translated to `Box`, which captures //! the ownership constraints. Note also that the nullable argument to @@ -97,7 +97,7 @@ //! #[no_mangle] //! pub extern "C" fn foo_delete(_: Option>) {} //! ``` -//! +//! //! Even though `Box` has the same representation and C ABI as a C pointer, //! this does not mean that you can convert an arbitrary `T*` into a `Box` //! and expect things to work. `Box` values will always be fully aligned, From 2f8b040d03163cbf8a7b9de7ee2a71046fc9900d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 11 Dec 2019 05:26:40 +0900 Subject: [PATCH 27/47] Make it executable --- src/ci/publish_toolstate.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/ci/publish_toolstate.sh diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh old mode 100644 new mode 100755 From 453605dca4eadb5b7699a463bed3f04d1492f286 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Tue, 10 Dec 2019 14:30:06 -0700 Subject: [PATCH 28/47] Add better documentation for unsafe block --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 26616a2d18bae..fd4be02e20f4b 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1133,7 +1133,7 @@ mod impls { -1 => Less, 0 => Equal, 1 => Greater, - // SAFETY: Unreachable code + // SAFETY: bool as i8 returns 0 or 1, so the difference can't be anything else _ => unsafe { unreachable_unchecked() }, } } From ed28f79ab6baa1dfbd5640a97ff83dd1e2de7757 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 6 Dec 2019 15:36:14 +1100 Subject: [PATCH 29/47] Optimize `shallow_resolve_changed`. It can be made even more specialized. --- src/librustc/infer/mod.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b3ddffc8b12f1..fca7704d5eefe 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1617,38 +1617,40 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always // inlined, despite being large, because it has only two call sites that // are extremely hot. + // + // Note that `typ` is always a `ty::Infer(_)`. #[inline(always)] - pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool { + pub fn shallow_resolve_changed(&self, typ: Ty<'tcx>) -> bool { match typ.kind { ty::Infer(ty::TyVar(v)) => { use self::type_variable::TypeVariableValue; - // See the comment in `shallow_resolve()`. + // If `inlined_probe` returns a `Known` value it never matches + // `typ`. match self.infcx.type_variables.borrow_mut().inlined_probe(v) { - TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ, TypeVariableValue::Unknown { .. } => false, + TypeVariableValue::Known { .. } => true, } } ty::Infer(ty::IntVar(v)) => { - match self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v) { - Some(v) => v.to_type(self.infcx.tcx) != typ, - None => false, - } + // If inlined_probe_value returns a value it's always a + // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a + // `ty::Infer(_)`. + self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some() } ty::Infer(ty::FloatVar(v)) => { + // If inlined_probe_value returns a value it's always a + // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`. + // // Not `inlined_probe_value(v)` because this call site is colder. - match self.infcx.float_unification_table.borrow_mut().probe_value(v) { - Some(v) => v.to_type(self.infcx.tcx) != typ, - None => false, - } + self.infcx.float_unification_table.borrow_mut().probe_value(v).is_some() } - _ => false, + _ => unreachable!(), } } - } impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { From 4d77427f15b3e03ea3324f68c9e6184dc1a77fe3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 6 Dec 2019 16:57:57 +1100 Subject: [PATCH 30/47] Change `PendingPredicateObligation::stalled_on`'s type. From a `Vec` to a `Vec`, because that's a more restrictive type. This is a perf win because the ultra-hot function `shallow_resolve_changed` has less pattern-matching to do. --- src/librustc/infer/mod.rs | 16 +++++++--------- src/librustc/traits/fulfill.rs | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fca7704d5eefe..73977878af337 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1617,30 +1617,28 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always // inlined, despite being large, because it has only two call sites that // are extremely hot. - // - // Note that `typ` is always a `ty::Infer(_)`. #[inline(always)] - pub fn shallow_resolve_changed(&self, typ: Ty<'tcx>) -> bool { - match typ.kind { - ty::Infer(ty::TyVar(v)) => { + pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool { + match infer { + ty::TyVar(v) => { use self::type_variable::TypeVariableValue; - // If `inlined_probe` returns a `Known` value it never matches - // `typ`. + // If `inlined_probe` returns a `Known` value its `kind` never + // matches `infer`. match self.infcx.type_variables.borrow_mut().inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } } - ty::Infer(ty::IntVar(v)) => { + ty::IntVar(v) => { // If inlined_probe_value returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a // `ty::Infer(_)`. self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some() } - ty::Infer(ty::FloatVar(v)) => { + ty::FloatVar(v) => { // If inlined_probe_value returns a value it's always a // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`. // diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index a981162fdc326..27731990d2b62 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -65,7 +65,7 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone, Debug)] pub struct PendingPredicateObligation<'tcx> { pub obligation: PredicateObligation<'tcx>, - pub stalled_on: Vec>, + pub stalled_on: Vec, } // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -263,8 +263,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // Match arms are in order of frequency, which matters because this // code is so hot. 1 and 0 dominate; 2+ is fairly rare. 1 => { - let ty = pending_obligation.stalled_on[0]; - ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) + let infer = pending_obligation.stalled_on[0]; + ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) } 0 => { // In this case we haven't changed, but wish to make a change. @@ -274,8 +274,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // This `for` loop was once a call to `all()`, but this lower-level // form was a perf win. See #64545 for details. (|| { - for &ty in &pending_obligation.stalled_on { - if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) { + for &infer in &pending_obligation.stalled_on { + if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) { return true; } } @@ -305,6 +305,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy { + match ty.kind { + ty::Infer(infer) => infer, + _ => panic!(), + } + } + match obligation.predicate { ty::Predicate::Trait(ref data) => { let trait_obligation = obligation.with(data.clone()); @@ -459,7 +466,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.cause.span, ) { None => { - pending_obligation.stalled_on = vec![ty]; + pending_obligation.stalled_on = vec![infer_ty(ty)]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(os)) @@ -472,8 +479,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { subtype) { None => { // None means that both are unresolved. - pending_obligation.stalled_on = vec![subtype.skip_binder().a, - subtype.skip_binder().b]; + pending_obligation.stalled_on = vec![infer_ty(subtype.skip_binder().a), + infer_ty(subtype.skip_binder().b)]; ProcessResult::Unchanged } Some(Ok(ok)) => { @@ -517,7 +524,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { )) } } else { - pending_obligation.stalled_on = substs.types().collect(); + pending_obligation.stalled_on = + substs.types().map(|ty| infer_ty(ty)).collect(); ProcessResult::Unchanged } } @@ -542,13 +550,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { fn trait_ref_type_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, t: ty::PolyTraitRef<'tcx>, -) -> Vec> { +) -> Vec { t.skip_binder() // ok b/c this check doesn't care about regions .input_types() .map(|t| selcx.infcx().resolve_vars_if_possible(&t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) - .filter(|t| match t.kind { ty::Infer(_) => true, _ => false }) + .filter_map(|t| match t.kind { ty::Infer(infer) => Some(infer), _ => None }) .collect() } From 62d372cb49dc59cac38a4c01adfe66d882ca51d8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Dec 2019 14:17:41 +1100 Subject: [PATCH 31/47] Fix `-Z print-type-sizes`'s handling of zero-sized fields. Currently, the type `struct S { x: u32, y: u32, tag: () }` is incorrectly described like this: ``` print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.x`: 4 bytes print-type-size field `.tag`: 0 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 4 bytes print-type-size field `.y`: 4 bytes, alignment: 4 bytes ``` Specifically: - The `padding` line is wrong. (There is no padding.) - The `offset` and `alignment` on the `.tag` line shouldn't be printed. The problem is that multiple fields can end up with the same offset, and the printing code doesn't handle this correctly. This commit fixes it by adjusting the field sorting so that zero-sized fields are dealt with before non-zero-sized fields. With that in place, the printing code works correctly. The commit also corrects the "something is very wrong" comment. The new output looks like this: ``` print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.tag`: 0 bytes print-type-size field `.x`: 4 bytes print-type-size field `.y`: 4 bytes ``` --- src/librustc_session/code_stats.rs | 9 ++-- .../ui/print_type_sizes/zero-sized-fields.rs | 46 +++++++++++++++++++ .../print_type_sizes/zero-sized-fields.stdout | 16 +++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/print_type_sizes/zero-sized-fields.rs create mode 100644 src/test/ui/print_type_sizes/zero-sized-fields.stdout diff --git a/src/librustc_session/code_stats.rs b/src/librustc_session/code_stats.rs index 5baf0c5948f28..764d6d8eaee30 100644 --- a/src/librustc_session/code_stats.rs +++ b/src/librustc_session/code_stats.rs @@ -132,9 +132,12 @@ impl CodeStats { let mut min_offset = discr_size; - // We want to print fields by increasing offset. + // We want to print fields by increasing offset. We also want + // zero-sized fields before non-zero-sized fields, otherwise + // the loop below goes wrong; hence the `f.size` in the sort + // key. let mut fields = fields.clone(); - fields.sort_by_key(|f| f.offset); + fields.sort_by_key(|f| (f.offset, f.size)); for field in fields.iter() { let FieldInfo { ref name, offset, size, align } = *field; @@ -146,7 +149,7 @@ impl CodeStats { } if offset < min_offset { - // if this happens something is very wrong + // If this happens it's probably a union. println!("print-type-size {}field `.{}`: {} bytes, \ offset: {} bytes, \ alignment: {} bytes", diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs new file mode 100644 index 0000000000000..2ad488e8d8fb9 --- /dev/null +++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs @@ -0,0 +1,46 @@ +// compile-flags: -Z print-type-sizes +// build-pass (FIXME(62277): could be check-pass?) + +// At one point, zero-sized fields such as those in this file were causing +// incorrect output from `-Z print-type-sizes`. + +#![feature(start)] + +struct S1 { + x: u32, + y: u32, + tag: (), +} + +struct Void(); +struct Empty {} + +struct S5 { + tagw: TagW, + w: u32, + unit: (), + x: u32, + void: Void, + y: u32, + empty: Empty, + z: u32, + tagz: TagZ, +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + let _s1: S1 = S1 { x: 0, y: 0, tag: () }; + + let _s5: S5<(), Empty> = S5 { + tagw: (), + w: 1, + unit: (), + x: 2, + void: Void(), + y: 3, + empty: Empty {}, + z: 4, + tagz: Empty {}, + }; + 0 +} diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.stdout b/src/test/ui/print_type_sizes/zero-sized-fields.stdout new file mode 100644 index 0000000000000..72f59c4bb57bf --- /dev/null +++ b/src/test/ui/print_type_sizes/zero-sized-fields.stdout @@ -0,0 +1,16 @@ +print-type-size type: `S5<(), Empty>`: 16 bytes, alignment: 4 bytes +print-type-size field `.tagw`: 0 bytes +print-type-size field `.unit`: 0 bytes +print-type-size field `.void`: 0 bytes +print-type-size field `.empty`: 0 bytes +print-type-size field `.tagz`: 0 bytes +print-type-size field `.w`: 4 bytes +print-type-size field `.x`: 4 bytes +print-type-size field `.y`: 4 bytes +print-type-size field `.z`: 4 bytes +print-type-size type: `S1`: 8 bytes, alignment: 4 bytes +print-type-size field `.tag`: 0 bytes +print-type-size field `.x`: 4 bytes +print-type-size field `.y`: 4 bytes +print-type-size type: `Empty`: 0 bytes, alignment: 1 bytes +print-type-size type: `Void`: 0 bytes, alignment: 1 bytes From 8219c6fccf726da48471c27ea851f40602916553 Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Tue, 10 Dec 2019 22:18:17 -0800 Subject: [PATCH 32/47] Fix description based on review --- src/liballoc/boxed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 0c336b0495393..103525eeceec5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -63,7 +63,7 @@ //! //! So long as `T: Sized`, a `Box` is guaranteed to be represented as a //! single pointer and is also ABI-compatible with C pointers (i.e. the C type -//! `T*`). This means that you have Rust code which passes ownership of a +//! `T*`). This means that you can have Rust code which passes ownership of a //! `Box` to C code by using `Box` as the type on the Rust side, and //! `T*` as the corresponding type on the C side. As an example, consider this //! C header which declares functions that create and destroy some kind of From 147c7cd57e2ce2c8d065eae8daf1da15abaf9f24 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Wed, 11 Dec 2019 10:10:41 +0100 Subject: [PATCH 33/47] Apply review suggestions --- src/librustc_lint/unused.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ee644acd09974..e6f39cca6dc3a 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -17,7 +17,7 @@ use syntax::print::pprust; use syntax::symbol::{kw, sym}; use syntax::symbol::Symbol; use syntax::util::parser; -use syntax_pos::{MultiSpan, Span, BytePos}; +use syntax_pos::{Span, BytePos}; use log::debug; @@ -356,8 +356,7 @@ impl UnusedParens { ast::ExprKind::Paren(ref inner) => { if !Self::is_expr_parens_necessary(inner, followed_by_block) && value.attrs.is_empty() && - !MultiSpan::from(value.span).primary_span() - .map_or(false, |span| span.from_expansion()) + !value.span.from_expansion() { let expr_text = if let Ok(snippet) = cx.sess().source_map() .span_to_snippet(value.span) { From b10ffdb7282fcda6b0214c944ccf15336d72fd61 Mon Sep 17 00:00:00 2001 From: PirateDragon Date: Wed, 11 Dec 2019 14:29:47 +0800 Subject: [PATCH 34/47] Improve Style Used Self for uniform style --- src/libcore/task/wake.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 0759ff93ea85f..277df332b4ad5 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -39,8 +39,8 @@ impl RawWaker { /// function in the `vtable` of the underlying `RawWaker` will be called. #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] - pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { - RawWaker { data, vtable } + pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self { + Self { data, vtable } } } @@ -180,7 +180,7 @@ impl<'a> Context<'a> { #[stable(feature = "futures_api", since = "1.36.0")] #[inline] pub fn from_waker(waker: &'a Waker) -> Self { - Context { waker, _marker: PhantomData } + Self { waker, _marker: PhantomData } } /// Returns a reference to the `Waker` for the current task. @@ -277,8 +277,8 @@ impl Waker { /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] - pub unsafe fn from_raw(waker: RawWaker) -> Waker { - Waker { waker } + pub unsafe fn from_raw(waker: RawWaker) -> Self { + Self { waker } } } @@ -286,7 +286,7 @@ impl Waker { impl Clone for Waker { #[inline] fn clone(&self) -> Self { - Waker { + Self { // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `clone` and `data` requiring the user to acknowledge // that the contract of [`RawWaker`] is upheld. From f48f74202547952ac8e370ba816530a45644cfff Mon Sep 17 00:00:00 2001 From: Nicholas Matsakis Date: Wed, 11 Dec 2019 10:32:11 -0500 Subject: [PATCH 35/47] clarify that `Box` should only be used when defined *in Rust* --- src/liballoc/boxed.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 103525eeceec5..1c39a3721f465 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -61,13 +61,14 @@ //! T` obtained from [`Box::::into_raw`] may be deallocated using the //! [`Global`] allocator with [`Layout::for_value(&*value)`]. //! -//! So long as `T: Sized`, a `Box` is guaranteed to be represented as a -//! single pointer and is also ABI-compatible with C pointers (i.e. the C type -//! `T*`). This means that you can have Rust code which passes ownership of a -//! `Box` to C code by using `Box` as the type on the Rust side, and -//! `T*` as the corresponding type on the C side. As an example, consider this -//! C header which declares functions that create and destroy some kind of -//! `Foo` value: +//! So long as `T: Sized`, a `Box` is guaranteed to be represented +//! as a single pointer and is also ABI-compatible with C pointers +//! (i.e. the C type `T*`). This means that if you have extern "C" +//! Rust functions that will be called from C, you can define those +//! Rust functions using `Box` types, and use `T*` as corresponding +//! type on the C side. As an example, consider this C header which +//! declares functions that create and destroy some kind of `Foo` +//! value: //! //! ```c //! /* C header */ @@ -106,6 +107,14 @@ //! is to only use `Box` for pointers that originated from the global //! allocator. //! +//! **Important.** At least at present, you should avoid using +//! `Box` types for functions that are defined in C but invoked +//! from Rust. In those cases, you should directly mirror the C types +//! as closely as possible. Using types like `Box` where the C +//! definition is just using `T*` can lead to undefined behavior, as +//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198]. +//! +//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html //! [`Box`]: struct.Box.html From cb8871d8debcdb8551309d3c84ad60872be9e9a1 Mon Sep 17 00:00:00 2001 From: chansuke Date: Thu, 12 Dec 2019 01:00:37 +0900 Subject: [PATCH 36/47] Remove irelevant comment on `register_dtor` --- src/libstd/sys/unix/fast_thread_local.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index dfb9307daea9f..0861432f8a923 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -8,8 +8,6 @@ // Note, however, that we run on lots older linuxes, as well as cross // compiling from a newer linux to an older linux, so we also have a // fallback implementation to use as well. -// -// Due to rust-lang/rust#18804, make sure this is not generic! #[cfg(any( target_os = "linux", target_os = "fuchsia", From 8db343f57fbd15a06bc37de5e95db0c3f8f60b79 Mon Sep 17 00:00:00 2001 From: Nicholas Matsakis Date: Wed, 11 Dec 2019 13:23:07 -0500 Subject: [PATCH 37/47] erase regions instead of using `builtin_deref` The reason we were invoking `builtin_deref` was to enable comparisons when the type was `&T`. For the reasons outlined in the comment, those comparisons failed because the regions disagreed. --- src/librustc/traits/error_reporting.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 84ffb74045eff..6a111895b5637 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2260,15 +2260,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Look for a type inside the generator interior that matches the target type to get // a span. + let target_ty_erased = self.tcx.erase_regions(&target_ty); let target_span = tables.generator_interior_types.iter() .find(|ty::GeneratorInteriorTypeCause { ty, .. }| { - let ty = ty.builtin_deref(false).map(|ty_and_mut| ty_and_mut.ty).unwrap_or(ty); - let target_ty = target_ty.builtin_deref(false) - .map(|ty_and_mut| ty_and_mut.ty) - .unwrap_or(target_ty); - let eq = ty::TyS::same_type(ty, target_ty); - debug!("maybe_note_obligation_cause_for_async_await: ty={:?} \ - target_ty={:?} eq={:?}", ty, target_ty, eq); + // Careful: the regions for types that appear in the + // generator interior are not generally known, so we + // want to erase them when comparing (and anyway, + // `Send` and other bounds are generally unaffected by + // the choice of region). When erasing regions, we + // also have to erase late-bound regions. This is + // because the types that appear in the generator + // interior generally contain "bound regions" to + // represent regions that are part of the suspended + // generator frame. Bound regions are preserved by + // `erase_regions` and so we must also call + // `erase_late_bound_regions`. + let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty)); + let ty_erased = self.tcx.erase_regions(&ty_erased); + let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + debug!("maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ + target_ty_erased={:?} eq={:?}", ty_erased, target_ty_erased, eq); eq }) .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| From e86f974e5c696798f1af6b0e06447815aceb772e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 11 Dec 2019 21:58:00 +0300 Subject: [PATCH 38/47] resolve: Always resolve visibilities on impl items --- src/librustc_resolve/build_reduced_graph.rs | 24 +++++++++--------- .../ui/resolve/impl-items-vis-unresolved.rs | 25 +++++++++++++++++++ .../resolve/impl-items-vis-unresolved.stderr | 9 +++++++ 3 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/resolve/impl-items-vis-unresolved.rs create mode 100644 src/test/ui/resolve/impl-items-vis-unresolved.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 566ba12907437..e2578d67e730c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -647,8 +647,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.define(parent, ident, TypeNS, imported_binding); } - ItemKind::GlobalAsm(..) => {} - ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root ItemKind::Mod(..) => { @@ -667,9 +665,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.parent_scope.module = module; } - // Handled in `rustc_metadata::{native_libs,link_args}` - ItemKind::ForeignMod(..) => {} - // These items live in the value namespace. ItemKind::Static(..) => { let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)); @@ -765,12 +760,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.insert_field_names_local(def_id, vdata); } - ItemKind::Impl(.., ref impl_items) => { - for impl_item in impl_items { - self.resolve_visibility(&impl_item.vis); - } - } - ItemKind::Trait(..) => { let def_id = self.r.definitions.local_def_id(item.id); @@ -785,6 +774,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.parent_scope.module = module; } + // These items do not add names to modules. + ItemKind::Impl(..) | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} + ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } @@ -1118,7 +1110,6 @@ macro_rules! method { } impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { - method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); @@ -1202,6 +1193,15 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { visit::walk_trait_item(self, item); } + fn visit_impl_item(&mut self, item: &'b ast::ImplItem) { + if let ast::ImplItemKind::Macro(..) = item.kind { + self.visit_invoc(item.id); + } else { + self.resolve_visibility(&item.vis); + visit::walk_impl_item(self, item); + } + } + fn visit_token(&mut self, t: Token) { if let token::Interpolated(nt) = t.kind { if let token::NtExpr(ref expr) = *nt { diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.rs b/src/test/ui/resolve/impl-items-vis-unresolved.rs new file mode 100644 index 0000000000000..9b4fe498239b6 --- /dev/null +++ b/src/test/ui/resolve/impl-items-vis-unresolved.rs @@ -0,0 +1,25 @@ +// Visibilities on impl items expanded from macros are resolved (issue #64705). + +macro_rules! perftools_inline { + ($($item:tt)*) => ( + $($item)* + ); +} + +mod state { + pub struct RawFloatState; + impl RawFloatState { + perftools_inline! { + pub(super) fn new() {} // OK + } + } +} + +pub struct RawFloatState; +impl RawFloatState { + perftools_inline! { + pub(super) fn new() {} //~ ERROR failed to resolve: there are too many initial `super`s + } +} + +fn main() {} diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.stderr b/src/test/ui/resolve/impl-items-vis-unresolved.stderr new file mode 100644 index 0000000000000..8e285e5312400 --- /dev/null +++ b/src/test/ui/resolve/impl-items-vis-unresolved.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: there are too many initial `super`s. + --> $DIR/impl-items-vis-unresolved.rs:21:13 + | +LL | pub(super) fn new() {} + | ^^^^^ there are too many initial `super`s. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. From 42cc1d7548c33bd858cde0ab60a41f7ac8c29260 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 11 Dec 2019 20:49:46 +0100 Subject: [PATCH 39/47] Some small readability improvements --- src/libcore/char/methods.rs | 15 +++++---------- src/libcore/str/pattern.rs | 7 +------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 1ec614edbe2eb..5c63eebf595f9 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -553,8 +553,7 @@ impl char { pub fn is_alphabetic(self) -> bool { match self { 'a'..='z' | 'A'..='Z' => true, - c if c > '\x7f' => derived_property::Alphabetic(c), - _ => false, + c => c > '\x7f' && derived_property::Alphabetic(c), } } @@ -585,8 +584,7 @@ impl char { pub fn is_lowercase(self) -> bool { match self { 'a'..='z' => true, - c if c > '\x7f' => derived_property::Lowercase(c), - _ => false, + c => c > '\x7f' && derived_property::Lowercase(c), } } @@ -617,8 +615,7 @@ impl char { pub fn is_uppercase(self) -> bool { match self { 'A'..='Z' => true, - c if c > '\x7f' => derived_property::Uppercase(c), - _ => false, + c => c > '\x7f' && derived_property::Uppercase(c), } } @@ -646,8 +643,7 @@ impl char { pub fn is_whitespace(self) -> bool { match self { ' ' | '\x09'..='\x0d' => true, - c if c > '\x7f' => property::White_Space(c), - _ => false, + c => c > '\x7f' && property::White_Space(c), } } @@ -744,8 +740,7 @@ impl char { pub fn is_numeric(self) -> bool { match self { '0'..='9' => true, - c if c > '\x7f' => general_category::N(c), - _ => false, + c => c > '\x7f' && general_category::N(c), } } diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index a494274118a74..1037da14b5f62 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -296,12 +296,7 @@ unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { fn next_match(&mut self) -> Option<(usize, usize)> { loop { // get the haystack after the last character found - let bytes = if let Some(slice) = self.haystack.as_bytes() - .get(self.finger..self.finger_back) { - slice - } else { - return None; - }; + let bytes = self.haystack.as_bytes().get(self.finger..self.finger_back)?; // the last byte of the utf8 encoded needle let last_byte = unsafe { *self.utf8_encoded.get_unchecked(self.utf8_size - 1) }; if let Some(index) = memchr::memchr(last_byte, bytes) { From 6c5047dd0075a95972715afb3bebe99e4e31055e Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 11 Dec 2019 21:01:33 +0100 Subject: [PATCH 40/47] Small Cow improvements --- src/liballoc/borrow.rs | 18 +++++------------- src/liballoc/tests/cow_str.rs | 3 +++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index d2bdda83fa998..fc96045196846 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -195,14 +195,10 @@ impl Clone for Cow<'_, B> { } fn clone_from(&mut self, source: &Self) { - if let Owned(ref mut dest) = *self { - if let Owned(ref o) = *source { - o.borrow().clone_into(dest); - return; - } + match (self, source) { + (&mut Owned(ref mut dest), &Owned(ref o)) => o.borrow().clone_into(dest), + (t, s) => *t = s.clone(), } - - *self = source.clone(); } } @@ -449,9 +445,7 @@ impl<'a> AddAssign<&'a str> for Cow<'a, str> { fn add_assign(&mut self, rhs: &'a str) { if self.is_empty() { *self = Cow::Borrowed(rhs) - } else if rhs.is_empty() { - return; - } else { + } else if !rhs.is_empty() { if let Cow::Borrowed(lhs) = *self { let mut s = String::with_capacity(lhs.len() + rhs.len()); s.push_str(lhs); @@ -467,9 +461,7 @@ impl<'a> AddAssign> for Cow<'a, str> { fn add_assign(&mut self, rhs: Cow<'a, str>) { if self.is_empty() { *self = rhs - } else if rhs.is_empty() { - return; - } else { + } else if !rhs.is_empty() { if let Cow::Borrowed(lhs) = *self { let mut s = String::with_capacity(lhs.len() + rhs.len()); s.push_str(lhs); diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index 6f357eda9b83b..62a5c245a5429 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -138,4 +138,7 @@ fn check_cow_clone_from() { let c2: Cow<'_, str> = Cow::Owned(s); c1.clone_from(&c2); assert!(c1.into_owned().capacity() >= 25); + let mut c3: Cow<'_, str> = Cow::Borrowed("bye"); + c3.clone_from(&c2); + assert_eq!(c2, c3); } From 7bb1606c8772898b8554d5de0f1cdc7ff014fb43 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 11 Dec 2019 21:05:28 +0100 Subject: [PATCH 41/47] Make TinyList::remove iterate instead of recurse --- src/librustc_data_structures/tiny_list.rs | 40 +++++++++-------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 371f0f6fa0b44..78cbc1240b182 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -16,41 +16,29 @@ mod tests; #[derive(Clone)] pub struct TinyList { - head: Option> + head: Option>, } impl TinyList { #[inline] pub fn new() -> TinyList { - TinyList { - head: None - } + TinyList { head: None } } #[inline] pub fn new_single(data: T) -> TinyList { - TinyList { - head: Some(Element { - data, - next: None, - }) - } + TinyList { head: Some(Element { data, next: None }) } } #[inline] pub fn insert(&mut self, data: T) { - self.head = Some(Element { - data, - next: self.head.take().map(Box::new) - }); + self.head = Some(Element { data, next: self.head.take().map(Box::new) }); } #[inline] pub fn remove(&mut self, data: &T) -> bool { self.head = match self.head { - Some(ref mut head) if head.data == *data => { - head.next.take().map(|x| *x) - } + Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x), Some(ref mut head) => return head.remove_next(data), None => return false, }; @@ -88,12 +76,16 @@ struct Element { impl Element { fn remove_next(&mut self, data: &T) -> bool { - let new_next = match self.next { - Some(ref mut next) if next.data == *data => next.next.take(), - Some(ref mut next) => return next.remove_next(data), - None => return false, - }; - self.next = new_next; - true + let mut n = self; + loop { + match n.next { + Some(ref mut next) if next.data == *data => { + n.next = next.next.take(); + return true; + } + Some(ref mut next) => n = next, + None => return false, + } + } } } From 93adec3389b4c909ff14b25651166714c068b414 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 29 Nov 2019 19:05:44 -0600 Subject: [PATCH 42/47] get rid of nll submod --- src/librustc_mir/borrow_check/{nll => }/constraint_generation.rs | 0 src/librustc_mir/borrow_check/{nll => }/constraints/graph.rs | 0 src/librustc_mir/borrow_check/{nll => }/constraints/mod.rs | 0 src/librustc_mir/borrow_check/{nll => }/facts.rs | 0 src/librustc_mir/borrow_check/{nll => }/invalidation.rs | 0 src/librustc_mir/borrow_check/{nll => }/member_constraints.rs | 0 src/librustc_mir/borrow_check/{nll/mod.rs => nll.rs} | 0 src/librustc_mir/borrow_check/{nll => }/region_infer/dump_mir.rs | 0 src/librustc_mir/borrow_check/{nll => }/region_infer/graphviz.rs | 0 src/librustc_mir/borrow_check/{nll => }/region_infer/mod.rs | 0 src/librustc_mir/borrow_check/{nll => }/region_infer/values.rs | 0 src/librustc_mir/borrow_check/{nll => }/renumber.rs | 0 .../borrow_check/{nll => }/type_check/constraint_conversion.rs | 0 .../borrow_check/{nll => }/type_check/free_region_relations.rs | 0 .../borrow_check/{nll => }/type_check/input_output.rs | 0 .../borrow_check/{nll => }/type_check/liveness/local_use_map.rs | 0 .../borrow_check/{nll => }/type_check/liveness/mod.rs | 0 .../borrow_check/{nll => }/type_check/liveness/polonius.rs | 0 .../borrow_check/{nll => }/type_check/liveness/trace.rs | 0 src/librustc_mir/borrow_check/{nll => }/type_check/mod.rs | 0 src/librustc_mir/borrow_check/{nll => }/type_check/relate_tys.rs | 0 src/librustc_mir/borrow_check/{nll => }/universal_regions.rs | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename src/librustc_mir/borrow_check/{nll => }/constraint_generation.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/constraints/graph.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/constraints/mod.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/facts.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/invalidation.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/member_constraints.rs (100%) rename src/librustc_mir/borrow_check/{nll/mod.rs => nll.rs} (100%) rename src/librustc_mir/borrow_check/{nll => }/region_infer/dump_mir.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/region_infer/graphviz.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/region_infer/mod.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/region_infer/values.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/renumber.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/constraint_conversion.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/free_region_relations.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/input_output.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/liveness/local_use_map.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/liveness/mod.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/liveness/polonius.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/liveness/trace.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/mod.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/type_check/relate_tys.rs (100%) rename src/librustc_mir/borrow_check/{nll => }/universal_regions.rs (100%) diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/constraint_generation.rs rename to src/librustc_mir/borrow_check/constraint_generation.rs diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/constraints/graph.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/constraints/graph.rs rename to src/librustc_mir/borrow_check/constraints/graph.rs diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/constraints/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/constraints/mod.rs rename to src/librustc_mir/borrow_check/constraints/mod.rs diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/facts.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/facts.rs rename to src/librustc_mir/borrow_check/facts.rs diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/invalidation.rs rename to src/librustc_mir/borrow_check/invalidation.rs diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/member_constraints.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/member_constraints.rs rename to src/librustc_mir/borrow_check/member_constraints.rs diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/mod.rs rename to src/librustc_mir/borrow_check/nll.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs rename to src/librustc_mir/borrow_check/region_infer/dump_mir.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs rename to src/librustc_mir/borrow_check/region_infer/graphviz.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/region_infer/mod.rs rename to src/librustc_mir/borrow_check/region_infer/mod.rs diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/region_infer/values.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/region_infer/values.rs rename to src/librustc_mir/borrow_check/region_infer/values.rs diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/renumber.rs rename to src/librustc_mir/borrow_check/renumber.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs rename to src/librustc_mir/borrow_check/type_check/constraint_conversion.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs rename to src/librustc_mir/borrow_check/type_check/free_region_relations.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/input_output.rs rename to src/librustc_mir/borrow_check/type_check/input_output.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs rename to src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs rename to src/librustc_mir/borrow_check/type_check/liveness/mod.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs rename to src/librustc_mir/borrow_check/type_check/liveness/polonius.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs rename to src/librustc_mir/borrow_check/type_check/liveness/trace.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/mod.rs rename to src/librustc_mir/borrow_check/type_check/mod.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs rename to src/librustc_mir/borrow_check/type_check/relate_tys.rs diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll/universal_regions.rs rename to src/librustc_mir/borrow_check/universal_regions.rs From 7e530dff81b7c42373cac3c0cfc2f2f2bf42980b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 29 Nov 2019 19:48:29 -0600 Subject: [PATCH 43/47] fix imports --- .../borrow_check/constraint_generation.rs | 15 ++++--- .../borrow_check/constraints/graph.rs | 9 ++-- .../borrow_check/constraints/mod.rs | 3 +- .../diagnostics/explain_borrow.rs | 13 ++++-- .../borrow_check/diagnostics/find_use.rs | 3 +- .../diagnostics/outlives_suggestion.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 20 +++++---- .../borrow_check/diagnostics/region_name.rs | 7 ++-- .../borrow_check/diagnostics/var_name.rs | 3 +- src/librustc_mir/borrow_check/invalidation.rs | 22 +++++----- src/librustc_mir/borrow_check/mod.rs | 21 +++++++--- src/librustc_mir/borrow_check/nll.rs | 42 ++++++++----------- .../borrow_check/region_infer/graphviz.rs | 5 ++- .../borrow_check/region_infer/mod.rs | 29 ++++++------- .../type_check/constraint_conversion.rs | 13 +++--- .../type_check/free_region_relations.rs | 12 ++++-- .../borrow_check/type_check/input_output.rs | 3 +- .../type_check/liveness/local_use_map.rs | 6 ++- .../borrow_check/type_check/liveness/mod.rs | 22 ++++++---- .../borrow_check/type_check/liveness/trace.rs | 20 +++++---- .../borrow_check/type_check/mod.rs | 25 ++++++++++- .../borrow_check/type_check/relate_tys.rs | 5 ++- .../borrow_check/universal_regions.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 14 ++++--- 24 files changed, 187 insertions(+), 129 deletions(-) diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs index dbeccab966bbb..28a631a711a87 100644 --- a/src/librustc_mir/borrow_check/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/constraint_generation.rs @@ -1,9 +1,3 @@ -use crate::borrow_check::borrow_set::BorrowSet; -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::ToRegionVid; -use crate::borrow_check::nll::facts::AllFacts; -use crate::borrow_check::nll::region_infer::values::LivenessValues; -use crate::borrow_check::places_conflict; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; @@ -15,6 +9,15 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, RegionVid, Ty}; use rustc::ty::subst::SubstsRef; +use crate::borrow_check::{ + borrow_set::BorrowSet, + location::LocationTable, + nll::ToRegionVid, + facts::AllFacts, + region_infer::values::LivenessValues, + places_conflict, +}; + pub(super) fn generate_constraints<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc_mir/borrow_check/constraints/graph.rs b/src/librustc_mir/borrow_check/constraints/graph.rs index b6a9a7ee6578f..3e7aa67ef6c7d 100644 --- a/src/librustc_mir/borrow_check/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/constraints/graph.rs @@ -1,12 +1,15 @@ -use crate::borrow_check::nll::type_check::Locations; -use crate::borrow_check::nll::constraints::OutlivesConstraintIndex; -use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint}; use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph; use rustc_index::vec::IndexVec; use syntax_pos::DUMMY_SP; +use crate::borrow_check::{ + type_check::Locations, + constraints::OutlivesConstraintIndex, + constraints::{OutlivesConstraintSet, OutlivesConstraint}, +}; + /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 /// -> R2` or `R2 -> R1` depending on the direction type `D`. diff --git a/src/librustc_mir/borrow_check/constraints/mod.rs b/src/librustc_mir/borrow_check/constraints/mod.rs index 8a242b7ee25ba..96982b604c0be 100644 --- a/src/librustc_mir/borrow_check/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/constraints/mod.rs @@ -1,4 +1,3 @@ -use crate::borrow_check::nll::type_check::Locations; use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph::scc::Sccs; @@ -6,6 +5,8 @@ use rustc_index::vec::{Idx, IndexVec}; use std::fmt; use std::ops::Index; +use crate::borrow_check::type_check::Locations; + crate mod graph; /// A set of NLL region constraints. These include "outlives" diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 67c3c36e73ec7..a463d2cb2990b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -1,9 +1,7 @@ +//! Print diagnostics to explain why values are borrowed. + use std::collections::VecDeque; -use crate::borrow_check::borrow_set::BorrowData; -use crate::borrow_check::nll::region_infer::Cause; -use crate::borrow_check::nll::ConstraintDescription; -use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, @@ -16,6 +14,13 @@ use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; use syntax_pos::symbol::Symbol; +use crate::borrow_check::{ + borrow_set::BorrowData, + region_infer::Cause, + nll::ConstraintDescription, + MirBorrowckCtxt, WriteKind, +}; + use super::{UseSpans, find_use, RegionName}; #[derive(Debug)] diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs index 7ab069260f940..c557e528768c5 100644 --- a/src/librustc_mir/borrow_check/diagnostics/find_use.rs +++ b/src/librustc_mir/borrow_check/diagnostics/find_use.rs @@ -1,8 +1,7 @@ use std::collections::VecDeque; use std::rc::Rc; -use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext}; -use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::{nll::ToRegionVid, region_infer::{Cause, RegionInferenceContext}}; use crate::util::liveness::{self, DefUse}; use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor}; use rustc::mir::{Local, Location, Body}; diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs index 7aecadae98b55..b61c37b061396 100644 --- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs +++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs @@ -13,7 +13,7 @@ use syntax_pos::symbol::Symbol; use smallvec::SmallVec; -use crate::borrow_check::nll::region_infer::RegionInferenceContext; +use crate::borrow_check::region_infer::RegionInferenceContext; use super::{ RegionName, RegionNameSource, ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx, diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 66f0330fe9b6c..8a37e2d02ec71 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -1,10 +1,5 @@ -use crate::borrow_check::nll::constraints::OutlivesConstraint; -use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use crate::borrow_check::nll::type_check::Locations; -use crate::borrow_check::nll::universal_regions::DefiningTy; -use crate::borrow_check::nll::ConstraintDescription; -use crate::borrow_check::Upvar; -use crate::util::borrowck_errors; +//! Error reporting machinery for lifetime errors. + use rustc::hir::def_id::DefId; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::InferCtxt; @@ -19,6 +14,17 @@ use syntax::symbol::kw; use syntax_pos::Span; use syntax_pos::symbol::Symbol; +use crate::util::borrowck_errors; + +use crate::borrow_check::{ + constraints::OutlivesConstraint, + region_infer::RegionInferenceContext, + type_check::Locations, + universal_regions::DefiningTy, + nll::ConstraintDescription, + Upvar, +}; + use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource, RegionErrorNamingCtx}; impl ConstraintDescription for ConstraintCategory { diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index e2e75962aecef..720c77beaf8b5 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -15,14 +15,13 @@ use rustc_data_structures::fx::FxHashMap; use syntax_pos::{Span, symbol::Symbol, DUMMY_SP}; use crate::borrow_check::{ - nll::region_infer::RegionInferenceContext, - nll::universal_regions::DefiningTy, + diagnostics::region_errors::ErrorReportingCtx, + region_infer::RegionInferenceContext, + universal_regions::DefiningTy, nll::ToRegionVid, Upvar, }; -use super::region_errors::ErrorReportingCtx; - /// A name for a particular region used in emitting diagnostics. This name could be a generated /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. #[derive(Debug, Clone)] diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/src/librustc_mir/borrow_check/diagnostics/var_name.rs index 1ac44c4fdb101..839e09be7af82 100644 --- a/src/librustc_mir/borrow_check/diagnostics/var_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/var_name.rs @@ -1,5 +1,4 @@ -use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::{nll::ToRegionVid, region_infer::RegionInferenceContext}; use crate::borrow_check::Upvar; use rustc::mir::{Local, Body}; use rustc::ty::{RegionVid, TyCtxt}; diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index e442f9c9e322f..58fac5512d9b6 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -1,14 +1,3 @@ -use crate::borrow_check::borrow_set::BorrowSet; -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::{JustWrite, WriteAndRead}; -use crate::borrow_check::{AccessDepth, Deep, Shallow}; -use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write}; -use crate::borrow_check::{LocalMutationIsAllowed, MutateMode}; -use crate::borrow_check::ArtificialField; -use crate::borrow_check::{ReadKind, WriteKind}; -use crate::borrow_check::nll::facts::AllFacts; -use crate::borrow_check::path_utils::*; -use crate::dataflow::indexes::BorrowIndex; use rustc::ty::{self, TyCtxt}; use rustc::mir::visit::Visitor; use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue}; @@ -17,6 +6,17 @@ use rustc::mir::TerminatorKind; use rustc::mir::{Operand, BorrowKind}; use rustc_data_structures::graph::dominators::Dominators; +use crate::dataflow::indexes::BorrowIndex; + +use crate::borrow_check::{ + borrow_set::BorrowSet, + location::LocationTable, + facts::AllFacts, + path_utils::*, + JustWrite, WriteAndRead, AccessDepth, Deep, Shallow, ReadOrWrite, Activation, Read, + Reservation, Write, LocalMutationIsAllowed, MutateMode, ArtificialField, ReadKind, WriteKind, +}; + pub(super) fn generate_invalidates<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index b4f2e2377ac7d..fb26effc0bc96 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1,6 +1,5 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. -use crate::borrow_check::nll::region_infer::RegionInferenceContext; use rustc::hir::{self, HirId}; use rustc::hir::Node; use rustc::hir::def_id::DefId; @@ -47,20 +46,30 @@ use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; use self::diagnostics::AccessKind; +use self::region_infer::RegionInferenceContext; use self::path_utils::*; -crate mod borrow_set; mod diagnostics; mod flows; mod location; mod path_utils; -crate mod place_ext; -crate mod places_conflict; mod prefixes; mod used_muts; - -pub(crate) mod nll; +mod constraint_generation; +mod facts; +mod invalidation; +mod renumber; +mod member_constraints; + +crate mod constraints; +crate mod universal_regions; +crate mod type_check; +crate mod region_infer; +crate mod borrow_set; +crate mod place_ext; +crate mod places_conflict; +crate mod nll; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 9ea3bd8899b9d..61e6b4c863180 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -1,13 +1,5 @@ -use crate::borrow_check::borrow_set::BorrowSet; -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::facts::AllFactsExt; -use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints}; -use crate::borrow_check::nll::region_infer::values::RegionValueElements; -use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind}; -use crate::dataflow::FlowAtLocation; -use crate::dataflow::MaybeInitializedPlaces; -use crate::transform::MirSource; -use crate::borrow_check::Upvar; +//! The entry point of the NLL borrow checker. + use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, @@ -27,24 +19,24 @@ use syntax::symbol::sym; use self::mir_util::PassWhere; use polonius_engine::{Algorithm, Output}; + use crate::util as mir_util; use crate::util::pretty; +use crate::dataflow::indexes::BorrowIndex; +use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind}; +use crate::dataflow::FlowAtLocation; +use crate::dataflow::MaybeInitializedPlaces; +use crate::transform::MirSource; -mod constraint_generation; -mod facts; -mod invalidation; -mod renumber; - -mod member_constraints; - -crate mod constraints; -crate mod universal_regions; -crate mod type_check; -crate mod region_infer; - -use self::facts::{AllFacts, RustcFacts}; -use self::region_infer::RegionInferenceContext; -use self::universal_regions::UniversalRegions; +use crate::borrow_check::{ + borrow_set::BorrowSet, + location::{LocationIndex, LocationTable}, + facts::{AllFacts, AllFactsExt, RustcFacts}, + region_infer::{RegionInferenceContext, values::RegionValueElements}, + universal_regions::UniversalRegions, + type_check::{self, MirTypeckResults, MirTypeckRegionConstraints}, + Upvar, renumber, constraint_generation, invalidation, +}; crate type PoloniusOutput = Output; diff --git a/src/librustc_mir/borrow_check/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs index fdf2af9f44ebc..29c6f32526390 100644 --- a/src/librustc_mir/borrow_check/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/region_infer/graphviz.rs @@ -2,11 +2,12 @@ //! libgraphviz traits, specialized to attaching borrowck analysis //! data to rendered labels. -use super::*; -use crate::borrow_check::nll::constraints::OutlivesConstraint; use std::borrow::Cow; use std::io::{self, Write}; +use super::*; +use crate::borrow_check::constraints::OutlivesConstraint; + impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index d62537b1ad465..b6946e2f73fc6 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -23,29 +23,26 @@ use syntax_pos::Span; use syntax_pos::symbol::Symbol; use crate::borrow_check::{ - nll::{ - constraints::{ - graph::NormalConstraintGraph, - ConstraintSccIndex, - OutlivesConstraint, - OutlivesConstraintSet, - }, - member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, - region_infer::values::{ - PlaceholderIndices, RegionElement, ToElementIndex - }, - type_check::{free_region_relations::UniversalRegionRelations, Locations}, + constraints::{ + graph::NormalConstraintGraph, + ConstraintSccIndex, + OutlivesConstraint, + OutlivesConstraintSet, }, + member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, + region_infer::values::{ + PlaceholderIndices, RegionElement, ToElementIndex, LivenessValues, RegionValueElements, + RegionValues, + }, + type_check::{free_region_relations::UniversalRegionRelations, Locations}, diagnostics::{ OutlivesSuggestionBuilder, RegionErrorNamingCtx, }, + nll::{ToRegionVid, PoloniusOutput}, + universal_regions::UniversalRegions, Upvar, }; -use self::values::{LivenessValues, RegionValueElements, RegionValues}; -use super::universal_regions::UniversalRegions; -use super::{PoloniusOutput, ToRegionVid}; - mod dump_mir; mod graphviz; diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs index 34ac96beb5ca3..334477dff2362 100644 --- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs @@ -1,8 +1,3 @@ -use crate::borrow_check::nll::constraints::OutlivesConstraint; -use crate::borrow_check::nll::region_infer::TypeTest; -use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; -use crate::borrow_check::nll::universal_regions::UniversalRegions; -use crate::borrow_check::nll::ToRegionVid; use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::canonical::QueryOutlivesConstraint; use rustc::infer::outlives::env::RegionBoundPairs; @@ -14,6 +9,14 @@ use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, TyCtxt}; use syntax_pos::DUMMY_SP; +use crate::borrow_check::{ + constraints::OutlivesConstraint, + region_infer::TypeTest, + type_check::{Locations, MirTypeckRegionConstraints}, + universal_regions::UniversalRegions, + nll::ToRegionVid, +}; + crate struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 8bb68383a49ba..8bbaeaace75b6 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,7 +1,4 @@ -use crate::borrow_check::nll::type_check::constraint_conversion; -use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; -use crate::borrow_check::nll::universal_regions::UniversalRegions; -use crate::borrow_check::nll::ToRegionVid; + use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; @@ -14,6 +11,13 @@ use rustc_data_structures::transitive_relation::TransitiveRelation; use std::rc::Rc; use syntax_pos::DUMMY_SP; +use crate::borrow_check::{ + type_check::constraint_conversion, + type_check::{Locations, MirTypeckRegionConstraints}, + universal_regions::UniversalRegions, + nll::ToRegionVid, +}; + #[derive(Debug)] crate struct UniversalRegionRelations<'tcx> { universal_regions: Rc>, diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs index 35fb677c053cb..3df04909d0d2f 100644 --- a/src/librustc_mir/borrow_check/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/type_check/input_output.rs @@ -7,7 +7,6 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use crate::borrow_check::nll::universal_regions::UniversalRegions; use rustc::infer::LateBoundRegionConversionTime; use rustc::mir::*; use rustc::ty::Ty; @@ -15,6 +14,8 @@ use rustc::ty::Ty; use rustc_index::vec::Idx; use syntax_pos::Span; +use crate::borrow_check::universal_regions::UniversalRegions; + use super::{Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { diff --git a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs index ab8c6f279733b..75e4f61245f5f 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs @@ -1,10 +1,12 @@ -use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements}; -use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::{Local, Location, ReadOnlyBodyAndCache}; use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; +use crate::util::liveness::{categorize, DefUse}; + +use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements}; + /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness /// computation. diff --git a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs index 8f8e9af797963..ee3d89e741a54 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs @@ -1,17 +1,21 @@ -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::constraints::OutlivesConstraintSet; -use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt}; -use crate::borrow_check::nll::region_infer::values::RegionValueElements; -use crate::borrow_check::nll::universal_regions::UniversalRegions; -use crate::borrow_check::nll::ToRegionVid; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::FlowAtLocation; -use crate::dataflow::MaybeInitializedPlaces; use rustc::mir::{Body, Local, ReadOnlyBodyAndCache}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::rc::Rc; +use crate::dataflow::move_paths::MoveData; +use crate::dataflow::FlowAtLocation; +use crate::dataflow::MaybeInitializedPlaces; + +use crate::borrow_check::{ + location::LocationTable, + constraints::OutlivesConstraintSet, + facts::{AllFacts, AllFactsExt}, + region_infer::values::RegionValueElements, + universal_regions::UniversalRegions, + nll::ToRegionVid, +}; + use super::TypeChecker; mod local_use_map; diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs index ba6fd75eea59c..9afd25a0f7f7e 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs @@ -1,11 +1,3 @@ -use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements}; -use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap; -use crate::borrow_check::nll::type_check::liveness::polonius; -use crate::borrow_check::nll::type_check::NormalizeLocation; -use crate::borrow_check::nll::type_check::TypeChecker; -use crate::dataflow::indexes::MovePathIndex; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces}; use rustc::infer::canonical::QueryRegionConstraints; use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache}; use rustc::traits::query::dropck_outlives::DropckOutlivesResult; @@ -16,6 +8,18 @@ use rustc_index::bit_set::HybridBitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::rc::Rc; +use crate::dataflow::indexes::MovePathIndex; +use crate::dataflow::move_paths::MoveData; +use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces}; + +use crate::borrow_check::{ + region_infer::values::{self, PointIndex, RegionValueElements}, + type_check::liveness::local_use_map::LocalUseMap, + type_check::liveness::polonius, + type_check::NormalizeLocation, + type_check::TypeChecker, +}; + /// This is the heart of the liveness computation. For each variable X /// that requires a liveness computation, it walks over all the uses /// of X and does a reverse depth-first search ("trace") through the diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 1e3723edc564f..5d801a77b25f3 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -55,9 +55,32 @@ use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::move_paths::MoveData; use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; +use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; +use crate::dataflow::move_paths::MoveData; +use crate::dataflow::FlowAtLocation; +use crate::dataflow::MaybeInitializedPlaces; + +use crate::borrow_check::{ + borrow_set::BorrowSet, + location::LocationTable, + constraints::{OutlivesConstraintSet, OutlivesConstraint}, + member_constraints::MemberConstraintSet, + facts::AllFacts, + region_infer::values::{ + LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, + }, + region_infer::{ClosureRegionRequirementsExt, TypeTest}, + type_check::free_region_relations::{ + CreateResult, UniversalRegionRelations, + }, + universal_regions::{DefiningTy, UniversalRegions}, + nll::ToRegionVid, + renumber, +}; + macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ - $crate::borrow_check::nll::type_check::mirbug( + $crate::borrow_check::type_check::mirbug( $context.tcx(), $context.last_span, &format!( diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index 80bf0478128c7..80da8a82c51ed 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -1,5 +1,3 @@ -use crate::borrow_check::nll::constraints::OutlivesConstraint; -use crate::borrow_check::nll::type_check::{BorrowCheckContext, Locations}; use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::ConstraintCategory; @@ -8,6 +6,9 @@ use rustc::traits::DomainGoal; use rustc::ty::relate::TypeRelation; use rustc::ty::{self, Ty}; +use crate::borrow_check::constraints::OutlivesConstraint; +use crate::borrow_check::type_check::{BorrowCheckContext, Locations}; + /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: /// /// - "Covariant" `a <: b` diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs index 9ad15fca0017d..c0353039b680c 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/src/librustc_mir/borrow_check/universal_regions.rs @@ -25,7 +25,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_errors::DiagnosticBuilder; use std::iter; -use super::ToRegionVid; +use crate::borrow_check::nll::ToRegionVid; #[derive(Debug)] pub struct UniversalRegions<'tcx> { diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 7e7652cdab5ce..d4f26c265e64c 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -1,6 +1,3 @@ -use crate::borrow_check::borrow_set::{BorrowSet, BorrowData}; -use crate::borrow_check::place_ext::PlaceExt; - use rustc::mir::{self, Location, Place, PlaceBase, Body}; use rustc::ty::{self, TyCtxt}; use rustc::ty::RegionVid; @@ -10,9 +7,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; -use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use crate::borrow_check::nll::ToRegionVid; -use crate::borrow_check::places_conflict; + +use crate::borrow_check::{ + borrow_set::{BorrowSet, BorrowData}, + place_ext::PlaceExt, + region_infer::RegionInferenceContext, + nll::ToRegionVid, + places_conflict, +}; use std::rc::Rc; From 4529d7811adf46481db43ca8a4265f14ec41d01e Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 29 Nov 2019 20:05:29 -0600 Subject: [PATCH 44/47] tidy --- .../borrow_check/type_check/free_region_relations.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 8bbaeaace75b6..03a7f97ac51f1 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,4 +1,3 @@ - use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; From fd07d5f756ee1fd784e827550b45d3d3751f35f2 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Thu, 5 Dec 2019 12:00:40 -0600 Subject: [PATCH 45/47] fix imports --- .../borrow_check/type_check/mod.rs | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 5d801a77b25f3..663536bc2b4b6 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -34,32 +34,11 @@ use rustc_error_codes::*; use rustc_index::vec::{Idx, IndexVec}; use syntax_pos::{DUMMY_SP, Span}; -use crate::borrow_check::borrow_set::BorrowSet; -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::constraints::{OutlivesConstraint, OutlivesConstraintSet}; -use crate::borrow_check::nll::facts::AllFacts; -use crate::borrow_check::nll::member_constraints::MemberConstraintSet; -use crate::borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; -use crate::borrow_check::nll::region_infer::values::LivenessValues; -use crate::borrow_check::nll::region_infer::values::PlaceholderIndex; -use crate::borrow_check::nll::region_infer::values::PlaceholderIndices; -use crate::borrow_check::nll::region_infer::values::RegionValueElements; -use crate::borrow_check::nll::renumber; -use crate::borrow_check::nll::ToRegionVid; -use crate::borrow_check::nll::type_check::free_region_relations::{ - CreateResult, UniversalRegionRelations, -}; -use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions}; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::move_paths::MoveData; use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; -use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::FlowAtLocation; -use crate::dataflow::MaybeInitializedPlaces; - use crate::borrow_check::{ borrow_set::BorrowSet, location::LocationTable, From 2e3072d48c2acfc3b82cda77faaebab66ac24e6a Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 6 Dec 2019 10:02:48 -0600 Subject: [PATCH 46/47] more private --- src/librustc_mir/borrow_check/mod.rs | 25 ++++++++++++---------- src/librustc_mir/dataflow/impls/borrows.rs | 12 ++++------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index fb26effc0bc96..11012ef2fc7ee 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -40,13 +40,11 @@ use crate::dataflow::{do_dataflow, DebugFormatted}; use crate::dataflow::EverInitializedPlaces; use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; -use self::borrow_set::{BorrowData, BorrowSet}; use self::flows::Flows; use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; use self::diagnostics::AccessKind; -use self::region_infer::RegionInferenceContext; use self::path_utils::*; @@ -61,15 +59,20 @@ mod facts; mod invalidation; mod renumber; mod member_constraints; - -crate mod constraints; -crate mod universal_regions; -crate mod type_check; -crate mod region_infer; -crate mod borrow_set; -crate mod place_ext; -crate mod places_conflict; -crate mod nll; +mod constraints; +mod universal_regions; +mod type_check; +mod region_infer; +mod borrow_set; +mod place_ext; +mod places_conflict; +mod nll; + +crate use region_infer::RegionInferenceContext; +crate use borrow_set::{BorrowSet, BorrowData}; +crate use places_conflict::{places_conflict, PlaceConflictBias}; +crate use place_ext::PlaceExt; +crate use nll::ToRegionVid; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index d4f26c265e64c..5433b7f5f74f7 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -6,15 +6,11 @@ use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; -use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; - use crate::borrow_check::{ - borrow_set::{BorrowSet, BorrowData}, - place_ext::PlaceExt, - region_infer::RegionInferenceContext, - nll::ToRegionVid, + ToRegionVid, BorrowSet, BorrowData, RegionInferenceContext, PlaceExt, PlaceConflictBias, places_conflict, }; +use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; use std::rc::Rc; @@ -223,13 +219,13 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // locations. let definitely_conflicting_borrows = other_borrows_of_local .filter(|&&i| { - places_conflict::places_conflict( + places_conflict( self.tcx, self.param_env, self.body, &self.borrow_set.borrows[i].borrowed_place, place, - places_conflict::PlaceConflictBias::NoOverlap) + PlaceConflictBias::NoOverlap) }); trans.kill_all(definitely_conflicting_borrows); From f1637a4a6ea04529fb9aebf10630d050827ab521 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 9 Dec 2019 12:24:47 -0600 Subject: [PATCH 47/47] fix imports after rebase --- src/librustc_mir/borrow_check/nll.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 61e6b4c863180..6d28a8caa92bd 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -22,15 +22,14 @@ use polonius_engine::{Algorithm, Output}; use crate::util as mir_util; use crate::util::pretty; -use crate::dataflow::indexes::BorrowIndex; -use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind}; +use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind}; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::transform::MirSource; use crate::borrow_check::{ borrow_set::BorrowSet, - location::{LocationIndex, LocationTable}, + location::LocationTable, facts::{AllFacts, AllFactsExt, RustcFacts}, region_infer::{RegionInferenceContext, values::RegionValueElements}, universal_regions::UniversalRegions,