From af424c1813eca41024da5290e064ead85f68dc0b Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Mon, 1 Feb 2021 10:31:05 +0100 Subject: [PATCH 01/19] Implement SourceIterator and InPlaceIterable for ResultShunt --- library/core/src/iter/adapters/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 41a7b13232adf..f72e642620090 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -191,3 +191,26 @@ where self.try_fold(init, ok(fold)).unwrap() } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for ResultShunt<'_, I, E> +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to +// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that +// at least one item will be moved out from the underlying source. +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for ResultShunt<'_, I, E> where + I: Iterator> + InPlaceIterable +{ +} From 524b0c9c614d4691b2e21ace47fce4df15900701 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Mon, 1 Feb 2021 10:31:34 +0100 Subject: [PATCH 02/19] Add test for inplace collection of Result,_> --- library/core/tests/iter/mod.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index 770b6f7601fa2..b88f2f2089d18 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -100,3 +100,29 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } + +#[test] +pub fn inplace_result_collect() { + let src = vec![0usize; 256]; + let srcptr = src.as_ptr(); + let sink = src.into_iter().map(|i| Ok(i)).collect::, ()>>().unwrap(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); + + let src: Vec = vec![0usize; 256]; + let srcptr = src.as_ptr(); + let iter = src + .into_iter() + .enumerate() + .map(|i| i.0 + i.1) + .zip(std::iter::repeat(1usize)) + .map(|(a, b)| a + b) + .map_while(Option::Some) + .peekable() + .skip(1) + .map(|e| std::num::NonZeroUsize::new(e)) + .map(|z| z.map(|u| u.get()).ok_or(())); + let sink = iter.collect::, _>>().unwrap(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr as *const usize); +} From c6c8f3bf12bdeba01ba16eaacc5808e5321302f8 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Mon, 1 Feb 2021 17:16:54 +0100 Subject: [PATCH 03/19] Move test --- library/alloc/tests/vec.rs | 4 ++-- library/core/tests/iter/mod.rs | 26 -------------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index e19406d7a0697..9ae333ce2c3e5 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -931,9 +931,9 @@ fn test_from_iter_specialization_with_iterator_adapters() { .map_while(Option::Some) .peekable() .skip(1) - .map(|e| std::num::NonZeroUsize::new(e)); + .map(|e| if e != 0 { Ok(e) } else { Err(()) }); assert_in_place_trait(&iter); - let sink = iter.collect::>(); + let sink = iter.collect::, _>>().unwrap(); let sinkptr = sink.as_ptr(); assert_eq!(srcptr, sinkptr as *const usize); } diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index b88f2f2089d18..770b6f7601fa2 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -100,29 +100,3 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } - -#[test] -pub fn inplace_result_collect() { - let src = vec![0usize; 256]; - let srcptr = src.as_ptr(); - let sink = src.into_iter().map(|i| Ok(i)).collect::, ()>>().unwrap(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr); - - let src: Vec = vec![0usize; 256]; - let srcptr = src.as_ptr(); - let iter = src - .into_iter() - .enumerate() - .map(|i| i.0 + i.1) - .zip(std::iter::repeat(1usize)) - .map(|(a, b)| a + b) - .map_while(Option::Some) - .peekable() - .skip(1) - .map(|e| std::num::NonZeroUsize::new(e)) - .map(|z| z.map(|u| u.get()).ok_or(())); - let sink = iter.collect::, _>>().unwrap(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr as *const usize); -} From 2fb56cc123cc1111cff2803ab7df26a0f0941fae Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Wed, 3 Feb 2021 21:00:07 +0100 Subject: [PATCH 04/19] Update test to collect item with a different type than the original vec --- library/alloc/tests/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 9ae333ce2c3e5..9a0739a27595f 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -931,7 +931,7 @@ fn test_from_iter_specialization_with_iterator_adapters() { .map_while(Option::Some) .peekable() .skip(1) - .map(|e| if e != 0 { Ok(e) } else { Err(()) }); + .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) }); assert_in_place_trait(&iter); let sink = iter.collect::, _>>().unwrap(); let sinkptr = sink.as_ptr(); From e7f340e19be8a4d50214c364aabb5577b6b38e9f Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 16 Feb 2021 17:13:43 +0100 Subject: [PATCH 05/19] BTree: move blocks around in node.rs --- library/alloc/src/collections/btree/node.rs | 332 ++++++++++---------- 1 file changed, 165 insertions(+), 167 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 9a7119470f370..f330a1bb3dcfe 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -128,106 +128,6 @@ impl InternalNode { /// is not a separate type and has no destructor. type BoxedNode = NonNull>; -/// The root node of an owned tree. -/// -/// Note that this does not have a destructor, and must be cleaned up manually. -pub type Root = NodeRef; - -impl Root { - /// Returns a new owned tree, with its own root node that is initially empty. - pub fn new() -> Self { - NodeRef::new_leaf().forget_type() - } -} - -impl NodeRef { - fn new_leaf() -> Self { - Self::from_new_leaf(LeafNode::new()) - } - - fn from_new_leaf(leaf: Box>) -> Self { - NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData } - } -} - -impl NodeRef { - fn new_internal(child: Root) -> Self { - let mut new_node = unsafe { InternalNode::new() }; - new_node.edges[0].write(child.node); - unsafe { NodeRef::from_new_internal(new_node, child.height + 1) } - } - - /// # Safety - /// `height` must not be zero. - unsafe fn from_new_internal(internal: Box>, height: usize) -> Self { - debug_assert!(height > 0); - let node = NonNull::from(Box::leak(internal)).cast(); - let mut this = NodeRef { height, node, _marker: PhantomData }; - this.borrow_mut().correct_all_childrens_parent_links(); - this - } -} - -impl NodeRef { - /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe - /// because the return value cannot be used to destroy the root, and there - /// cannot be other references to the tree. - pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } - - /// Slightly mutably borrows the owned root node. - pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } - - /// Irreversibly transitions to a reference that permits traversal and offers - /// destructive methods and little else. - pub fn into_dying(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } -} - -impl NodeRef { - /// Adds a new internal node with a single edge pointing to the previous root node, - /// make that new node the root node, and return it. This increases the height by 1 - /// and is the opposite of `pop_internal_level`. - pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { - super::mem::take_mut(self, |old_root| NodeRef::new_internal(old_root).forget_type()); - - // `self.borrow_mut()`, except that we just forgot we're internal now: - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } - - /// Removes the internal root node, using its first child as the new root node. - /// As it is intended only to be called when the root node has only one child, - /// no cleanup is done on any of the keys, values and other children. - /// This decreases the height by 1 and is the opposite of `push_internal_level`. - /// - /// Requires exclusive access to the `Root` object but not to the root node; - /// it will not invalidate other handles or references to the root node. - /// - /// Panics if there is no internal level, i.e., if the root node is a leaf. - pub fn pop_internal_level(&mut self) { - assert!(self.height > 0); - - let top = self.node; - - // SAFETY: we asserted to be internal. - let internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() }; - // SAFETY: we borrowed `self` exclusively and its borrow type is exclusive. - let internal_node = unsafe { &mut *NodeRef::as_internal_ptr(&internal_self) }; - // SAFETY: the first edge is always initialized. - self.node = unsafe { internal_node.edges[0].assume_init_read() }; - self.height -= 1; - self.clear_parent_link(); - - unsafe { - Global.deallocate(top.cast(), Layout::new::>()); - } - } -} - // N.B. `NodeRef` is always covariant in `K` and `V`, even when the `BorrowType` // is `Mut`. This is technically wrong, but cannot result in any unsafety due to // internal use of `NodeRef` because we stay completely generic over `K` and `V`. @@ -292,6 +192,11 @@ pub struct NodeRef { _marker: PhantomData<(BorrowType, Type)>, } +/// The root node of an owned tree. +/// +/// Note that this does not have a destructor, and must be cleaned up manually. +pub type Root = NodeRef; + impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef, K, V, Type> {} impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef, K, V, Type> { fn clone(&self) -> Self { @@ -307,6 +212,34 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef Send for NodeRef {} unsafe impl Send for NodeRef {} +impl NodeRef { + fn new_leaf() -> Self { + Self::from_new_leaf(LeafNode::new()) + } + + fn from_new_leaf(leaf: Box>) -> Self { + NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData } + } +} + +impl NodeRef { + fn new_internal(child: Root) -> Self { + let mut new_node = unsafe { InternalNode::new() }; + new_node.edges[0].write(child.node); + unsafe { NodeRef::from_new_internal(new_node, child.height + 1) } + } + + /// # Safety + /// `height` must not be zero. + unsafe fn from_new_internal(internal: Box>, height: usize) -> Self { + debug_assert!(height > 0); + let node = NonNull::from(Box::leak(internal)).cast(); + let mut this = NodeRef { height, node, _marker: PhantomData }; + this.borrow_mut().correct_all_childrens_parent_links(); + this + } +} + impl NodeRef { /// Unpack a node reference that was packed as `NodeRef::parent`. fn from_internal(node: NonNull>, height: usize) -> Self { @@ -420,6 +353,19 @@ impl NodeRef } } +impl NodeRef { + /// Could be a public implementation of PartialEq, but only used in this module. + fn eq(&self, other: &Self) -> bool { + let Self { node, height, _marker } = self; + if node.eq(&other.node) { + debug_assert_eq!(*height, other.height); + true + } else { + false + } + } +} + impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Exposes the leaf portion of any leaf or internal node in an immutable tree. fn into_leaf(self) -> &'a LeafNode { @@ -461,20 +407,6 @@ impl NodeRef { } } -impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { - /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. - unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { - debug_assert!(self.height == 0); - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } - - /// Unsafely asserts to the compiler the static information that this node is an `Internal`. - unsafe fn cast_to_internal_unchecked(self) -> NodeRef, K, V, marker::Internal> { - debug_assert!(self.height > 0); - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } -} - impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Temporarily takes out another, mutable reference to the same node. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear @@ -577,6 +509,22 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } } +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// # Safety + /// Every item returned by `range` is a valid edge index for the node. + unsafe fn correct_childrens_parent_links>(&mut self, range: R) { + for i in range { + debug_assert!(i <= self.len()); + unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); + } + } + + fn correct_all_childrens_parent_links(&mut self) { + let len = self.len(); + unsafe { self.correct_childrens_parent_links(0..=len) }; + } +} + impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Sets the node's link to its parent edge, /// without invalidating other references to the node. @@ -596,6 +544,71 @@ impl NodeRef { } } +impl NodeRef { + /// Returns a new owned tree, with its own root node that is initially empty. + pub fn new() -> Self { + NodeRef::new_leaf().forget_type() + } + + /// Adds a new internal node with a single edge pointing to the previous root node, + /// make that new node the root node, and return it. This increases the height by 1 + /// and is the opposite of `pop_internal_level`. + pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { + super::mem::take_mut(self, |old_root| NodeRef::new_internal(old_root).forget_type()); + + // `self.borrow_mut()`, except that we just forgot we're internal now: + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } + + /// Removes the internal root node, using its first child as the new root node. + /// As it is intended only to be called when the root node has only one child, + /// no cleanup is done on any of the keys, values and other children. + /// This decreases the height by 1 and is the opposite of `push_internal_level`. + /// + /// Requires exclusive access to the `Root` object but not to the root node; + /// it will not invalidate other handles or references to the root node. + /// + /// Panics if there is no internal level, i.e., if the root node is a leaf. + pub fn pop_internal_level(&mut self) { + assert!(self.height > 0); + + let top = self.node; + + // SAFETY: we asserted to be internal. + let internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() }; + // SAFETY: we borrowed `self` exclusively and its borrow type is exclusive. + let internal_node = unsafe { &mut *NodeRef::as_internal_ptr(&internal_self) }; + // SAFETY: the first edge is always initialized. + self.node = unsafe { internal_node.edges[0].assume_init_read() }; + self.height -= 1; + self.clear_parent_link(); + + unsafe { + Global.deallocate(top.cast(), Layout::new::>()); + } + } +} + +impl NodeRef { + /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe + /// because the return value cannot be used to destroy the root, and there + /// cannot be other references to the tree. + pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } + + /// Slightly mutably borrows the owned root node. + pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } + + /// Irreversibly transitions to a reference that permits traversal and offers + /// destructive methods and little else. + pub fn into_dying(self) -> NodeRef { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } +} + impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { @@ -610,22 +623,6 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { } } -impl<'a, K, V> NodeRef, K, V, marker::Internal> { - /// # Safety - /// Every item returned by `range` is a valid edge index for the node. - unsafe fn correct_childrens_parent_links>(&mut self, range: R) { - for i in range { - debug_assert!(i <= self.len()); - unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); - } - } - - fn correct_all_childrens_parent_links(&mut self) { - let len = self.len(); - unsafe { self.correct_childrens_parent_links(0..=len) }; - } -} - impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// Adds a key-value pair, and an edge to go to the right of that pair, /// to the end of the node. @@ -645,6 +642,20 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } } +impl NodeRef { + /// Removes any static information asserting that this node is a `Leaf` node. + pub fn forget_type(self) -> NodeRef { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } +} + +impl NodeRef { + /// Removes any static information asserting that this node is an `Internal` node. + pub fn forget_type(self) -> NodeRef { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } +} + impl NodeRef { /// Checks whether a node is an `Internal` node or a `Leaf` node. pub fn force( @@ -669,6 +680,20 @@ impl NodeRef { } } +impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { + /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. + unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + debug_assert!(self.height == 0); + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } + + /// Unsafely asserts to the compiler the static information that this node is an `Internal`. + unsafe fn cast_to_internal_unchecked(self) -> NodeRef, K, V, marker::Internal> { + debug_assert!(self.height > 0); + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } +} + /// A reference to a specific key-value pair or edge within a node. The `Node` parameter /// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key-value /// pair) or `Edge` (signifying a handle on an edge). @@ -722,19 +747,6 @@ impl Handle, mar } } -impl NodeRef { - /// Could be a public implementation of PartialEq, but only used in this module. - fn eq(&self, other: &Self) -> bool { - let Self { node, height, _marker } = self; - if node.eq(&other.node) { - debug_assert_eq!(*height, other.height); - true - } else { - false - } - } -} - impl PartialEq for Handle, HandleType> { @@ -754,16 +766,6 @@ impl } } -impl<'a, K, V, Type> Handle, K, V, marker::LeafOrInternal>, Type> { - /// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`. - pub unsafe fn cast_to_leaf_unchecked( - self, - ) -> Handle, K, V, marker::Leaf>, Type> { - let node = unsafe { self.node.cast_to_leaf_unchecked() }; - Handle { node, idx: self.idx, _marker: PhantomData } - } -} - impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeType>, HandleType> { /// Temporarily takes out another, mutable handle on the same location. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear @@ -1466,20 +1468,6 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } } -impl NodeRef { - /// Removes any static information asserting that this node is a `Leaf` node. - pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } -} - -impl NodeRef { - /// Removes any static information asserting that this node is an `Internal` node. - pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, _marker: PhantomData } - } -} - impl Handle, marker::Edge> { pub fn forget_node_type( self, @@ -1531,6 +1519,16 @@ impl Handle Handle, K, V, marker::LeafOrInternal>, Type> { + /// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`. + pub unsafe fn cast_to_leaf_unchecked( + self, + ) -> Handle, K, V, marker::Leaf>, Type> { + let node = unsafe { self.node.cast_to_leaf_unchecked() }; + Handle { node, idx: self.idx, _marker: PhantomData } + } +} + impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { /// Move the suffix after `self` from one node to another one. `right` must be empty. /// The first edge of `right` remains unchanged. From aef1e35edc11b3e0ecf7f77bc70c197062023476 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 30 Jun 2020 18:58:15 +0200 Subject: [PATCH 06/19] Emit unused externs --- compiler/rustc_errors/src/emitter.rs | 3 +++ compiler/rustc_errors/src/json.rs | 19 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 8 ++++++++ compiler/rustc_metadata/src/creader.rs | 4 ++++ 4 files changed, 34 insertions(+) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 9b6f67166bdaa..dbb71d52e499e 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -195,6 +195,9 @@ pub trait Emitter { fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} + /// Emit list of unused externs + fn emit_unused_externs(&mut self, _unused_externs: &[&str]) {} + /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { true diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index c27b39a9d62ff..a1ab98f766efd 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -159,6 +159,19 @@ impl Emitter for JsonEmitter { } } + fn emit_unused_externs(&mut self, unused_externs: &[&str]) { + let data = UnusedExterns { unused_extern_names: unused_externs }; + let result = if self.pretty { + writeln!(&mut self.dst, "{}", as_pretty_json(&data)) + } else { + writeln!(&mut self.dst, "{}", as_json(&data)) + } + .and_then(|_| self.dst.flush()); + if let Err(e) = result { + panic!("failed to print unused externs: {:?}", e); + } + } + fn source_map(&self) -> Option<&Lrc> { Some(&self.sm) } @@ -322,6 +335,12 @@ struct FutureIncompatReport { future_incompat_report: Vec, } +#[derive(Encodable)] +struct UnusedExterns<'a, 'b> { + /// List of unused externs by their names. + unused_extern_names: &'a [&'b str], +} + impl Diagnostic { fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { let sugg = diag.suggestions.iter().map(|sugg| Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a0be7442d597a..5720e98abc8c2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -767,6 +767,10 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } + pub fn emit_unused_externs(&self, unused_externs: &[&str]) { + self.inner.borrow_mut().emit_unused_externs(unused_externs) + } + pub fn delay_as_bug(&self, diagnostic: Diagnostic) { self.inner.borrow_mut().delay_as_bug(diagnostic) } @@ -841,6 +845,10 @@ impl HandlerInner { self.emitter.emit_artifact_notification(path, artifact_type); } + fn emit_unused_externs(&mut self, unused_externs: &[&str]) { + self.emitter.emit_unused_externs(unused_externs); + } + fn treat_err_as_bug(&self) -> bool { self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get()) } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index b5506acf73522..3f2d312e61b7a 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -893,6 +893,7 @@ impl<'a> CrateLoader<'a> { fn report_unused_deps(&mut self, krate: &ast::Crate) { // Make a point span rather than covering the whole file let span = krate.span.shrink_to_lo(); + let mut unused_externs = Vec::new(); // Complain about anything left over for (name, entry) in self.sess.opts.externs.iter() { if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { @@ -917,6 +918,7 @@ impl<'a> CrateLoader<'a> { ) } }; + unused_externs.push(name as &str); self.sess.parse_sess.buffer_lint_with_diagnostic( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, @@ -929,6 +931,8 @@ impl<'a> CrateLoader<'a> { diag, ); } + // FIXME: add gating + self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); } pub fn postprocess(&mut self, krate: &ast::Crate) { From 3f2ca47a79911d422fd47ee2a23dd08a9fa42aa9 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 30 Jun 2020 20:17:07 +0200 Subject: [PATCH 07/19] Gate the printing on --json=unused-externs --- compiler/rustc_metadata/src/creader.rs | 5 +++-- compiler/rustc_session/src/config.rs | 18 +++++++++++++++--- compiler/rustc_session/src/options.rs | 3 +++ src/librustdoc/config.rs | 2 +- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 3f2d312e61b7a..7b34374032c91 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -931,8 +931,9 @@ impl<'a> CrateLoader<'a> { diag, ); } - // FIXME: add gating - self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); + if self.sess.opts.json_unused_externs { + self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); + } } pub fn postprocess(&mut self, krate: &ast::Crate) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f25828e21618f..a66201953d611 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -734,6 +734,7 @@ impl Default for Options { remap_path_prefix: Vec::new(), edition: DEFAULT_EDITION, json_artifact_notifications: false, + json_unused_externs: false, pretty: None, } } @@ -1254,11 +1255,12 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { /// /// The first value returned is how to render JSON diagnostics, and the second /// is whether or not artifact notifications are enabled. -pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) { +pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, bool) { let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; let mut json_artifact_notifications = false; + let mut json_unused_externs = false; for option in matches.opt_strs("json") { // For now conservatively forbid `--color` with `--json` since `--json` // won't actually be emitting any colors and anything colorized is @@ -1275,6 +1277,7 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, + "unused-externs" => json_unused_externs = true, s => early_error( ErrorOutputType::default(), &format!("unknown `--json` option `{}`", s), @@ -1282,7 +1285,7 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) } } } - (json_rendered(json_color), json_artifact_notifications) + (json_rendered(json_color), json_artifact_notifications, json_unused_externs) } /// Parses the `--error-format` flag. @@ -1860,7 +1863,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let edition = parse_crate_edition(matches); - let (json_rendered, json_artifact_notifications) = parse_json(matches); + let (json_rendered, json_artifact_notifications, json_unused_externs) = parse_json(matches); let error_format = parse_error_format(matches, color, json_rendered); @@ -1873,6 +1876,14 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut debugging_opts = build_debugging_options(matches, error_format); check_debug_option_stability(&debugging_opts, error_format, json_rendered); + if !debugging_opts.unstable_options && json_unused_externs { + early_error( + error_format, + "the `-Z unstable-options` flag must also be passed to enable \ + the flag `--json=unused-externs`", + ); + } + let output_types = parse_output_types(&debugging_opts, matches, error_format); let mut cg = build_codegen_options(matches, error_format); @@ -2050,6 +2061,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { remap_path_prefix, edition, json_artifact_notifications, + json_unused_externs, pretty, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 79bbad8307ba7..cfe29d40b7460 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -147,6 +147,9 @@ top_level_options!( // by the compiler. json_artifact_notifications: bool [TRACKED], + // `true` if we're emitting a JSON blob containing the unused externs + json_unused_externs: bool [UNTRACKED], + pretty: Option [UNTRACKED], } ); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ecb6378f31fb4..5d6d5aaec1404 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -323,7 +323,7 @@ impl Options { } let color = config::parse_color(&matches); - let (json_rendered, _artifacts) = config::parse_json(&matches); + let (json_rendered, ..) = config::parse_json(&matches); let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); From 2d5200605f18717efcb5483cfd2aece167cab7ce Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 5 Jul 2020 19:35:46 +0200 Subject: [PATCH 08/19] Make parse_json return JsonConfig --- compiler/rustc_session/src/config.rs | 19 ++++++++++++++++--- src/librustdoc/config.rs | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a66201953d611..433b87aa3c682 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1251,11 +1251,18 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { } } +/// Possible json config files +pub struct JsonConfig { + pub json_rendered: HumanReadableErrorType, + pub json_artifact_notifications: bool, + pub json_unused_externs: bool, +} + /// Parse the `--json` flag. /// /// The first value returned is how to render JSON diagnostics, and the second /// is whether or not artifact notifications are enabled. -pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, bool) { +pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; @@ -1285,7 +1292,12 @@ pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool, } } } - (json_rendered(json_color), json_artifact_notifications, json_unused_externs) + + JsonConfig { + json_rendered: json_rendered(json_color), + json_artifact_notifications, + json_unused_externs, + } } /// Parses the `--error-format` flag. @@ -1863,7 +1875,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let edition = parse_crate_edition(matches); - let (json_rendered, json_artifact_notifications, json_unused_externs) = parse_json(matches); + let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } = + parse_json(matches); let error_format = parse_error_format(matches, color, json_rendered); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5d6d5aaec1404..112fe230916f2 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -323,7 +323,7 @@ impl Options { } let color = config::parse_color(&matches); - let (json_rendered, ..) = config::parse_json(&matches); + let config::JsonConfig { json_rendered, .. } = config::parse_json(&matches); let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); From 13371b59ee918445ede03cebb741539db807e0e7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 1 Aug 2020 12:57:35 +0200 Subject: [PATCH 09/19] Make doctests collect and emit the unused externs --- compiler/rustc_session/src/config.rs | 4 ++ src/librustdoc/config.rs | 6 +- src/librustdoc/doctest.rs | 85 ++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 433b87aa3c682..2965fe8e1e8b0 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -485,6 +485,10 @@ impl Externs { pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> { self.0.iter() } + + pub fn len(&self) -> usize { + self.0.len() + } } impl ExternEntry { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 112fe230916f2..61035684ef3cd 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -153,6 +153,8 @@ crate struct Options { /// If this option is set to `true`, rustdoc will only run checks and not generate /// documentation. crate run_check: bool, + /// Whether doctests should emit unused externs + crate json_unused_externs: bool, } impl fmt::Debug for Options { @@ -323,7 +325,8 @@ impl Options { } let color = config::parse_color(&matches); - let config::JsonConfig { json_rendered, .. } = config::parse_json(&matches); + let config::JsonConfig { json_rendered, json_unused_externs, .. } = + config::parse_json(&matches); let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); @@ -644,6 +647,7 @@ impl Options { }, crate_name, output_format, + json_unused_externs, }) } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 27ce064669d2c..50cdf46ce4f41 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_errors::{ColorConfig, ErrorReported}; use rustc_hir as hir; @@ -23,6 +23,8 @@ use std::panic; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; use crate::clean::Attributes; use crate::config::Options; @@ -103,8 +105,10 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { let mut test_args = options.test_args.clone(); let display_warnings = options.display_warnings; + let externs = options.externs.clone(); + let json_unused_externs = options.json_unused_externs; - let tests = interface::run_compiler(config, |compiler| { + let res = interface::run_compiler(config, |compiler| { compiler.enter(|queries| { let lower_to_hir = queries.lower_to_hir()?; @@ -147,12 +151,15 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { }); compiler.session().abort_if_errors(); - let ret: Result<_, ErrorReported> = Ok(collector.tests); + let unused_extern_reports = collector.unused_extern_reports.clone(); + let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst); + let ret: Result<_, ErrorReported> = + Ok((collector.tests, unused_extern_reports, compiling_test_count)); ret }) }); - let tests = match tests { - Ok(tests) => tests, + let (tests, unused_extern_reports, compiling_test_count) = match res { + Ok(res) => res, Err(ErrorReported) => return Err(ErrorReported), }; @@ -164,6 +171,29 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { Some(testing::Options::new().display_output(display_warnings)), ); + // Collect and warn about unused externs, but only if we've gotten + // reports for each doctest + if json_unused_externs { + let unused_extern_reports: Vec<_> = + std::mem::take(&mut unused_extern_reports.lock().unwrap()); + if unused_extern_reports.len() == compiling_test_count { + let extern_names = externs.iter().map(|(name, _)| name).collect::>(); + let mut unused_extern_names = unused_extern_reports + .iter() + .map(|uexts| uexts.unused_extern_names.iter().collect::>()) + .fold(extern_names, |uextsa, uextsb| { + uextsa.intersection(&uextsb).map(|v| *v).collect::>() + }) + .iter() + .map(|v| (*v).clone()) + .collect::>(); + unused_extern_names.sort(); + let unused_extern_json = + serde_json::to_string(&UnusedExterns { unused_extern_names }).unwrap(); + eprintln!("{}", unused_extern_json); + } + } + Ok(()) } @@ -233,6 +263,12 @@ impl DirState { } } +#[derive(serde::Serialize, serde::Deserialize)] +struct UnusedExterns { + /// List of unused externs by their names. + unused_extern_names: Vec, +} + fn run_test( test: &str, cratename: &str, @@ -251,6 +287,7 @@ fn run_test( outdir: DirState, path: PathBuf, test_id: &str, + report_unused_externs: impl Fn(UnusedExterns), ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id)); @@ -276,6 +313,11 @@ fn run_test( if as_test_harness { compiler.arg("--test"); } + if options.json_unused_externs && !compile_fail { + compiler.arg("--error-format=json"); + compiler.arg("--json").arg("unused-externs"); + compiler.arg("-Z").arg("unstable-options"); + } for lib_str in &options.lib_strs { compiler.arg("-L").arg(&lib_str); } @@ -335,7 +377,26 @@ fn run_test( eprint!("{}", self.0); } } - let out = str::from_utf8(&output.stderr).unwrap(); + let mut out_lines = str::from_utf8(&output.stderr) + .unwrap() + .lines() + .filter(|l| { + if let Ok(uext) = serde_json::from_str::(l) { + report_unused_externs(uext); + false + } else { + true + } + }) + .collect::>(); + + // Add a \n to the end to properly terminate the last line, + // but only if there was output to be printed + if out_lines.len() > 0 { + out_lines.push(""); + } + + let out = out_lines.join("\n"); let _bomb = Bomb(&out); match (output.status.success(), compile_fail) { (true, true) => { @@ -719,6 +780,8 @@ crate struct Collector { source_map: Option>, filename: Option, visited_tests: FxHashMap<(String, usize), usize>, + unused_extern_reports: Arc>>, + compiling_test_count: AtomicUsize, } impl Collector { @@ -743,6 +806,8 @@ impl Collector { source_map, filename, visited_tests: FxHashMap::default(), + unused_extern_reports: Default::default(), + compiling_test_count: AtomicUsize::new(0), } } @@ -789,6 +854,10 @@ impl Tester for Collector { let runtool_args = self.options.runtool_args.clone(); let target = self.options.target.clone(); let target_str = target.to_string(); + let unused_externs = self.unused_extern_reports.clone(); + if !config.compile_fail { + self.compiling_test_count.fetch_add(1, Ordering::SeqCst); + } // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. @@ -844,6 +913,9 @@ impl Tester for Collector { test_type: testing::TestType::DocTest, }, testfn: testing::DynTestFn(box move || { + let report_unused_externs = |uext| { + unused_externs.lock().unwrap().push(uext); + }; let res = run_test( &test, &cratename, @@ -862,6 +934,7 @@ impl Tester for Collector { outdir, path, &test_id, + report_unused_externs, ); if let Err(err) = res { From 3a62eb74db63f1b49d5e00c32192498abaf1640f Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 10 Aug 2020 01:57:35 +0200 Subject: [PATCH 10/19] Emit the lint level of the unused-crate-dependencies Also, turn off the lint when the unused dependencies json flag is specified so that cargo doesn't have to supress the lint --- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_errors/src/json.rs | 10 ++++--- compiler/rustc_errors/src/lib.rs | 8 +++--- compiler/rustc_interface/src/passes.rs | 7 +++++ compiler/rustc_metadata/src/creader.rs | 36 ++++++++++++++++++++------ src/librustdoc/doctest.rs | 22 ++++++++++++++-- 6 files changed, 66 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index dbb71d52e499e..2b6dec905f142 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -196,7 +196,7 @@ pub trait Emitter { fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} /// Emit list of unused externs - fn emit_unused_externs(&mut self, _unused_externs: &[&str]) {} + fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {} /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index a1ab98f766efd..8511b51e3bffa 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -159,8 +159,8 @@ impl Emitter for JsonEmitter { } } - fn emit_unused_externs(&mut self, unused_externs: &[&str]) { - let data = UnusedExterns { unused_extern_names: unused_externs }; + fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + let data = UnusedExterns { lint_level, unused_extern_names: unused_externs }; let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { @@ -336,9 +336,11 @@ struct FutureIncompatReport { } #[derive(Encodable)] -struct UnusedExterns<'a, 'b> { +struct UnusedExterns<'a, 'b, 'c> { + /// The severity level of the unused dependencies lint + lint_level: &'a str, /// List of unused externs by their names. - unused_extern_names: &'a [&'b str], + unused_extern_names: &'b [&'c str], } impl Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5720e98abc8c2..533c32b32c620 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -767,8 +767,8 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } - pub fn emit_unused_externs(&self, unused_externs: &[&str]) { - self.inner.borrow_mut().emit_unused_externs(unused_externs) + pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) { + self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs) } pub fn delay_as_bug(&self, diagnostic: Diagnostic) { @@ -845,8 +845,8 @@ impl HandlerInner { self.emitter.emit_artifact_notification(path, artifact_type); } - fn emit_unused_externs(&mut self, unused_externs: &[&str]) { - self.emitter.emit_unused_externs(unused_externs); + fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + self.emitter.emit_unused_externs(lint_level, unused_externs); } fn treat_err_as_bug(&self) -> bool { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5217066bbefde..717f4d5a3ba68 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -17,6 +17,7 @@ use rustc_hir::definitions::Definitions; use rustc_hir::Crate; use rustc_index::vec::IndexVec; use rustc_lint::LintStore; +use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::middle; @@ -836,6 +837,12 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { }); sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx)); + + let cstore = tcx + .cstore_as_any() + .downcast_ref::() + .expect("`tcx.cstore` is not a `CStore`"); + cstore.report_unused_deps(tcx); }, { par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 7b34374032c91..9e3f121378cba 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -46,6 +46,9 @@ pub struct CStore { /// This map is used to verify we get no hash conflicts between /// `StableCrateId` values. stable_crate_ids: FxHashMap, + + /// Unused externs of the crate + unused_externs: Vec, } pub struct CrateLoader<'a> { @@ -190,6 +193,21 @@ impl CStore { crate fn has_global_allocator(&self) -> bool { self.has_global_allocator } + + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { + let level = tcx + .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID) + .0; + if level != lint::Level::Allow && tcx.sess.opts.json_unused_externs { + let unused_externs = + self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::>(); + let unused_externs = unused_externs.iter().map(String::as_str).collect::>(); + tcx.sess + .parse_sess + .span_diagnostic + .emit_unused_externs(level.as_str(), &unused_externs); + } + } } impl<'a> CrateLoader<'a> { @@ -217,6 +235,7 @@ impl<'a> CrateLoader<'a> { allocator_kind: None, has_global_allocator: false, stable_crate_ids, + unused_externs: Vec::new(), }, used_extern_options: Default::default(), } @@ -893,18 +912,23 @@ impl<'a> CrateLoader<'a> { fn report_unused_deps(&mut self, krate: &ast::Crate) { // Make a point span rather than covering the whole file let span = krate.span.shrink_to_lo(); - let mut unused_externs = Vec::new(); // Complain about anything left over for (name, entry) in self.sess.opts.externs.iter() { if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { // Don't worry about pathless `--extern foo` sysroot references continue; } - if self.used_extern_options.contains(&Symbol::intern(name)) { + let name_interned = Symbol::intern(name); + if self.used_extern_options.contains(&name_interned) { continue; } // Got a real unused --extern + if self.sess.opts.json_unused_externs { + self.cstore.unused_externs.push(name_interned); + continue; + } + let diag = match self.sess.opts.extern_dep_specs.get(name) { Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()), None => { @@ -918,7 +942,6 @@ impl<'a> CrateLoader<'a> { ) } }; - unused_externs.push(name as &str); self.sess.parse_sess.buffer_lint_with_diagnostic( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, @@ -931,9 +954,6 @@ impl<'a> CrateLoader<'a> { diag, ); } - if self.sess.opts.json_unused_externs { - self.sess.parse_sess.span_diagnostic.emit_unused_externs(&unused_externs); - } } pub fn postprocess(&mut self, krate: &ast::Crate) { @@ -941,9 +961,9 @@ impl<'a> CrateLoader<'a> { self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); - info!("{:?}", CrateDump(&self.cstore)); - self.report_unused_deps(krate); + + info!("{:?}", CrateDump(&self.cstore)); } pub fn process_extern_crate( diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 50cdf46ce4f41..116b3aad61eb4 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -188,8 +188,23 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { .map(|v| (*v).clone()) .collect::>(); unused_extern_names.sort(); - let unused_extern_json = - serde_json::to_string(&UnusedExterns { unused_extern_names }).unwrap(); + // Take the most severe lint level + let lint_level = unused_extern_reports + .iter() + .map(|uexts| uexts.lint_level.as_str()) + .max_by_key(|v| match *v { + "warn" => 1, + "deny" => 2, + "forbid" => 3, + // The allow lint level is not expected, + // as if allow is specified, no message + // is to be emitted. + v => unreachable!("Invalid lint level '{}'", v), + }) + .unwrap_or("warn") + .to_string(); + let uext = UnusedExterns { lint_level, unused_extern_names }; + let unused_extern_json = serde_json::to_string(&uext).unwrap(); eprintln!("{}", unused_extern_json); } } @@ -265,6 +280,8 @@ impl DirState { #[derive(serde::Serialize, serde::Deserialize)] struct UnusedExterns { + /// Lint level of the unused_crate_dependencies lint + lint_level: String, /// List of unused externs by their names. unused_extern_names: Vec, } @@ -317,6 +334,7 @@ fn run_test( compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); + compiler.arg("-W").arg("unused_crate_dependencies"); } for lib_str in &options.lib_strs { compiler.arg("-L").arg(&lib_str); From d8c9a287036f72bf078f868f8fe635b7a7fde32c Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 12 Aug 2020 03:45:16 +0200 Subject: [PATCH 11/19] Fix the tests --- compiler/rustc_metadata/src/creader.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 9e3f121378cba..5634467eeb7fb 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -195,10 +195,16 @@ impl CStore { } pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { + // We put the check for the option before the lint_level_at_node call + // because the call mutates internal state and introducing it + // leads to some ui tests failing. + if !tcx.sess.opts.json_unused_externs { + return; + } let level = tcx .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID) .0; - if level != lint::Level::Allow && tcx.sess.opts.json_unused_externs { + if level != lint::Level::Allow { let unused_externs = self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::>(); let unused_externs = unused_externs.iter().map(String::as_str).collect::>(); From d018ef180d9bc4e852457fd83fda0bec8452baf6 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 2 Mar 2021 03:07:13 +0100 Subject: [PATCH 12/19] Add notes to keep the UnusedExterns structs synced up --- compiler/rustc_errors/src/json.rs | 4 ++++ src/librustdoc/doctest.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 8511b51e3bffa..3753ca580e708 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -335,6 +335,10 @@ struct FutureIncompatReport { future_incompat_report: Vec, } +// NOTE: Keep this in sync with the equivalent structs in rustdoc's +// doctest component (as well as cargo). +// We could unify this struct the one in rustdoc but they have different +// ownership semantics, so doing so would create wasteful allocations. #[derive(Encodable)] struct UnusedExterns<'a, 'b, 'c> { /// The severity level of the unused dependencies lint diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 116b3aad61eb4..f7a6ccfc7d1fd 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -278,6 +278,10 @@ impl DirState { } } +// NOTE: Keep this in sync with the equivalent structs in rustc +// and cargo. +// We could unify this struct the one in rustc but they have different +// ownership semantics, so doing so would create wasteful allocations. #[derive(serde::Serialize, serde::Deserialize)] struct UnusedExterns { /// Lint level of the unused_crate_dependencies lint From 7f5964a5e7eccd3f9191b16da4f7a7662489de74 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 22 Mar 2021 02:31:47 -0400 Subject: [PATCH 13/19] Add `download-rustc = "if-unchanged"` This allows keeping the setting to a fixed value without having to toggle it when you want to work on the compiler instead of on tools. --- config.toml.example | 4 +++- src/bootstrap/bootstrap.py | 8 +++++++- src/bootstrap/config.rs | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/config.toml.example b/config.toml.example index ee06e1bd0ba1b..539ff06c5adc9 100644 --- a/config.toml.example +++ b/config.toml.example @@ -372,7 +372,9 @@ changelog-seen = 2 # Whether to download the stage 1 and 2 compilers from CI. # This is mostly useful for tools; if you have changes to `compiler/` they will be ignored. # -# FIXME: currently, this also uses the downloaded compiler for stage0, but that causes unnecessary rebuilds. +# You can set this to "if-unchanged" to only download if `compiler/` has not been modified. +# +# FIXME(#82739): currently, this also uses the downloaded compiler for stage0, but that causes unnecessary rebuilds. #download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3e7d1d54f1284..59f22f3310caa 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -638,8 +638,10 @@ def fix_bin_or_dylib(self, fname, rpath_libz=False): # Return the stage1 compiler to download, if any. def maybe_download_rustc(self): # If `download-rustc` is not set, default to rebuilding. - if self.get_toml("download-rustc", section="rust") != "true": + download_rustc = self.get_toml("download-rustc", section="rust") + if download_rustc is None or download_rustc == "false": return None + assert download_rustc == "true" or download_rustc == "if-unchanged", download_rustc # Handle running from a directory other than the top level rev_parse = ["git", "rev-parse", "--show-toplevel"] @@ -654,6 +656,8 @@ def maybe_download_rustc(self): # Warn if there were changes to the compiler since the ancestor commit. status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler]) if status != 0: + if download_rustc == "if-unchanged": + return None print("warning: `download-rustc` is enabled, but there are changes to compiler/") return commit @@ -1158,6 +1162,8 @@ def bootstrap(help_triggered): env["RUSTC_BOOTSTRAP"] = '1' if toml_path: env["BOOTSTRAP_CONFIG"] = toml_path + if build.rustc_commit is not None: + env["BOOTSTRAP_DOWNLOAD_RUSTC"] = '1' run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b9b090bb2d2de..36aa0ee4358bd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -510,7 +510,7 @@ struct Rust { new_symbol_mangling: Option, profile_generate: Option, profile_use: Option, - download_rustc: Option, + download_rustc: Option, } /// TOML representation of how each build target is configured. @@ -897,7 +897,7 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc = rust.download_rustc.unwrap_or(false); + config.download_rustc = env::var("BOOTSTRAP_DOWNLOAD_RUSTC").as_deref() == Ok("1"); } else { config.rust_profile_use = flags.rust_profile_use; config.rust_profile_generate = flags.rust_profile_generate; From 4f73d2153c4a8c71e5fa9c03b6b9f3af39491319 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 26 Mar 2021 15:25:48 -0600 Subject: [PATCH 14/19] Fix compiletest on FreeBSD Recent FreeBSD gdb packages have a different format for the version string. --- src/tools/compiletest/src/main.rs | 3 ++- src/tools/compiletest/src/tests.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 1d4b5e1247de7..480916018619d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -909,7 +909,8 @@ fn extract_gdb_version(full_version_line: &str) -> Option { // This particular form is documented in the GNU coding standards: // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - let mut splits = full_version_line.rsplit(' '); + let unbracketed_part = full_version_line.split('[').next().unwrap(); + let mut splits = unbracketed_part.trim_end().rsplit(' '); let version_string = splits.next().unwrap(); let mut splits = version_string.split('.'); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index ea9bc1c1a5b7f..ce75cb2878bec 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -39,6 +39,9 @@ fn test_extract_gdb_version() { 7012000: "GNU gdb (GDB) 7.12", 7012000: "GNU gdb (GDB) 7.12.20161027-git", 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", + + 9002000: "GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2", + 10001000: "GNU gdb (GDB) 10.1 [GDB v10.1 for FreeBSD]", } } From d1c591b5ab9842df8b7bf31c501106c43a868ce7 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 25 Mar 2021 18:49:35 +0800 Subject: [PATCH 15/19] Allow using `-C force-unwind-tables=no` when `panic=unwind` --- compiler/rustc_session/src/session.rs | 25 +++++--------- .../assembly/panic-no-unwind-no-uwtable.rs | 8 +++++ src/test/assembly/panic-unwind-no-uwtable.rs | 12 +++++++ src/test/codegen/force-no-unwind-tables.rs | 8 +++-- .../codegen/panic-unwind-default-uwtable.rs | 6 ++++ .../unwind-tables-panic-required.rs | 11 ------- src/test/ui/unwind-no-uwtable.rs | 33 +++++++++++++++++++ 7 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 src/test/assembly/panic-no-unwind-no-uwtable.rs create mode 100644 src/test/assembly/panic-unwind-no-uwtable.rs create mode 100644 src/test/codegen/panic-unwind-default-uwtable.rs delete mode 100644 src/test/ui/panic-runtime/unwind-tables-panic-required.rs create mode 100644 src/test/ui/unwind-no-uwtable.rs diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a30b4ae9b971c..7a91a406b76fd 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -844,8 +844,11 @@ impl Session { // This is used to control the emission of the `uwtable` attribute on // LLVM functions. // - // At the very least, unwind tables are needed when compiling with - // `-C panic=unwind`. + // Unwind tables are needed when compiling with `-C panic=unwind`, but + // LLVM won't omit unwind tables unless the function is also marked as + // `nounwind`, so users are allowed to disable `uwtable` emission. + // Historically rustc always emits `uwtable` attributes by default, so + // even they can be disabled, they're still emitted by default. // // On some targets (including windows), however, exceptions include // other events such as illegal instructions, segfaults, etc. This means @@ -858,13 +861,10 @@ impl Session { // If a target requires unwind tables, then they must be emitted. // Otherwise, we can defer to the `-C force-unwind-tables=` // value, if it is provided, or disable them, if not. - if self.panic_strategy() == PanicStrategy::Unwind { - true - } else if self.target.requires_uwtable { - true - } else { - self.opts.cg.force_unwind_tables.unwrap_or(self.target.default_uwtable) - } + self.target.requires_uwtable + || self.opts.cg.force_unwind_tables.unwrap_or( + self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable, + ) } /// Returns the symbol name for the registrar function, @@ -1536,13 +1536,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Unwind tables cannot be disabled if the target requires them. if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { - if sess.panic_strategy() == PanicStrategy::Unwind && !include_uwtables { - sess.err( - "panic=unwind requires unwind tables, they cannot be disabled \ - with `-C force-unwind-tables=no`.", - ); - } - if sess.target.requires_uwtable && !include_uwtables { sess.err( "target requires unwind tables, they cannot be disabled with \ diff --git a/src/test/assembly/panic-no-unwind-no-uwtable.rs b/src/test/assembly/panic-no-unwind-no-uwtable.rs new file mode 100644 index 0000000000000..0d49ea8852454 --- /dev/null +++ b/src/test/assembly/panic-no-unwind-no-uwtable.rs @@ -0,0 +1,8 @@ +// assembly-output: emit-asm +// only-x86_64-unknown-linux-gnu +// compile-flags: -C panic=unwind -C force-unwind-tables=n + +#![crate_type = "lib"] + +// CHECK-NOT: .cfi_startproc +pub fn foo() {} diff --git a/src/test/assembly/panic-unwind-no-uwtable.rs b/src/test/assembly/panic-unwind-no-uwtable.rs new file mode 100644 index 0000000000000..8eed72b2fca69 --- /dev/null +++ b/src/test/assembly/panic-unwind-no-uwtable.rs @@ -0,0 +1,12 @@ +// assembly-output: emit-asm +// only-x86_64-unknown-linux-gnu +// compile-flags: -C panic=unwind -C force-unwind-tables=n + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +// CHECK: .cfi_startproc +#[no_mangle] +fn foo() { + panic!(); +} diff --git a/src/test/codegen/force-no-unwind-tables.rs b/src/test/codegen/force-no-unwind-tables.rs index dc77e6cb70917..b7678d89f1ca6 100644 --- a/src/test/codegen/force-no-unwind-tables.rs +++ b/src/test/codegen/force-no-unwind-tables.rs @@ -1,7 +1,11 @@ -// compile-flags: -C no-prepopulate-passes -C panic=abort -C force-unwind-tables=n +// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=n // ignore-windows #![crate_type="lib"] +// CHECK-LABEL: define void @foo // CHECK-NOT: attributes #{{.*}} uwtable -pub fn foo() {} +#[no_mangle] +fn foo() { + panic!(); +} diff --git a/src/test/codegen/panic-unwind-default-uwtable.rs b/src/test/codegen/panic-unwind-default-uwtable.rs new file mode 100644 index 0000000000000..6b64f289f61a5 --- /dev/null +++ b/src/test/codegen/panic-unwind-default-uwtable.rs @@ -0,0 +1,6 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} uwtable +pub fn foo() {} diff --git a/src/test/ui/panic-runtime/unwind-tables-panic-required.rs b/src/test/ui/panic-runtime/unwind-tables-panic-required.rs deleted file mode 100644 index 6393a27046b8a..0000000000000 --- a/src/test/ui/panic-runtime/unwind-tables-panic-required.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Tests that the compiler errors if the user tries to turn off unwind tables -// when they are required. -// -// dont-check-compiler-stderr -// compile-flags: -C panic=unwind -C force-unwind-tables=no -// ignore-tidy-linelength -// -// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`. - -pub fn main() { -} diff --git a/src/test/ui/unwind-no-uwtable.rs b/src/test/ui/unwind-no-uwtable.rs new file mode 100644 index 0000000000000..62b8e3826df81 --- /dev/null +++ b/src/test/ui/unwind-no-uwtable.rs @@ -0,0 +1,33 @@ +// run-pass +// ignore-windows target requires uwtable +// compile-flags: -C panic=unwind -C force-unwind-tables=n + +use std::panic::{self, AssertUnwindSafe}; + +struct Increase<'a>(&'a mut u8); + +impl Drop for Increase<'_> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +#[inline(never)] +fn unwind() { + panic!(); +} + +#[inline(never)] +fn increase(count: &mut u8) { + let _increase = Increase(count); + unwind(); +} + +fn main() { + let mut count = 0; + assert!(panic::catch_unwind(AssertUnwindSafe( + #[inline(never)] + || increase(&mut count) + )).is_err()); + assert_eq!(count, 1); +} From 2fb1fb7634b79d93d48749ee1f84d4ba552b186f Mon Sep 17 00:00:00 2001 From: Roxane Date: Thu, 25 Mar 2021 23:03:12 -0400 Subject: [PATCH 16/19] Fix diagnostic issue when using FakeReads in closures --- compiler/rustc_middle/src/mir/mod.rs | 16 ++++++++-- .../diagnostics/explain_borrow.rs | 2 +- .../src/borrow_check/diagnostics/mod.rs | 22 +++++++++++-- .../src/build/expr/as_rvalue.rs | 32 ++++++++----------- .../rustc_mir_build/src/build/matches/mod.rs | 6 ++-- compiler/rustc_typeck/src/expr_use_visitor.rs | 21 ++++++++++-- ..._of_reborrow.SimplifyCfg-initial.after.mir | 28 ++++++++-------- ...row_and_cast.SimplifyCfg-initial.after.mir | 6 ++-- ...ignment.main.SimplifyCfg-initial.after.mir | 4 +-- ....match_tuple.SimplifyCfg-initial.after.mir | 2 +- ...e_38669.main.SimplifyCfg-initial.after.mir | 2 +- .../mir-opt/issue_49232.main.mir_map.0.mir | 4 +-- .../issue_72181.main.mir_map.0.32bit.mir | 2 +- .../issue_72181.main.mir_map.0.64bit.mir | 2 +- .../mir-opt/issue_72181_1.f.mir_map.0.mir | 2 +- .../mir-opt/issue_72181_1.main.mir_map.0.mir | 2 +- ....main.SimplifyCfg-promote-consts.after.mir | 2 +- ...fg-initial.after-ElaborateDrops.after.diff | 2 +- ...s.full_tested_match.PromoteTemps.after.mir | 2 +- ...full_tested_match2.PromoteTemps.before.mir | 2 +- ...h_false_edges.main.PromoteTemps.before.mir | 2 +- ...ch_test.main.SimplifyCfg-initial.after.mir | 6 ++-- ...egion_subtyping_basic.main.nll.0.32bit.mir | 6 ++-- ...egion_subtyping_basic.main.nll.0.64bit.mir | 6 ++-- ...receiver_ptr_mutability.main.mir_map.0.mir | 4 +-- ...tch_guard.CleanupNonCodegenStatements.diff | 2 +- ...imple_match.match_bool.mir_map.0.32bit.mir | 2 +- ...imple_match.match_bool.mir_map.0.64bit.mir | 2 +- .../mir-opt/storage_ranges.main.nll.0.mir | 6 ++-- ...ove_out.move_out_by_subslice.mir_map.0.mir | 2 +- ...y_move_out.move_out_from_end.mir_map.0.mir | 2 +- 31 files changed, 120 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b2cf1aab112b3..1f7e12db47a01 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1452,7 +1452,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Statement<'_>, 32); +static_assert_size!(Statement<'_>, 40); impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1575,7 +1575,12 @@ pub enum FakeReadCause { /// `let x: !; match x {}` doesn't generate any read of x so we need to /// generate a read of x to check that it is initialized and safe. - ForMatchedPlace, + /// + /// If a closure pattern matches a Place starting with an Upvar, then we introduce a + /// FakeRead for that Place outside the closure, in such a case this option would be + /// Some(closure_def_id). + /// Otherwise, the value of the optional DefId will be None. + ForMatchedPlace(Option), /// A fake read of the RefWithinGuard version of a bind-by-value variable /// in a match guard to ensure that it's value hasn't change by the time @@ -1594,7 +1599,12 @@ pub enum FakeReadCause { /// but in some cases it can affect the borrow checker, as in #53695. /// Therefore, we insert a "fake read" here to ensure that we get /// appropriate errors. - ForLet, + /// + /// If a closure pattern matches a Place starting with an Upvar, then we introduce a + /// FakeRead for that Place outside the closure, in such a case this option would be + /// Some(closure_def_id). + /// Otherwise, the value of the optional DefId will be None. + ForLet(Option), /// If we have an index expression like /// diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index 06e3f4b91f61f..4ab0fe082598b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -515,7 +515,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(FakeReadCause::ForLet, _), + kind: StatementKind::FakeRead(FakeReadCause::ForLet(_), _), .. }) = block.statements.get(location.statement_index) { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 6ea0ba0a8e1ba..6a457487348e7 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItemGroup; use rustc_hir::GeneratorKind; use rustc_middle::mir::{ - AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, + Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; @@ -795,6 +795,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + // StatementKind::FakeRead only contains a def_id if they are introduced as a result + // of pattern matching within a closure. + if let StatementKind::FakeRead(cause, box ref place) = stmt.kind { + match cause { + FakeReadCause::ForMatchedPlace(Some(closure_def_id)) + | FakeReadCause::ForLet(Some(closure_def_id)) => { + debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); + let places = &[Operand::Move(*place)]; + if let Some((args_span, generator_kind, var_span)) = + self.closure_span(closure_def_id, moved_place, places) + { + return ClosureUse { generator_kind, args_span, var_span }; + } + } + _ => {} + } + } + let normal_ret = if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { PatUse(stmt.source_info.span) diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 7f24a41b00bbe..822fbd91c947e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -179,24 +179,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // match x { _ => () } // fake read of `x` // }; // ``` - // FIXME(RFC2229): Remove feature gate once diagnostics are improved - if this.tcx.features().capture_disjoint_fields { - for (thir_place, cause, hir_id) in fake_reads.into_iter() { - let place_builder = - unpack!(block = this.as_place_builder(block, thir_place)); - - if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); - this.cfg.push_fake_read( - block, - this.source_info(this.tcx.hir().span(*hir_id)), - *cause, - mir_place, - ); - } + for (thir_place, cause, hir_id) in fake_reads.into_iter() { + let place_builder = unpack!(block = this.as_place_builder(block, thir_place)); + + if let Ok(place_builder_resolved) = + place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = + place_builder_resolved.into_place(this.tcx, this.typeck_results); + this.cfg.push_fake_read( + block, + this.source_info(this.tcx.hir().span(*hir_id)), + *cause, + mir_place, + ); } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 73fd3f0feb591..0e422dc3c6378 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // uninhabited value. If we get never patterns, those will check that // the place is initialized, and so this read would only be used to // check safety. - let cause_matched_place = FakeReadCause::ForMatchedPlace; + let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let source_info = self.source_info(scrutinee_span); if let Ok(scrutinee_builder) = @@ -400,7 +400,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); - self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place); + self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place); self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() @@ -435,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); - let cause_let = FakeReadCause::ForLet; + let cause_let = FakeReadCause::ForLet(None); self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); let ty_source_info = self.source_info(user_ty_span); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ab286bacd8189..02510cb6a44cf 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -280,9 +280,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { if needs_to_be_read { self.borrow_expr(&discr, ty::ImmBorrow); } else { + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), + _ => None, + }; + self.delegate.fake_read( discr_place.place.clone(), - FakeReadCause::ForMatchedPlace, + FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); @@ -578,9 +583,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), + _ => None, + }; + self.delegate.fake_read( discr_place.place.clone(), - FakeReadCause::ForMatchedPlace, + FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); self.walk_pat(discr_place, &arm.pat); @@ -595,9 +605,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), + _ => None, + }; + self.delegate.fake_read( discr_place.place.clone(), - FakeReadCause::ForLet, + FakeReadCause::ForLet(closure_def_id), discr_place.hir_id, ); self.walk_pat(discr_place, pat); diff --git a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index a95681126205f..9fa478f8a826c 100644 --- a/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -130,12 +130,12 @@ fn address_of_reborrow() -> () { StorageLive(_2); // scope 0 at $DIR/address-of.rs:4:14: 4:21 _2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21 _1 = &_2; // scope 0 at $DIR/address-of.rs:4:13: 4:21 - FakeRead(ForLet, _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10 StorageLive(_3); // scope 1 at $DIR/address-of.rs:5:9: 5:14 StorageLive(_4); // scope 1 at $DIR/address-of.rs:5:22: 5:29 _4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29 _3 = &mut _4; // scope 1 at $DIR/address-of.rs:5:17: 5:29 - FakeRead(ForLet, _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14 + FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14 StorageLive(_5); // scope 2 at $DIR/address-of.rs:7:5: 7:18 StorageLive(_6); // scope 2 at $DIR/address-of.rs:7:5: 7:18 _6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:7:5: 7:6 @@ -170,25 +170,25 @@ fn address_of_reborrow() -> () { StorageDead(_13); // scope 2 at $DIR/address-of.rs:11:20: 11:21 StorageLive(_15); // scope 2 at $DIR/address-of.rs:13:9: 13:10 _15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:13:23: 13:24 - FakeRead(ForLet, _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10 + FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10 AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:13:12: 13:20 StorageLive(_16); // scope 3 at $DIR/address-of.rs:14:9: 14:10 _16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:14:31: 14:32 - FakeRead(ForLet, _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10 + FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10 AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:14:12: 14:28 StorageLive(_17); // scope 4 at $DIR/address-of.rs:15:9: 15:10 StorageLive(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31 _18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:15:30: 15:31 _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:15:30: 15:31 StorageDead(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31 - FakeRead(ForLet, _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10 + FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10 AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:15:12: 15:27 StorageLive(_19); // scope 5 at $DIR/address-of.rs:16:9: 16:10 StorageLive(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28 _20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:16:27: 16:28 _19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:16:27: 16:28 StorageDead(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28 - FakeRead(ForLet, _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10 + FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10 AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:16:12: 16:24 StorageLive(_21); // scope 6 at $DIR/address-of.rs:18:5: 18:18 StorageLive(_22); // scope 6 at $DIR/address-of.rs:18:5: 18:18 @@ -218,25 +218,25 @@ fn address_of_reborrow() -> () { StorageDead(_27); // scope 6 at $DIR/address-of.rs:21:22: 21:23 StorageLive(_29); // scope 6 at $DIR/address-of.rs:23:9: 23:10 _29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:23:23: 23:24 - FakeRead(ForLet, _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10 + FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10 AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:23:12: 23:20 StorageLive(_30); // scope 7 at $DIR/address-of.rs:24:9: 24:10 _30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:24:31: 24:32 - FakeRead(ForLet, _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10 + FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10 AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:24:12: 24:28 StorageLive(_31); // scope 8 at $DIR/address-of.rs:25:9: 25:10 StorageLive(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31 _32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:25:30: 25:31 _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:25:30: 25:31 StorageDead(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31 - FakeRead(ForLet, _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10 + FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10 AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:25:12: 25:27 StorageLive(_33); // scope 9 at $DIR/address-of.rs:26:9: 26:10 StorageLive(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28 _34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:26:27: 26:28 _33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:26:27: 26:28 StorageDead(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28 - FakeRead(ForLet, _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10 + FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10 AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:26:12: 26:24 StorageLive(_35); // scope 10 at $DIR/address-of.rs:28:5: 28:16 StorageLive(_36); // scope 10 at $DIR/address-of.rs:28:5: 28:16 @@ -266,25 +266,25 @@ fn address_of_reborrow() -> () { StorageDead(_41); // scope 10 at $DIR/address-of.rs:31:20: 31:21 StorageLive(_43); // scope 10 at $DIR/address-of.rs:33:9: 33:10 _43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:33:21: 33:22 - FakeRead(ForLet, _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10 + FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10 AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:33:12: 33:18 StorageLive(_44); // scope 11 at $DIR/address-of.rs:34:9: 34:10 _44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:34:29: 34:30 - FakeRead(ForLet, _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10 + FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10 AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:34:12: 34:26 StorageLive(_45); // scope 12 at $DIR/address-of.rs:35:9: 35:10 StorageLive(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29 _46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:35:28: 35:29 _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:35:28: 35:29 StorageDead(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29 - FakeRead(ForLet, _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10 + FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10 AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:35:12: 35:25 StorageLive(_47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 StorageLive(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26 _48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:36:25: 36:26 _47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:36:25: 36:26 StorageDead(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26 - FakeRead(ForLet, _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 + FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10 AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:36:12: 36:22 _0 = const (); // scope 0 at $DIR/address-of.rs:3:26: 37:2 StorageDead(_47); // scope 13 at $DIR/address-of.rs:37:1: 37:2 diff --git a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir index e058b0aaa8f0e..195f3e2e65c64 100644 --- a/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address_of.borrow_and_cast.SimplifyCfg-initial.after.mir @@ -24,19 +24,19 @@ fn borrow_and_cast(_1: i32) -> () { StorageLive(_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15 _3 = &_1; // scope 0 at $DIR/address-of.rs:42:13: 42:15 _2 = &raw const (*_3); // scope 0 at $DIR/address-of.rs:42:13: 42:15 - FakeRead(ForLet, _2); // scope 0 at $DIR/address-of.rs:42:9: 42:10 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/address-of.rs:42:9: 42:10 StorageDead(_3); // scope 0 at $DIR/address-of.rs:42:29: 42:30 StorageLive(_4); // scope 1 at $DIR/address-of.rs:43:9: 43:10 StorageLive(_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19 _5 = &mut _1; // scope 1 at $DIR/address-of.rs:43:13: 43:19 _4 = &raw const (*_5); // scope 1 at $DIR/address-of.rs:43:13: 43:19 - FakeRead(ForLet, _4); // scope 1 at $DIR/address-of.rs:43:9: 43:10 + FakeRead(ForLet(None), _4); // scope 1 at $DIR/address-of.rs:43:9: 43:10 StorageDead(_5); // scope 1 at $DIR/address-of.rs:43:33: 43:34 StorageLive(_6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 StorageLive(_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19 _7 = &mut _1; // scope 2 at $DIR/address-of.rs:44:13: 44:19 _6 = &raw mut (*_7); // scope 2 at $DIR/address-of.rs:44:13: 44:19 - FakeRead(ForLet, _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 + FakeRead(ForLet(None), _6); // scope 2 at $DIR/address-of.rs:44:9: 44:10 StorageDead(_7); // scope 2 at $DIR/address-of.rs:44:31: 44:32 _0 = const (); // scope 0 at $DIR/address-of.rs:41:32: 45:2 StorageDead(_6); // scope 2 at $DIR/address-of.rs:45:1: 45:2 diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 7e0ca3dea4b71..e751b825c0505 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -28,7 +28,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 _1 = const false; // scope 0 at $DIR/basic_assignment.rs:11:20: 11:25 - FakeRead(ForLet, _1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/basic_assignment.rs:11:9: 11:17 StorageLive(_2); // scope 1 at $DIR/basic_assignment.rs:12:9: 12:17 StorageLive(_3); // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24 _3 = _1; // scope 2 at $DIR/basic_assignment.rs:16:16: 16:24 @@ -36,7 +36,7 @@ fn main() -> () { StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:16:23: 16:24 StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 _4 = Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 - FakeRead(ForLet, _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 + FakeRead(ForLet(None), _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:18:17: 18:33 StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index aa4f996c4b46a..93507879a6f83 100644 --- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -18,7 +18,7 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { } bb0: { - FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/exponential-or.rs:5:11: 5:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential-or.rs:5:11: 5:12 switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:6:15: 6:16 } diff --git a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir index e9e5a101a64a5..8355b2d195e14 100644 --- a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir @@ -14,7 +14,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25 _1 = const false; // scope 0 at $DIR/issue-38669.rs:5:28: 5:33 - FakeRead(ForLet, _1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-38669.rs:5:9: 5:25 goto -> bb1; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6 } diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir index 79f5495c78828..06fbbda3d9e22 100644 --- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir @@ -24,7 +24,7 @@ fn main() -> () { StorageLive(_2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19 StorageLive(_3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 _3 = const true; // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 - FakeRead(ForMatchedPlace, _3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 + FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue-49232.rs:8:19: 8:23 switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22 } @@ -51,7 +51,7 @@ fn main() -> () { } bb8: { - FakeRead(ForLet, _2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-49232.rs:7:13: 7:19 StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:12:10: 12:11 StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:13:14: 13:21 diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir index cf66a501e35ee..2e6783b7f3c9d 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir @@ -38,7 +38,7 @@ fn main() -> () { _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 - FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir index cf66a501e35ee..2e6783b7f3c9d 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir @@ -38,7 +38,7 @@ fn main() -> () { _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 - FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 diff --git a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir index 7571d7bb94f92..7def08ece220b 100644 --- a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir @@ -9,7 +9,7 @@ fn f(_1: Void) -> ! { bb0: { StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 - FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 } diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index 1fd91c2056bf8..3c26b20c35e2d 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -29,7 +29,7 @@ fn main() -> () { bb1: { StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44 - FakeRead(ForLet, _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16 StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index f109937dbf937..99c7ac8d5b708 100644 --- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir +++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir @@ -41,7 +41,7 @@ fn main() -> () { bb4: { StorageLive(_6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 _6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18 - FakeRead(ForLet, _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 + FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6 goto -> bb3; // scope 0 at $DIR/loop_test.rs:1:1: 1:1 } diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 95beab2ec9af7..3395cbfbdfb3a 100644 --- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -31,7 +31,7 @@ } bb0: { -- FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 +- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16 - switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15 + switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15 } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 1921b93594129..5af242376c930 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -27,7 +27,7 @@ fn full_tested_match() -> () { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 - FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index c7b1cce061bc6..a4ebf8a02466a 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -26,7 +26,7 @@ fn full_tested_match2() -> () { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 - FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 } diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index 9b8ce2c1ed047..5de52b324f43f 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -37,7 +37,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 _2 = Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 - FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 + FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 } diff --git a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir index e3bc4f80f27fd..5bb910947ca25 100644 --- a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir @@ -21,12 +21,12 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_test.rs:7:9: 7:10 _1 = const 3_i32; // scope 0 at $DIR/match_test.rs:7:13: 7:14 - FakeRead(ForLet, _1); // scope 0 at $DIR/match_test.rs:7:9: 7:10 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/match_test.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/match_test.rs:8:9: 8:10 _2 = const true; // scope 1 at $DIR/match_test.rs:8:13: 8:17 - FakeRead(ForLet, _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10 + FakeRead(ForLet(None), _2); // scope 1 at $DIR/match_test.rs:8:9: 8:10 StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6 - FakeRead(ForMatchedPlace, _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12 + FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12 _6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14 switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 8c939d5fc3da5..39e6cee11b4c9 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -46,7 +46,7 @@ fn main() -> () { bb0: { StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 - FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 @@ -57,10 +57,10 @@ fn main() -> () { bb1: { _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 - FakeRead(ForLet, _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 - FakeRead(ForLet, _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 00704baa6c19f..6021b6529f911 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -46,7 +46,7 @@ fn main() -> () { bb0: { StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 - FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 @@ -57,10 +57,10 @@ fn main() -> () { bb1: { _2 = &'_#3r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 - FakeRead(ForLet, _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 - FakeRead(ForLet, _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 diff --git a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir index d2d96ff468dfc..f54c8f8ab4a2e 100644 --- a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir +++ b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir @@ -36,7 +36,7 @@ fn main() -> () { } bb1: { - FakeRead(ForLet, _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:14: 14:23 StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 @@ -63,7 +63,7 @@ fn main() -> () { _7 = &_8; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 _6 = &_7; // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 _5 = &(*_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 - FakeRead(ForLet, _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 + FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:18: 18:31 StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:41: 18:42 StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff index 47027311b4759..4aa388fc67bd0 100644 --- a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff +++ b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff @@ -13,7 +13,7 @@ let mut _8: bool; // in scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21 bb0: { -- FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 +- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 + nop; // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12 _3 = discriminant(_1); // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16 switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16 diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir index 5bcb20ca72a3f..841cca7c381f7 100644 --- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir +++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir @@ -5,7 +5,7 @@ fn match_bool(_1: bool) -> usize { let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32 bb0: { - FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13 } diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir index 5bcb20ca72a3f..841cca7c381f7 100644 --- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir +++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir @@ -5,7 +5,7 @@ fn match_bool(_1: bool) -> usize { let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:5:27: 5:32 bb0: { - FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 + FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:6:11: 6:12 switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13 } diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index 6fa83d3de6253..e02580135af38 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -39,7 +39,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 _1 = const 0_i32; // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14 - FakeRead(ForLet, _1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10 StorageLive(_2); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6 StorageLive(_3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 @@ -48,14 +48,14 @@ fn main() -> () { _4 = Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:6:24: 6:25 _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25 - FakeRead(ForLet, _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 + FakeRead(ForLet(None), _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 _2 = const (); // scope 1 at $DIR/storage_ranges.rs:5:5: 7:6 StorageDead(_4); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 StorageDead(_3); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 StorageDead(_2); // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6 StorageLive(_6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 _6 = const 1_i32; // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14 - FakeRead(ForLet, _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 + FakeRead(ForLet(None), _6); // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10 _0 = const (); // scope 0 at $DIR/storage_ranges.rs:3:11: 9:2 StorageDead(_6); // scope 1 at $DIR/storage_ranges.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/storage_ranges.rs:9:1: 9:2 diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index d18f6308ded84..7f81d9fc482ff 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -48,7 +48,7 @@ fn move_out_by_subslice() -> () { bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index eda8e5fd3afe7..62ab494c06628 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -48,7 +48,7 @@ fn move_out_from_end() -> () { bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 From 0a97eee8df1f4a3182cd92786258ee5cf2baa43f Mon Sep 17 00:00:00 2001 From: Roxane Date: Mon, 29 Mar 2021 22:48:44 -0400 Subject: [PATCH 17/19] Reduce size of statements --- compiler/rustc_middle/src/mir/mod.rs | 8 +++++--- compiler/rustc_middle/src/mir/visit.rs | 2 +- .../src/borrow_check/diagnostics/conflict_errors.rs | 2 +- .../src/borrow_check/diagnostics/explain_borrow.rs | 2 +- compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs | 2 +- compiler/rustc_mir/src/borrow_check/invalidation.rs | 2 +- compiler/rustc_mir/src/borrow_check/mod.rs | 2 +- compiler/rustc_mir/src/dataflow/move_paths/builder.rs | 4 ++-- compiler/rustc_mir/src/transform/coverage/spans.rs | 4 ++-- compiler/rustc_mir_build/src/build/cfg.rs | 2 +- 10 files changed, 16 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1f7e12db47a01..a7e9fc468b4fd 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1452,7 +1452,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Statement<'_>, 40); +static_assert_size!(Statement<'_>, 32); impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1482,7 +1482,7 @@ pub enum StatementKind<'tcx> { /// /// Note that this also is emitted for regular `let` bindings to ensure that locals that are /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` - FakeRead(FakeReadCause, Box>), + FakeRead(Box<(FakeReadCause, Place<'tcx>)>), /// Write the discriminant for a variant to the enum Place. SetDiscriminant { place: Box>, variant_index: VariantIdx }, @@ -1628,7 +1628,9 @@ impl Debug for Statement<'_> { use self::StatementKind::*; match self.kind { Assign(box (ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), - FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), + FakeRead(box (ref cause, ref place)) => { + write!(fmt, "FakeRead({:?}, {:?})", cause, place) + } Retag(ref kind, ref place) => write!( fmt, "Retag({}{:?})", diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 32b4cd665d03f..fd504f8c5d5ac 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -380,7 +380,7 @@ macro_rules! make_mir_visitor { ) => { self.visit_assign(place, rvalue, location); } - StatementKind::FakeRead(_, place) => { + StatementKind::FakeRead(box (_, place)) => { self.visit_place( place, PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index eb942b195b252..d5deec820889a 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1728,7 +1728,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { match statement { - Statement { kind: StatementKind::FakeRead(cause, box place), .. } + Statement { kind: StatementKind::FakeRead(box (cause, place)), .. } if *place == self.place => { self.cause = Some(*cause); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index 4ab0fe082598b..2a388b8a72bb0 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -515,7 +515,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(FakeReadCause::ForLet(_), _), + kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), .. }) = block.statements.get(location.statement_index) { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 6a457487348e7..577d7d53814ee 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -797,7 +797,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // StatementKind::FakeRead only contains a def_id if they are introduced as a result // of pattern matching within a closure. - if let StatementKind::FakeRead(cause, box ref place) = stmt.kind { + if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind { match cause { FakeReadCause::ForMatchedPlace(Some(closure_def_id)) | FakeReadCause::ForLet(Some(closure_def_id)) => { diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index 1055e30a3a44c..9374741f83749 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -63,7 +63,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, *lhs, Shallow(None), JustWrite); } - StatementKind::FakeRead(_, _) => { + StatementKind::FakeRead(box (_, _)) => { // Only relevant for initialized/liveness/safety checks. } StatementKind::SetDiscriminant { place, variant_index: _ } => { diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 583f73d5775d1..71db6abde4351 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -574,7 +574,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state); } - StatementKind::FakeRead(_, box ref place) => { + StatementKind::FakeRead(box (_, ref place)) => { // Read for match doesn't access any memory and is used to // assert that a place is safe and live. So we don't have to // do any checks here. diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 52b6e9f3753be..538d8921869c3 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -293,8 +293,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } self.gather_rvalue(rval); } - StatementKind::FakeRead(_, place) => { - self.create_move_path(**place); + StatementKind::FakeRead(box (_, place)) => { + self.create_move_path(*place); } StatementKind::LlvmInlineAsm(ref asm) => { for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index e7097ce861902..324d826b375c1 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -683,10 +683,10 @@ pub(super) fn filtered_statement_span( // and `_1` is the `Place` for `somenum`. // // If and when the Issue is resolved, remove this special case match pattern: - StatementKind::FakeRead(cause, _) if cause == FakeReadCause::ForGuardBinding => None, + StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None, // Retain spans from all other statements - StatementKind::FakeRead(_, _) // Not including `ForGuardBinding` + StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` | StatementKind::CopyNonOverlapping(..) | StatementKind::Assign(_) | StatementKind::SetDiscriminant { .. } diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index e562e52f8410f..fd4a783d12a00 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -80,7 +80,7 @@ impl<'tcx> CFG<'tcx> { cause: FakeReadCause, place: Place<'tcx>, ) { - let kind = StatementKind::FakeRead(cause, box place); + let kind = StatementKind::FakeRead(box (cause, place)); let stmt = Statement { source_info, kind }; self.push(block, stmt); } From c29dc120e5e43a4757d8f7f20db35c61767fe987 Mon Sep 17 00:00:00 2001 From: Roxane Date: Tue, 30 Mar 2021 00:30:20 -0400 Subject: [PATCH 18/19] fix clippy error --- src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 1391f7505e27c..dac4d93499dc2 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -212,7 +212,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen check_rvalue(tcx, body, def_id, rval, span) } - StatementKind::FakeRead(_, place) | + StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body), From 95f84c3beb889898576b7e3c25deca630f423c17 Mon Sep 17 00:00:00 2001 From: The8472 Date: Fri, 26 Mar 2021 19:01:55 +0100 Subject: [PATCH 19/19] reduce threads spawned by ui-tests the test harness already spawns enough tests for all cores, individual tests should keep their own threading to a minimum to avoid context switch overhead some tests fail with 1 CGU, so explicit compile flags have been added to keep their old behavior # Conflicts: # src/test/ui/asm/sym.rs --- src/bootstrap/test.rs | 2 ++ src/test/ui/asm/sym.rs | 1 + src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs | 1 + .../linkage-detect-extern-generated-name-collision.rs | 1 + .../linkage-detect-local-generated-name-collision.rs | 2 +- src/tools/compiletest/src/runtest.rs | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 86d940cd733da..03799a302982d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1156,6 +1156,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); if builder.is_fuse_ld_lld(compiler.host) { hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); + hostflags.push("-Clink-arg=-Wl,--threads=1".to_string()); } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); @@ -1163,6 +1164,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); if builder.is_fuse_ld_lld(target) { targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); + targetflags.push("-Clink-arg=-Wl,--threads=1".to_string()); } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs index 634ef010e6fea..05cc9b296515a 100644 --- a/src/test/ui/asm/sym.rs +++ b/src/test/ui/asm/sym.rs @@ -1,4 +1,5 @@ // min-llvm-version: 10.0.1 +// compile-flags: -C codegen-units=2 // only-x86_64 // only-linux // run-pass diff --git a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs index 6e030f1cc4875..e04dec24e445e 100644 --- a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs +++ b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs @@ -1,5 +1,6 @@ // run-fail // compile-flags: -C opt-level=3 +// min-llvm-version: 11.0 // error-pattern: index out of bounds: the len is 0 but the index is 16777216 // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support diff --git a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs index 7b2f5365acaa3..c0aefcc4977ed 100644 --- a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs +++ b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs @@ -4,6 +4,7 @@ // build-fail // aux-build:def_colliding_external.rs +// compile-flags: -Ccodegen-units=16 extern crate def_colliding_external as dep1; diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs index b712f3225ed16..82e10dcddf860 100644 --- a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs +++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs @@ -1,5 +1,5 @@ // build-fail - +// compile-flags: -Ccodegen-units=16 #![feature(linkage)] mod dep1 { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7aa3d4ab09e41..d0f61a8c595ea 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1952,6 +1952,7 @@ impl<'test> TestCx<'test> { if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) { rustc.args(&["--error-format", "json"]); } + rustc.arg("-Ccodegen-units=1"); rustc.arg("-Zui-testing"); rustc.arg("-Zdeduplicate-diagnostics=no"); rustc.arg("-Zemit-future-incompat-report");