From fac272688e9d561b1fff71621323682d23e4c31d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Sep 2020 00:59:41 -0700 Subject: Use ops::ControlFlow in graph::iterate --- compiler/rustc_data_structures/src/graph/iterate/mod.rs | 13 +++++-------- compiler/rustc_data_structures/src/lib.rs | 1 + 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 64ff6130ddf..8946666d961 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -87,11 +87,8 @@ where } /// Allows searches to terminate early with a value. -#[derive(Clone, Copy, Debug)] -pub enum ControlFlow { - Break(T), - Continue, -} +// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`. +pub type ControlFlow = std::ops::ControlFlow<(), T>; /// The status of a node in the depth-first search. /// @@ -260,12 +257,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Behave as if no edges exist from `source` to `target`. @@ -290,7 +287,7 @@ where ) -> ControlFlow { match prior_status { Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue, + _ => ControlFlow::CONTINUE, } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index de4e7a13424..88c160e93b6 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(incomplete_features)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] #![feature(generators)] -- cgit 1.4.1-3-g733a5 From 59e37332b0d2d0c5e43bea1184ec0387fb07cc80 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Sep 2020 16:28:23 -0700 Subject: Add `BREAK` too, and improve the comments --- .../rustc_data_structures/src/graph/iterate/mod.rs | 2 +- library/core/src/iter/traits/iterator.rs | 14 ++++----- library/core/src/ops/control_flow.rs | 36 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 8946666d961..bc3d1ce53ba 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -286,7 +286,7 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), + Some(NodeStatus::Visited) => ControlFlow::BREAK, _ => ControlFlow::CONTINUE, } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 46ef12cd938..ceeae2371e1 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2086,10 +2086,10 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } } - self.try_fold((), check(f)) == ControlFlow::Continue(()) + self.try_fold((), check(f)) == ControlFlow::CONTINUE } /// Tests if any element of the iterator matches a predicate. @@ -2139,11 +2139,11 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } } - self.try_fold((), check(f)) == ControlFlow::Break(()) + self.try_fold((), check(f)) == ControlFlow::BREAK } /// Searches for an element of an iterator that satisfies a predicate. @@ -2201,7 +2201,7 @@ pub trait Iterator { mut predicate: impl FnMut(&T) -> bool, ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -2236,7 +2236,7 @@ pub trait Iterator { ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::Continue(()), + None => ControlFlow::CONTINUE, } } @@ -2278,7 +2278,7 @@ pub trait Iterator { R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => ControlFlow::Continue(()), + Ok(false) => ControlFlow::CONTINUE, Ok(true) => ControlFlow::Break(Ok(x)), Err(x) => ControlFlow::Break(Err(x)), } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 3f0cce4e18a..b0c7dc1a518 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -69,6 +69,42 @@ impl ControlFlow { impl ControlFlow<(), B> { /// It's frequently the case that there's no value needed with `Continue`, /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// let last_used = (1..10).chain(20..25).try_for_each(|x| { + /// partial_sum += x; + /// if partial_sum > 100 { ControlFlow::Break(x) } + /// else { ControlFlow::CONTINUE } + /// }); + /// assert_eq!(last_used.break_value(), Some(22)); + /// ``` #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub const CONTINUE: Self = ControlFlow::Continue(()); } + +impl ControlFlow { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// (1..10).chain(20..25).try_for_each(|x| { + /// if partial_sum > 100 { ControlFlow::BREAK } + /// else { partial_sum += x; ControlFlow::CONTINUE } + /// }); + /// assert_eq!(partial_sum, 108); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const BREAK: Self = ControlFlow::Break(()); +} -- cgit 1.4.1-3-g733a5 From 2799aec6ab4ae35f1a2064f941a9f2a270953b63 Mon Sep 17 00:00:00 2001 From: Flying-Toast <38232168+Flying-Toast@users.noreply.github.com> Date: Tue, 8 Sep 2020 22:37:18 -0400 Subject: Capitalize safety comments --- compiler/rustc_data_structures/src/temp_dir.rs | 2 +- library/alloc/src/alloc.rs | 2 +- library/alloc/src/collections/vec_deque.rs | 2 +- src/test/ui/generator/static-generators.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs index 0d9b3e3ca25..a780d2386a6 100644 --- a/compiler/rustc_data_structures/src/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -12,7 +12,7 @@ pub struct MaybeTempDir { impl Drop for MaybeTempDir { fn drop(&mut self) { - // Safety: We are in the destructor, and no further access will + // SAFETY: We are in the destructor, and no further access will // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 5f09f8def4d..341c6816197 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -157,7 +157,7 @@ impl Global { } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( &mut self, diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index cc2ef25a5a7..172b25b9d17 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -2392,7 +2392,7 @@ impl VecDeque { } } - // Safety: the following two methods require that the rotation amount + // SAFETY: the following two methods require that the rotation amount // be less than half the length of the deque. // // `wrap_copy` requires that `min(x, cap() - x) + copy_len <= cap()`, diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs index 3980766c428..d098bf1e688 100644 --- a/src/test/ui/generator/static-generators.rs +++ b/src/test/ui/generator/static-generators.rs @@ -12,7 +12,7 @@ fn main() { yield; assert_eq!(b as *const _, &a as *const _); }; - // Safety: We shadow the original generator variable so have no safe API to + // SAFETY: We shadow the original generator variable so have no safe API to // move it after this point. let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(())); -- cgit 1.4.1-3-g733a5 From 4fe6ca37898bcd65488764f2679e27c936879ade Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 07:08:34 +0200 Subject: Replace const_generics feature gate with min_const_generics The latter is on the path to stabilization. --- compiler/rustc_data_structures/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b6..b339261189b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,7 +26,7 @@ #![feature(thread_id_value)] #![feature(extend_one)] #![feature(const_panic)] -#![feature(const_generics)] +#![feature(min_const_generics)] #![feature(once_cell)] #![allow(rustc::default_hash_types)] -- cgit 1.4.1-3-g733a5 From ebdea011436dfea810ff1bbd827636ac75f6f092 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 17 Sep 2020 07:46:35 +0200 Subject: Remove redundant #![feature(...)] 's from compiler/ --- compiler/rustc_ast/src/lib.rs | 4 ---- compiler/rustc_codegen_ssa/src/lib.rs | 2 -- compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_expand/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 2 -- compiler/rustc_middle/src/lib.rs | 5 ----- compiler/rustc_mir/src/lib.rs | 3 --- compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_parse_format/src/lib.rs | 2 -- compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_span/src/lib.rs | 2 -- compiler/rustc_traits/src/lib.rs | 1 - compiler/rustc_ty/src/lib.rs | 1 - 13 files changed, 26 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index b556c1a446b..76b84d9da83 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -5,17 +5,13 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(or_patterns)] -#![feature(try_trait)] -#![feature(unicode_internals)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 73e33369175..a87ce1446ba 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -8,8 +8,6 @@ #![feature(or_patterns)] #![feature(trusted_len)] #![feature(associated_type_bounds)] -#![feature(const_fn)] // for rustc_index::newtype_index -#![feature(const_panic)] // for rustc_index::newtype_index #![recursion_limit = "256"] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b339261189b..e5dd7107ff3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,7 +11,6 @@ #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] -#![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] #![feature(min_specialization)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5436b1ef737..47247294f5d 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,5 +1,4 @@ #![feature(bool_to_option)] -#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(or_patterns)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index e05041d8846..504b66bae73 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -13,7 +13,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -23,7 +22,6 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] -#![feature(crate_visibility_modifier)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a675aae5b17..6b411ef8f09 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,12 +30,9 @@ #![feature(cmp_min_max_by)] #![feature(const_fn)] #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] -#![feature(drain_filter)] #![feature(never_type)] -#![feature(exhaustive_patterns)] #![feature(extern_types)] #![feature(nll)] #![feature(once_cell)] @@ -43,13 +40,11 @@ #![feature(or_patterns)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(stmt_expr_attributes)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] -#![feature(hash_raw_entry)] #![feature(int_error_matching)] #![recursion_limit = "512"] diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 42717f27384..fae4a261b3e 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -13,15 +13,12 @@ Rust MIR: a lowered representation of Rust. #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(iter_order_by)] #![feature(never_type)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(try_blocks)] -#![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 0becdf24c53..72a34b86ae2 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,7 +3,6 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(try_blocks)] #![feature(or_patterns)] use rustc_ast as ast; diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e07b8b86aef..dde162681b7 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -11,8 +11,6 @@ )] #![feature(nll)] #![feature(or_patterns)] -#![feature(rustc_private)] -#![feature(unicode_internals)] #![feature(bool_to_option)] pub use Alignment::*; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 03cc718b899..d451a383b12 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] use rustc_attr as attr; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e38cd516b91..1d1013967b7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -10,10 +10,8 @@ #![feature(const_panic)] #![feature(negative_impls)] #![feature(nll)] -#![feature(optin_builtin_traits)] #![feature(min_specialization)] #![feature(option_expect_none)] -#![feature(refcell_take)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 6fea4732dda..d0b05beb4e6 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,7 +4,6 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 6e9042d1ba7..8dd6aa3c7fc 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -5,7 +5,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bool_to_option)] #![feature(nll)] #![recursion_limit = "256"] -- cgit 1.4.1-3-g733a5 From 1e2dba1e7cf15442257f2cd3ddfe5d0462ee9102 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Sep 2020 21:39:13 +0200 Subject: Use `T::BITS` instead of `size_of:: * 8`. --- compiler/rustc_data_structures/src/lib.rs | 1 + .../rustc_data_structures/src/tagged_ptr/copy.rs | 2 +- library/alloc/src/collections/binary_heap.rs | 4 +-- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 2 +- library/alloc/tests/lib.rs | 1 + library/alloc/tests/string.rs | 5 ++-- library/alloc/tests/vec.rs | 2 +- library/core/src/fmt/mod.rs | 2 +- library/core/src/num/bignum.rs | 34 ++++++---------------- library/core/src/slice/sort.rs | 6 ++-- library/core/tests/iter.rs | 2 +- library/core/tests/lib.rs | 1 + library/core/tests/num/int_macros.rs | 20 +++++-------- library/core/tests/num/uint_macros.rs | 20 +++++-------- library/panic_unwind/src/dwarf/mod.rs | 4 +-- library/panic_unwind/src/lib.rs | 1 + 17 files changed, 44 insertions(+), 64 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b6..06718cc9803 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -14,6 +14,7 @@ #![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] +#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(optin_builtin_traits)] #![feature(nll)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index d39d146db31..d63bcdb3c2b 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -48,7 +48,7 @@ where P: Pointer, T: Tag, { - const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::()) - T::BITS; + const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS; const ASSERTION: () = { assert!(T::BITS <= P::BITS); // Used for the transmute_copy's below diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 24d17fdd880..8a7dd9d4249 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -146,7 +146,7 @@ use core::fmt; use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; -use core::mem::{self, size_of, swap, ManuallyDrop}; +use core::mem::{self, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; @@ -617,7 +617,7 @@ impl BinaryHeap { #[inline(always)] fn log2_fast(x: usize) -> usize { - 8 * size_of::() - (x.leading_zeros() as usize) - 1 + (usize::BITS - x.leading_zeros() - 1) as usize } // `rebuild` takes O(len1 + len2) operations diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7881c101f9f..f3c1eee47c7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,6 +101,7 @@ #![feature(fn_traits)] #![feature(fundamental)] #![feature(inplace_iteration)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(libc)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 05382d0b559..62675665f03 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -528,7 +528,7 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if mem::size_of::() < 8 && alloc_size > isize::MAX as usize { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { Err(CapacityOverflow) } else { Ok(()) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 03737e1ef1f..3ee0cfbe747 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -18,6 +18,7 @@ #![feature(deque_range)] #![feature(inplace_iteration)] #![feature(iter_map_while)] +#![feature(int_bits_const)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 4e604354122..a6e41b21b61 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; -use std::mem::size_of; use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> @@ -605,7 +604,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -686,7 +685,7 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { let mut empty_string: String = String::new(); diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 368ca4c5432..a49ca7c256a 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1341,7 +1341,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 48b7f2739ee..8558cb5a5e8 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2086,7 +2086,7 @@ impl Pointer for *const T { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); if f.width.is_none() { - f.width = Some(((mem::size_of::() * 8) / 4) + 2); + f.width = Some((usize::BITS / 4) as usize + 2); } } f.flags |= 1 << (FlagV1::Alternate as u32); diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 6f16b93d048..6a1a1e19761 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -20,7 +20,6 @@ #![macro_use] use crate::intrinsics; -use crate::mem; /// Arithmetic operations required by bignums. pub trait FullOps: Sized { @@ -58,25 +57,22 @@ macro_rules! impl_full_ops { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. // FIXME: will LLVM optimize this into ADC or similar? - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { debug_assert!(borrow < other); // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; - let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); + let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty); let rhs = other as $bigty; ((lhs / rhs) as $ty, (lhs % rhs) as $ty) } @@ -128,13 +124,11 @@ macro_rules! define_bignum { /// Makes a bignum from `u64` value. pub fn from_u64(mut v: u64) -> $name { - use crate::mem; - let mut base = [0; $n]; let mut sz = 0; while v > 0 { base[sz] = v as $ty; - v >>= mem::size_of::<$ty>() * 8; + v >>= <$ty>::BITS; sz += 1; } $name { size: sz, base: base } @@ -150,9 +144,7 @@ macro_rules! define_bignum { /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let d = i / digitbits; let b = i % digitbits; ((self.base[d] >> b) & 1) as u8 @@ -166,8 +158,6 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - use crate::mem; - // Skip over the most significant digits which are zero. let digits = self.digits(); let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); @@ -180,7 +170,7 @@ macro_rules! define_bignum { } // This could be optimized with leading_zeros() and bit shifts, but that's // probably not worth the hassle. - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let mut i = nonzero.len() * digitbits - 1; while self.get_bit(i) == 0 { i -= 1; @@ -265,9 +255,7 @@ macro_rules! define_bignum { /// Multiplies itself by `2^bits` and returns its own mutable reference. pub fn mul_pow2(&mut self, bits: usize) -> &mut $name { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let digits = bits / digitbits; let bits = bits % digitbits; @@ -393,13 +381,11 @@ macro_rules! define_bignum { /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the /// remainder. pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - use crate::mem; - // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm // FIXME use a greater base ($ty) for the long division. assert!(!d.is_zero()); - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; for digit in &mut q.base[..] { *digit = 0; } @@ -462,10 +448,8 @@ macro_rules! define_bignum { impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - use crate::mem; - let sz = if self.size < 1 { 1 } else { self.size }; - let digitlen = mem::size_of::<$ty>() * 2; + let digitlen = <$ty>::BITS as usize / 4; write!(f, "{:#x}", self.base[sz - 1])?; for &v in self.base[..sz - 1].iter().rev() { diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8c14651bd82..71d2c2c9b2f 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -565,7 +565,7 @@ fn break_patterns(v: &mut [T]) { random }; let mut gen_usize = || { - if mem::size_of::() <= 4 { + if usize::BITS <= 32 { gen_u32() as usize } else { (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize @@ -667,7 +667,7 @@ where /// /// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, /// this function will immediately switch to heapsort. -fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize) +fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32) where F: FnMut(&T, &T) -> bool, { @@ -763,7 +763,7 @@ where } // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. - let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize; + let limit = usize::BITS - v.len().leading_zeros(); recurse(v, &mut is_less, None, limit); } diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 00e3972c42f..0eb9af3f454 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -474,7 +474,7 @@ fn test_iterator_step_by_nth_overflow() { } let mut it = Test(0); - let root = usize::MAX >> (::std::mem::size_of::() * 8 / 2); + let root = usize::MAX >> (usize::BITS / 2); let n = root + 20; (&mut it).step_by(n).nth(n); assert_eq!(it.0, n as Bigger * n as Bigger); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a5b1b51e06c..4db391f3e56 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -52,6 +52,7 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(int_bits_const)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 58a58566912..27e6760e7cb 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -2,7 +2,6 @@ macro_rules! int_module { ($T:ident, $T_i:ident) => { #[cfg(test)] mod tests { - use core::mem; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; @@ -82,30 +81,27 @@ macro_rules! int_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert_eq!(A.count_zeros(), bits as u32 - 3); - assert_eq!(B.count_zeros(), bits as u32 - 2); - assert_eq!(C.count_zeros(), bits as u32 - 5); + assert_eq!(A.count_zeros(), $T::BITS - 3); + assert_eq!(B.count_zeros(), $T::BITS - 2); + assert_eq!(C.count_zeros(), $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!(MAX.trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!(MAX.trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index b84a8a7d9f8..952ec188dc1 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -4,7 +4,6 @@ macro_rules! uint_module { mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; - use std::mem; use std::str::FromStr; use crate::num; @@ -47,30 +46,27 @@ macro_rules! uint_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert!(A.count_zeros() == bits as u32 - 3); - assert!(B.count_zeros() == bits as u32 - 2); - assert!(C.count_zeros() == bits as u32 - 5); + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!((_1 >> 1).leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!((_1 >> 1).trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/panic_unwind/src/dwarf/mod.rs b/library/panic_unwind/src/dwarf/mod.rs index 649bbce52a3..652fbe95a14 100644 --- a/library/panic_unwind/src/dwarf/mod.rs +++ b/library/panic_unwind/src/dwarf/mod.rs @@ -53,7 +53,7 @@ impl DwarfReader { } pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: usize = 0; + let mut shift: u32 = 0; let mut result: u64 = 0; let mut byte: u8; loop { @@ -65,7 +65,7 @@ impl DwarfReader { } } // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { + if shift < u64::BITS && (byte & 0x40) != 0 { result |= (!0 as u64) << shift; } result as i64 diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 6f31e6dcae7..162f0386b66 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,6 +18,7 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(libc)] #![feature(nll)] -- cgit 1.4.1-3-g733a5 From 1146c39da74b3875e6667aeeafde2773644dc8b6 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 19 Sep 2020 17:27:13 +0200 Subject: cache types during normalization --- Cargo.lock | 1 + compiler/rustc_data_structures/Cargo.toml | 1 + compiler/rustc_data_structures/src/lib.rs | 12 +++-- compiler/rustc_data_structures/src/mini_map.rs | 61 ++++++++++++++++++++++ compiler/rustc_index/Cargo.toml | 2 +- compiler/rustc_infer/src/infer/combine.rs | 61 +--------------------- .../src/traits/query/normalize.rs | 13 ++++- 7 files changed, 83 insertions(+), 68 deletions(-) create mode 100644 compiler/rustc_data_structures/src/mini_map.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/Cargo.lock b/Cargo.lock index c9f75aa1d43..825ded3eeee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3435,6 +3435,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ + "arrayvec", "bitflags", "cfg-if", "crossbeam-utils 0.7.2", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 3dc55cab95a..7a6f4b82b52 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" doctest = false [dependencies] +arrayvec = { version = "0.5.1", default-features = false } ena = "0.14" indexmap = "1.5.1" tracing = "0.1" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 88c160e93b6..7d4aed14be1 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -87,25 +87,27 @@ pub mod sorted_map; pub mod stable_set; #[macro_use] pub mod stable_hasher; +mod atomic_ref; +pub mod fingerprint; +pub mod profiling; pub mod sharded; pub mod stack; pub mod sync; pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; -pub use ena::undo_log; -pub use ena::unify; -mod atomic_ref; -pub mod fingerprint; -pub mod profiling; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; +pub mod mini_map; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; +pub use ena::undo_log; +pub use ena::unify; + pub struct OnDrop(pub F); impl OnDrop { diff --git a/compiler/rustc_data_structures/src/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs new file mode 100644 index 00000000000..cd3e949d383 --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_map.rs @@ -0,0 +1,61 @@ +use crate::fx::FxHashMap; +use arrayvec::ArrayVec; + +use std::hash::Hash; + +/// Small-storage-optimized implementation of a map +/// made specifically for caching results. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashMap` when that length is exceeded. +pub enum MiniMap { + Array(ArrayVec<[(K, V); 8]>), + Map(FxHashMap), +} + +impl MiniMap { + /// Creates an empty `MiniMap`. + pub fn new() -> Self { + MiniMap::Array(ArrayVec::new()) + } + + /// Inserts or updates value in the map. + pub fn insert(&mut self, key: K, value: V) { + match self { + MiniMap::Array(array) => { + for pair in array.iter_mut() { + if pair.0 == key { + pair.1 = value; + return; + } + } + if let Err(error) = array.try_push((key, value)) { + let mut map: FxHashMap = array.drain(..).collect(); + let (key, value) = error.element(); + map.insert(key, value); + *self = MiniMap::Map(map); + } + } + MiniMap::Map(map) => { + map.insert(key, value); + } + } + } + + /// Return value by key if any. + pub fn get(&self, key: &K) -> Option<&V> { + match self { + MiniMap::Array(array) => { + for pair in array { + if pair.0 == *key { + return Some(&pair.1); + } + } + return None; + } + MiniMap::Map(map) => { + return map.get(key); + } + } + } +} diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 6ac7c06ee83..6e1471df195 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -8,6 +8,6 @@ edition = "2018" doctest = false [dependencies] -arrayvec = "0.5.1" +arrayvec = { version = "0.5.1", default-features = false } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5bd6c667fd7..982973878c6 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -31,13 +31,11 @@ use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use super::{InferCtxt, MiscVariable, TypeTrace}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashMap; -use std::hash::Hash; use crate::traits::{Obligation, PredicateObligations}; use rustc_ast as ast; +use rustc_data_structures::mini_map::MiniMap; use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; @@ -47,63 +45,6 @@ use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::DUMMY_SP; -/// Small-storage-optimized implementation of a map -/// made specifically for caching results. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashMap` when that length is exceeded. -enum MiniMap { - Array(ArrayVec<[(K, V); 8]>), - Map(FxHashMap), -} - -impl MiniMap { - /// Creates an empty `MiniMap`. - pub fn new() -> Self { - MiniMap::Array(ArrayVec::new()) - } - - /// Inserts or updates value in the map. - pub fn insert(&mut self, key: K, value: V) { - match self { - MiniMap::Array(array) => { - for pair in array.iter_mut() { - if pair.0 == key { - pair.1 = value; - return; - } - } - if let Err(error) = array.try_push((key, value)) { - let mut map: FxHashMap = array.drain(..).collect(); - let (key, value) = error.element(); - map.insert(key, value); - *self = MiniMap::Map(map); - } - } - MiniMap::Map(map) => { - map.insert(key, value); - } - } - } - - /// Return value by key if any. - pub fn get(&self, key: &K) -> Option<&V> { - match self { - MiniMap::Array(array) => { - for pair in array { - if pair.0 == *key { - return Some(&pair.1); - } - } - return None; - } - MiniMap::Map(map) => { - return map.get(key); - } - } - } -} - #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'infcx, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 323063b9584..3dcebbcc244 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc_data_structures::mini_map::MiniMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -57,6 +58,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { param_env: self.param_env, obligations: vec![], error: false, + cache: MiniMap::new(), anon_depth: 0, }; @@ -85,6 +87,7 @@ struct QueryNormalizer<'cx, 'tcx> { cause: &'cx ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec>, + cache: MiniMap, Ty<'tcx>>, error: bool, anon_depth: usize, } @@ -99,8 +102,12 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { return ty; } + if let Some(ty) = self.cache.get(&ty) { + return ty; + } + let ty = ty.super_fold_with(self); - match *ty.kind() { + let res = (|| match *ty.kind() { ty::Opaque(def_id, substs) => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { @@ -197,7 +204,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } _ => ty, - } + })(); + self.cache.insert(ty, res); + res } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { -- cgit 1.4.1-3-g733a5 From 3435683fd5930676b5a7ccd40dc08e4758e8b90a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 17 Sep 2020 09:28:14 +0200 Subject: use `array_windows` instead of `windows` in the compiler --- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/sorted_map.rs | 4 ++-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/nonstandard_style.rs | 4 ++-- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_mir/src/lib.rs | 1 + compiler/rustc_mir/src/monomorphize/partitioning/mod.rs | 8 +------- compiler/rustc_mir_build/src/lib.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/_match.rs | 4 ++-- compiler/rustc_span/src/lib.rs | 10 ++++++++-- 11 files changed, 21 insertions(+), 17 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 06718cc9803..3322edd18cc 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(incomplete_features)] +#![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 856eb73e629..4807380595d 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -34,7 +34,7 @@ impl SortedMap { /// and that there are no duplicates. #[inline] pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); SortedMap { data: elements } } @@ -159,7 +159,7 @@ impl SortedMap { return; } - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); let start_index = self.lookup_index_for(&elements[0].0); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a14b16e274..b48592c103c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -27,6 +27,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(test, feature(test))] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 24467f81172..b3125f55d4d 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -70,9 +70,9 @@ fn is_camel_case(name: &str) -> bool { // ones (some scripts don't have a concept of upper/lowercase) !name.chars().next().unwrap().is_lowercase() && !name.contains("__") - && !name.chars().collect::>().windows(2).any(|pair| { + && !name.chars().collect::>().array_windows().any(|&[fst, snd]| { // contains a capitalisable character followed by, or preceded by, an underscore - char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_' + char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_' }) } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a675aae5b17..ac931028c01 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -23,6 +23,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] #![feature(box_patterns)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f..38c0441990b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2419,7 +2419,7 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[ExistentialPredicate<'tcx>], ) -> &'tcx List> { assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); + assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); self._intern_existential_predicates(eps) } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 251037792c9..52b0a7e7067 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -6,6 +6,7 @@ Rust MIR: a lowered representation of Rust. #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(array_windows)] #![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index b60beca6880..db6d3b2d912 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -277,14 +277,8 @@ where symbols.sort_by_key(|sym| sym.1); - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - let span1 = mono_item1.local_span(tcx); let span2 = mono_item2.local_span(tcx); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index e55180ff4be..714041ad4e8 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,7 +1,7 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. - +#![feature(array_windows)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index ad94740c160..e71e1abd680 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -2299,8 +2299,8 @@ fn split_grouped_constructors<'p, 'tcx>( // interval into a constructor. split_ctors.extend( borders - .windows(2) - .filter_map(|window| match (window[0], window[1]) { + .array_windows() + .filter_map(|&[fst, snd]| match (fst, snd) { (Border::JustBefore(n), Border::JustBefore(m)) => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e38cd516b91..e817fa56c55 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -5,6 +5,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] #![feature(const_panic)] @@ -1158,7 +1159,12 @@ impl Encodable for SourceFile { let max_line_length = if lines.len() == 1 { 0 } else { - lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap() + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() }; let bytes_per_diff: u8 = match max_line_length { @@ -1173,7 +1179,7 @@ impl Encodable for SourceFile { // Encode the first element. lines[0].encode(s)?; - let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0])); + let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst); match bytes_per_diff { 1 => { -- cgit 1.4.1-3-g733a5 From 43193dcb882466163436057e50c96bb74d9bf50f Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 10:27:14 +0200 Subject: Use as_secs_f64 in profiling.rs --- compiler/rustc_data_structures/src/profiling.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 07d16c6483e..363879cbb1d 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -600,10 +600,7 @@ pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { // Hack up our own formatting for the duration to make it easier for scripts // to parse (always use the same number of decimal places and the same unit). pub fn duration_to_secs_str(dur: std::time::Duration) -> String { - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - - format!("{:.3}", secs) + format!("{:.3}", dur.as_secs_f64()) } // Memory reporting -- cgit 1.4.1-3-g733a5 From c2dad1c6b9f9636198d7c561b47a2974f5103f6d Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 20 Sep 2020 11:40:51 +0200 Subject: Remove unused static_assert macro --- compiler/rustc_data_structures/src/macros.rs | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/macros.rs b/compiler/rustc_data_structures/src/macros.rs index 67fbe3058cd..b918ed9458c 100644 --- a/compiler/rustc_data_structures/src/macros.rs +++ b/compiler/rustc_data_structures/src/macros.rs @@ -1,15 +1,3 @@ -/// A simple static assertion macro. -#[macro_export] -#[allow_internal_unstable(type_ascription)] -macro_rules! static_assert { - ($test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - const _: () = [()][!($test: bool) as usize]; - }; -} - /// Type size assertion. The first argument is a type and the second argument is its expected size. #[macro_export] macro_rules! static_assert_size { -- cgit 1.4.1-3-g733a5 From 6586c37beca21869f698ef2de10d1df7be7e7879 Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Wed, 23 Sep 2020 08:09:16 +0200 Subject: Move MiniSet to data_structures remove the need for T to be copy from MiniSet as was done for MiniMap --- Cargo.lock | 2 -- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/mini_set.rs | 41 +++++++++++++++++++++ compiler/rustc_infer/Cargo.toml | 1 - compiler/rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_middle/Cargo.toml | 1 - compiler/rustc_middle/src/ty/outlives.rs | 2 +- compiler/rustc_middle/src/ty/print/mod.rs | 2 +- compiler/rustc_middle/src/ty/walk.rs | 44 +---------------------- 9 files changed, 46 insertions(+), 50 deletions(-) create mode 100644 compiler/rustc_data_structures/src/mini_set.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/Cargo.lock b/Cargo.lock index 68288916e6d..26a9e64b85a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3638,7 +3638,6 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "arrayvec", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3778,7 +3777,6 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "arrayvec", "bitflags", "chalk-ir", "measureme", diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 1f977805f5e..5990e94ab7e 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -102,6 +102,7 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod mini_map; +pub mod mini_set; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs new file mode 100644 index 00000000000..9d45af723de --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_set.rs @@ -0,0 +1,41 @@ +use crate::fx::FxHashSet; +use arrayvec::ArrayVec; +use std::hash::Hash; +/// Small-storage-optimized implementation of a set. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum MiniSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl MiniSet { + /// Creates an empty `MiniSet`. + pub fn new() -> Self { + MiniSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + MiniSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if let Err(error) = array.try_push(elem) { + let mut set: FxHashSet = array.drain(..).collect(); + set.insert(error.element()); + *self = MiniSet::Set(set); + } + true + } + } + MiniSet::Set(set) => set.insert(elem), + } + } +} diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index a8c1a370cef..5dba4106c94 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -21,5 +21,4 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index e06bfb59580..21b0836563f 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,9 +1,9 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::walk::MiniSet; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 1d84ddad7f5..a5a860a38b3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,6 +28,5 @@ rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } chalk-ir = "0.21.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } measureme = "0.7.1" rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 01649f44c88..ca992d36e95 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -3,8 +3,8 @@ // RFC for reference. use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::walk::MiniSet; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::mini_set::MiniSet; use smallvec::SmallVec; #[derive(Debug)] diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index f315292dab5..225ea2399fb 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,9 +2,9 @@ use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ty::walk::MiniSet; // `pretty` is a separate module only for organization. mod pretty; diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 7afa6e6cc05..80ade7dda4c 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,50 +3,8 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use smallvec::{self, SmallVec}; -use std::hash::Hash; - -/// Small-storage-optimized implementation of a set -/// made specifically for walking type tree. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -pub enum MiniSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), -} - -impl MiniSet { - /// Creates an empty `MiniSet`. - pub fn new() -> Self { - MiniSet::Array(ArrayVec::new()) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, true is returned. - /// - /// If the set did have this value present, false is returned. - pub fn insert(&mut self, elem: T) -> bool { - match self { - MiniSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if array.try_push(elem).is_err() { - let mut set: FxHashSet = array.iter().copied().collect(); - set.insert(elem); - *self = MiniSet::Set(set); - } - true - } - } - MiniSet::Set(set) => set.insert(elem), - } - } -} // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. -- cgit 1.4.1-3-g733a5 From dd66ea2d3d78727eb3d3574f4f6fbe82085d9ee2 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Wed, 23 Sep 2020 21:14:43 +0200 Subject: Updated html_root_url for compiler crates --- compiler/rustc_apfloat/src/lib.rs | 2 +- compiler/rustc_arena/src/lib.rs | 2 +- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_incremental/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_plugin_impl/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty/src/lib.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index ba3adc4a135..7c96be4f479 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6f9cccf58dd..86a0fb64f2c 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,7 +8,7 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 480a5d2f18e..2072462baa0 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_fn_transmute)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 87be6d1743a..6bffad36615 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 2e2abe9fb30..64c58775f49 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a87ce1446ba..16babec6255 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 1f977805f5e..e037169b252 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,7 +6,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 972e04fd101..5316fedee10 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b16fe5603c1..b221219bedd 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,7 +2,7 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(nll)] diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 58db81bc1dc..4bd334e15e1 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -272,7 +272,7 @@ //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![feature(nll)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index ad189138054..bcd700e5ac1 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 504b66bae73..99bec24b868 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,7 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b48592c103c..c4832aa85e4 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,7 +25,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 9d23397ade0..dfcb6d04b6f 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 85490f5f6e9..4011521d237 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 74cb3c130b7..86ceaca9b04 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index cef632b1d8f..a0d64107c91 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,7 +5,7 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index be4c542ec3a..08e152cf5ee 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index 1eb65dd96ba..efa2f6e96f9 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c2de4cdbf0d..0b45d779260 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 677cf27cde7..a34572e7f36 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 032d7cb3ed6..af001594b20 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 265b3b95e95..fa6f5ab3db6 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 4b02a2d4076..20b2eff8555 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 296b40c4e39..c15cb4bf6c5 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 5788e1e8385..eacc1d0c23d 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index da1996b92a6..b9e300a3ec1 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,7 +10,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(drain_filter)] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 8dd6aa3c7fc..9f6a310033b 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 0e9f4476c20..7ee62c77dbf 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,7 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] #![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] -- cgit 1.4.1-3-g733a5 From 138a2e5eaaafeee8b981045857f9df18ef4689d5 Mon Sep 17 00:00:00 2001 From: Erik Hofmayer Date: Wed, 23 Sep 2020 21:51:56 +0200 Subject: /nightly/nightly-rustc --- compiler/rustc_apfloat/src/lib.rs | 2 +- compiler/rustc_arena/src/lib.rs | 2 +- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_incremental/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_plugin_impl/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty/src/lib.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index 7c96be4f479..4a845fcb691 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 86a0fb64f2c..152f0f1ab2a 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,7 +8,7 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 2072462baa0..765a21fd93e 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/", test(attr(deny(warnings))))] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` #![feature(const_fn_transmute)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6bffad36615..97cadb913ca 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 64c58775f49..456e9c7ce75 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 16babec6255..8568bd64f4c 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index e037169b252..b0b7f9058f9 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,7 +6,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 5316fedee10..7118437c0c8 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b221219bedd..2e8a4ef327a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,7 +2,7 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(nll)] diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 4bd334e15e1..76e33bed97f 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -272,7 +272,7 @@ //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![feature(nll)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index bcd700e5ac1..a80c4be3e93 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 99bec24b868..ea9a4661348 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,7 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c4832aa85e4..7f7472d9283 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,7 +25,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index dfcb6d04b6f..a7a10b91b4e 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 4011521d237..77766be7397 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 86ceaca9b04..fa885ce2e7c 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a0d64107c91..25e3e67e28e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,7 +5,7 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 08e152cf5ee..c14d6aace87 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index efa2f6e96f9..5bf4d300e9e 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 0b45d779260..8d1b826ea35 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a34572e7f36..283db1404d0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index af001594b20..f6434689fec 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index fa6f5ab3db6..ed48fbf40ac 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly-rustc/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 20b2eff8555..96a6956a40c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c15cb4bf6c5..75150a56c43 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index eacc1d0c23d..fb747dfcbd3 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index b9e300a3ec1..caf0325084c 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,7 +10,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(drain_filter)] diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty/src/lib.rs index 9f6a310033b..904c0062a92 100644 --- a/compiler/rustc_ty/src/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 7ee62c77dbf..84efb92582e 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,7 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly-rustc/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] -- cgit 1.4.1-3-g733a5 From 12187b7f860e8e823eb5e399946746c4d2c1b1a7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 26 Sep 2020 01:17:54 +0200 Subject: Remove unused #[allow(...)] statements from compiler/ --- compiler/rustc_arena/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/builder.rs | 1 - compiler/rustc_codegen_llvm/src/common.rs | 2 -- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 1 - compiler/rustc_codegen_llvm/src/va_arg.rs | 1 - compiler/rustc_codegen_ssa/src/common.rs | 4 +--- compiler/rustc_data_structures/src/lib.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 3 --- compiler/rustc_infer/src/infer/mod.rs | 1 - compiler/rustc_lint/src/types.rs | 2 -- compiler/rustc_llvm/src/lib.rs | 1 - compiler/rustc_macros/src/query.rs | 1 - compiler/rustc_macros/src/symbols.rs | 1 - compiler/rustc_middle/src/util/common.rs | 2 -- compiler/rustc_mir/src/borrow_check/prefixes.rs | 1 - compiler/rustc_mir/src/dataflow/move_paths/mod.rs | 1 - compiler/rustc_session/src/filesearch.rs | 2 -- compiler/rustc_trait_selection/src/traits/auto_trait.rs | 1 + compiler/rustc_trait_selection/src/traits/mod.rs | 1 - compiler/rustc_trait_selection/src/traits/select/mod.rs | 1 - compiler/rustc_typeck/src/lib.rs | 1 - 21 files changed, 2 insertions(+), 28 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index b4bf31b1aba..166f7f53c41 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -15,7 +15,6 @@ #![feature(new_uninit)] #![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -#![allow(deprecated)] use rustc_data_structures::cold_path; use smallvec::SmallVec; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 23a3be1a2f2..67191ac0e46 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -931,7 +931,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED) } } - #[allow(dead_code)] fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 0b1cf03fa7e..0992410a728 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types, non_snake_case)] - //! Code that is useful in various codegen modules. use crate::consts::{self, const_alloc_to_llvm}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 868eb74cf09..987149cb4c2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1845,7 +1845,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> { None } - #[allow(dead_code)] fn is_artificial(&self) -> bool { match self { VariantInfo::Generator { .. } => true, diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 54efa05aee8..22ed4dd7576 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; -#[allow(dead_code)] fn round_pointer_up_to_alignment( bx: &mut Builder<'a, 'll, 'tcx>, addr: &'ll Value, diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index e04ed531bbf..780b1d2cd94 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types, non_snake_case)] +#![allow(non_camel_case_types)] use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -25,7 +25,6 @@ pub enum IntPredicate { IntSLE, } -#[allow(dead_code)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -60,7 +59,6 @@ pub enum AtomicRmwBinOp { } pub enum AtomicOrdering { - #[allow(dead_code)] NotAtomic, Unordered, Monotonic, diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 9ded10e9c26..90b0f254751 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -7,7 +7,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![allow(incomplete_features)] #![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 76cf6bd4776..820d664c07d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -256,7 +256,6 @@ pub trait Visitor<'v>: Sized { /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only /// reason to override this method is if you want a nested pattern /// but cannot supply a `Map`; see `nested_visit_map` for advice. - #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id)); walk_list!(self, visit_item, opt_item); @@ -265,7 +264,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_trait_item(&mut self, id: TraitItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id)); walk_list!(self, visit_trait_item, opt_item); @@ -274,7 +272,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for impl items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id)); walk_list!(self, visit_impl_item, opt_item); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2cbdc954e20..95137410c62 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1275,7 +1275,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gives temporary access to the region constraint data. - #[allow(non_camel_case_types)] // bug with impl trait pub fn with_region_constraints( &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 6aa28d04ae1..9925444b869 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] - use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index a7a10b91b4e..a381290d46f 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -21,7 +21,6 @@ impl RustString { /// Appending to a Rust string -- used by RawRustStringOstream. #[no_mangle] -#[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn LLVMRustStringWriteImpl( sr: &RustString, ptr: *const c_char, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 204e8e800cd..e7c054653ac 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -9,7 +9,6 @@ use syn::{ ReturnType, Token, Type, }; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(query); } diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 352665f0ab1..94d4ad78e8d 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(Keywords); syn::custom_keyword!(Symbols); diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index 1e09702bf27..da857b0a403 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - use rustc_data_structures::sync::Lock; use std::fmt::Debug; diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs index 5bfe02ff3b0..6c5d42296f7 100644 --- a/compiler/rustc_mir/src/borrow_check/prefixes.rs +++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs @@ -33,7 +33,6 @@ pub(super) struct Prefixes<'cx, 'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[allow(dead_code)] pub(super) enum PrefixSet { /// Doesn't stop until it returns the base case (a Local or /// Static prefix). diff --git a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs index d66d2625d78..7c630259186 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs @@ -144,7 +144,6 @@ impl<'tcx> fmt::Display for MovePath<'tcx> { } } -#[allow(unused)] struct MovePathLinearIter<'a, 'tcx, F> { next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, fetch_next: F, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 284fca652ec..12a268d5b1d 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - pub use self::FileMatch::*; use std::borrow::Cow; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 35bfeff10b4..e40067202e1 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -32,6 +32,7 @@ pub enum AutoTraitResult { NegativeImpl, } +#[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { match *self { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 79495ba7f9b..c93087a18cf 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -2,7 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -#[allow(dead_code)] pub mod auto_trait; mod chalk_fulfill; pub mod codegen; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5e2f7d81d00..57f1fedacbe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2148,7 +2148,6 @@ trait TraitObligationExt<'tcx> { } impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { - #[allow(unused_comparisons)] fn derived_cause( &self, variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 84efb92582e..e8fa2b13a9f 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -56,7 +56,6 @@ This API is completely unstable and subject to change. */ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![allow(non_camel_case_types)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -- cgit 1.4.1-3-g733a5 From 5c224a484dc6ba2a70c9cd0d73a04849f6d7aa68 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Wed, 23 Sep 2020 23:32:11 -0500 Subject: MiniSet/MiniMap moved and renamed into SsoHashSet/SsoHashMap It is a more descriptive name and with upcoming changes there will be nothing "mini" about them. --- compiler/rustc_data_structures/src/lib.rs | 3 +- compiler/rustc_data_structures/src/mini_map.rs | 61 ---------------------- compiler/rustc_data_structures/src/mini_set.rs | 41 --------------- compiler/rustc_data_structures/src/sso/map.rs | 61 ++++++++++++++++++++++ compiler/rustc_data_structures/src/sso/mod.rs | 5 ++ compiler/rustc_data_structures/src/sso/set.rs | 41 +++++++++++++++ compiler/rustc_infer/src/infer/combine.rs | 6 +-- compiler/rustc_infer/src/infer/outlives/verify.rs | 10 ++-- compiler/rustc_middle/src/ty/outlives.rs | 10 ++-- compiler/rustc_middle/src/ty/print/mod.rs | 6 +-- compiler/rustc_middle/src/ty/walk.rs | 8 +-- .../src/traits/query/normalize.rs | 6 +-- 12 files changed, 131 insertions(+), 127 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/mini_map.rs delete mode 100644 compiler/rustc_data_structures/src/mini_set.rs create mode 100644 compiler/rustc_data_structures/src/sso/map.rs create mode 100644 compiler/rustc_data_structures/src/sso/mod.rs create mode 100644 compiler/rustc_data_structures/src/sso/set.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 9ded10e9c26..d0f2a4148d3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -101,8 +101,7 @@ pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; -pub mod mini_map; -pub mod mini_set; +pub mod sso; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; diff --git a/compiler/rustc_data_structures/src/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs deleted file mode 100644 index cd3e949d383..00000000000 --- a/compiler/rustc_data_structures/src/mini_map.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::fx::FxHashMap; -use arrayvec::ArrayVec; - -use std::hash::Hash; - -/// Small-storage-optimized implementation of a map -/// made specifically for caching results. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashMap` when that length is exceeded. -pub enum MiniMap { - Array(ArrayVec<[(K, V); 8]>), - Map(FxHashMap), -} - -impl MiniMap { - /// Creates an empty `MiniMap`. - pub fn new() -> Self { - MiniMap::Array(ArrayVec::new()) - } - - /// Inserts or updates value in the map. - pub fn insert(&mut self, key: K, value: V) { - match self { - MiniMap::Array(array) => { - for pair in array.iter_mut() { - if pair.0 == key { - pair.1 = value; - return; - } - } - if let Err(error) = array.try_push((key, value)) { - let mut map: FxHashMap = array.drain(..).collect(); - let (key, value) = error.element(); - map.insert(key, value); - *self = MiniMap::Map(map); - } - } - MiniMap::Map(map) => { - map.insert(key, value); - } - } - } - - /// Return value by key if any. - pub fn get(&self, key: &K) -> Option<&V> { - match self { - MiniMap::Array(array) => { - for pair in array { - if pair.0 == *key { - return Some(&pair.1); - } - } - return None; - } - MiniMap::Map(map) => { - return map.get(key); - } - } - } -} diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs deleted file mode 100644 index 9d45af723de..00000000000 --- a/compiler/rustc_data_structures/src/mini_set.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::fx::FxHashSet; -use arrayvec::ArrayVec; -use std::hash::Hash; -/// Small-storage-optimized implementation of a set. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -pub enum MiniSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), -} - -impl MiniSet { - /// Creates an empty `MiniSet`. - pub fn new() -> Self { - MiniSet::Array(ArrayVec::new()) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, true is returned. - /// - /// If the set did have this value present, false is returned. - pub fn insert(&mut self, elem: T) -> bool { - match self { - MiniSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if let Err(error) = array.try_push(elem) { - let mut set: FxHashSet = array.drain(..).collect(); - set.insert(error.element()); - *self = MiniSet::Set(set); - } - true - } - } - MiniSet::Set(set) => set.insert(elem), - } - } -} diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs new file mode 100644 index 00000000000..c253e9d6616 --- /dev/null +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -0,0 +1,61 @@ +use crate::fx::FxHashMap; +use arrayvec::ArrayVec; + +use std::hash::Hash; + +/// Small-storage-optimized implementation of a map +/// made specifically for caching results. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashMap` when that length is exceeded. +pub enum SsoHashMap { + Array(ArrayVec<[(K, V); 8]>), + Map(FxHashMap), +} + +impl SsoHashMap { + /// Creates an empty `SsoHashMap`. + pub fn new() -> Self { + SsoHashMap::Array(ArrayVec::new()) + } + + /// Inserts or updates value in the map. + pub fn insert(&mut self, key: K, value: V) { + match self { + SsoHashMap::Array(array) => { + for pair in array.iter_mut() { + if pair.0 == key { + pair.1 = value; + return; + } + } + if let Err(error) = array.try_push((key, value)) { + let mut map: FxHashMap = array.drain(..).collect(); + let (key, value) = error.element(); + map.insert(key, value); + *self = SsoHashMap::Map(map); + } + } + SsoHashMap::Map(map) => { + map.insert(key, value); + } + } + } + + /// Return value by key if any. + pub fn get(&self, key: &K) -> Option<&V> { + match self { + SsoHashMap::Array(array) => { + for pair in array { + if pair.0 == *key { + return Some(&pair.1); + } + } + return None; + } + SsoHashMap::Map(map) => { + return map.get(key); + } + } + } +} diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs new file mode 100644 index 00000000000..ef634b9adce --- /dev/null +++ b/compiler/rustc_data_structures/src/sso/mod.rs @@ -0,0 +1,5 @@ +mod map; +mod set; + +pub use map::SsoHashMap; +pub use set::SsoHashSet; diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs new file mode 100644 index 00000000000..b403c9dcc33 --- /dev/null +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -0,0 +1,41 @@ +use crate::fx::FxHashSet; +use arrayvec::ArrayVec; +use std::hash::Hash; +/// Small-storage-optimized implementation of a set. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum SsoHashSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl SsoHashSet { + /// Creates an empty `SsoHashSet`. + pub fn new() -> Self { + SsoHashSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + SsoHashSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if let Err(error) = array.try_push(elem) { + let mut set: FxHashSet = array.drain(..).collect(); + set.insert(error.element()); + *self = SsoHashSet::Set(set); + } + true + } + } + SsoHashSet::Set(set) => set.insert(elem), + } + } +} diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a540face4f2..6a1715ef818 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -35,7 +35,7 @@ use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_ast as ast; -use rustc_data_structures::mini_map::MiniMap; +use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; @@ -429,7 +429,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { needs_wf: false, root_ty: ty, param_env: self.param_env, - cache: MiniMap::new(), + cache: SsoHashMap::new(), }; let ty = match generalize.relate(ty, ty) { @@ -490,7 +490,7 @@ struct Generalizer<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, - cache: MiniMap, RelateResult<'tcx, Ty<'tcx>>>, + cache: SsoHashMap, RelateResult<'tcx, Ty<'tcx>>>, } /// Result from a generalization operation. This includes diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 21b0836563f..07924298c24 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,7 +1,7 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::mini_set::MiniSet; +use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -32,7 +32,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// Returns a "verify bound" that encodes what we know about /// `generic` and the regions it outlives. pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> { - let mut visited = MiniSet::new(); + let mut visited = SsoHashSet::new(); match generic { GenericKind::Param(param_ty) => self.param_bound(param_ty), GenericKind::Projection(projection_ty) => { @@ -44,7 +44,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn type_bound( &self, ty: Ty<'tcx>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { match *ty.kind() { ty::Param(p) => self.param_bound(p), @@ -148,7 +148,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { pub fn projection_bound( &self, projection_ty: ty::ProjectionTy<'tcx>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { debug!("projection_bound(projection_ty={:?})", projection_ty); @@ -186,7 +186,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn recursive_bound( &self, parent: GenericArg<'tcx>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { let mut bounds = parent .walk_shallow(visited) diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index ca992d36e95..4c20141bbe6 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -4,7 +4,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::mini_set::MiniSet; +use rustc_data_structures::sso::SsoHashSet; use smallvec::SmallVec; #[derive(Debug)] @@ -51,7 +51,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut visited = MiniSet::new(); + let mut visited = SsoHashSet::new(); compute_components(self, ty0, out, &mut visited); debug!("components({:?}) = {:?}", ty0, out); } @@ -61,7 +61,7 @@ fn compute_components( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) { // Descend through the types, looking for the various "base" // components and collecting them into `out`. This is not written @@ -142,7 +142,7 @@ fn compute_components( // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; - let mut subvisited = MiniSet::new(); + let mut subvisited = SsoHashSet::new(); compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); } @@ -194,7 +194,7 @@ fn compute_components_recursive( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) { for child in parent.walk_shallow(visited) { match child.unpack() { diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 225ea2399fb..2e00be2395b 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,7 +2,7 @@ use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::mini_set::MiniSet; +use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; @@ -269,7 +269,7 @@ pub trait Printer<'tcx>: Sized { /// deeply nested tuples that have no DefId. fn characteristic_def_id_of_type_cached<'a>( ty: Ty<'a>, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) -> Option { match *ty.kind() { ty::Adt(adt_def, _) => Some(adt_def.did), @@ -316,7 +316,7 @@ fn characteristic_def_id_of_type_cached<'a>( } } pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { - characteristic_def_id_of_type_cached(ty, &mut MiniSet::new()) + characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new()) } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind { diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 80ade7dda4c..357a0dd65c4 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,7 +3,7 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; -use rustc_data_structures::mini_set::MiniSet; +use rustc_data_structures::sso::SsoHashSet; use smallvec::{self, SmallVec}; // The TypeWalker's stack is hot enough that it's worth going to some effort to @@ -13,7 +13,7 @@ type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { stack: TypeWalkerStack<'tcx>, last_subtree: usize, - visited: MiniSet>, + visited: SsoHashSet>, } /// An iterator for walking the type tree. @@ -26,7 +26,7 @@ pub struct TypeWalker<'tcx> { /// skips any types that are already there. impl<'tcx> TypeWalker<'tcx> { pub fn new(root: GenericArg<'tcx>) -> Self { - Self { stack: smallvec![root], last_subtree: 1, visited: MiniSet::new() } + Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } } /// Skips the subtree corresponding to the last type @@ -87,7 +87,7 @@ impl GenericArg<'tcx> { /// and skips any types that are already there. pub fn walk_shallow( self, - visited: &mut MiniSet>, + visited: &mut SsoHashSet>, ) -> impl Iterator> { let mut stack = SmallVec::new(); push_inner(&mut stack, self); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 3dcebbcc244..bdbf45f78a2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,7 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; -use rustc_data_structures::mini_map::MiniMap; +use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -58,7 +58,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { param_env: self.param_env, obligations: vec![], error: false, - cache: MiniMap::new(), + cache: SsoHashMap::new(), anon_depth: 0, }; @@ -87,7 +87,7 @@ struct QueryNormalizer<'cx, 'tcx> { cause: &'cx ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec>, - cache: MiniMap, Ty<'tcx>>, + cache: SsoHashMap, Ty<'tcx>>, error: bool, anon_depth: usize, } -- cgit 1.4.1-3-g733a5 From 0600b178aa0e9f310067bf8ccaf736e77a03eb1d Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Thu, 24 Sep 2020 01:21:31 -0500 Subject: SsoHashSet/SsoHashMap API greatly expanded Now both provide almost complete API of their non-SSO counterparts. --- compiler/rustc_data_structures/src/sso/map.rs | 508 +++++++++++++++++++++++++- compiler/rustc_data_structures/src/sso/mod.rs | 72 ++++ compiler/rustc_data_structures/src/sso/set.rs | 307 +++++++++++++++- 3 files changed, 864 insertions(+), 23 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index c253e9d6616..258368c8ef3 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,32 +1,202 @@ +use super::EitherIter; use crate::fx::FxHashMap; use arrayvec::ArrayVec; - +use std::borrow::Borrow; +use std::fmt; use std::hash::Hash; +use std::iter::FromIterator; +use std::ops::Index; -/// Small-storage-optimized implementation of a map -/// made specifically for caching results. +/// Small-storage-optimized implementation of a map. /// /// Stores elements in a small array up to a certain length /// and switches to `HashMap` when that length is exceeded. +/// +/// Implements subset of HashMap API. +/// +/// Missing HashMap API: +/// all hasher-related +/// try_reserve (unstable) +/// shrink_to (unstable) +/// drain_filter (unstable) +/// into_keys/into_values (unstable) +/// all raw_entry-related +/// PartialEq/Eq (requires sorting the array) +/// Entry::or_insert_with_key (unstable) +/// Vacant/Occupied entries and related +#[derive(Clone)] pub enum SsoHashMap { Array(ArrayVec<[(K, V); 8]>), Map(FxHashMap), } -impl SsoHashMap { +impl SsoHashMap { /// Creates an empty `SsoHashMap`. pub fn new() -> Self { SsoHashMap::Array(ArrayVec::new()) } - /// Inserts or updates value in the map. - pub fn insert(&mut self, key: K, value: V) { + /// Creates an empty `SsoHashMap` with the specified capacity. + pub fn with_capacity(cap: usize) -> Self { + let array = ArrayVec::new(); + if array.capacity() >= cap { + SsoHashMap::Array(array) + } else { + SsoHashMap::Map(FxHashMap::with_capacity_and_hasher(cap, Default::default())) + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + pub fn clear(&mut self) { + match self { + SsoHashMap::Array(array) => array.clear(), + SsoHashMap::Map(map) => map.clear(), + } + } + + /// Returns the number of elements the map can hold without reallocating. + pub fn capacity(&self) -> usize { + match self { + SsoHashMap::Array(array) => array.capacity(), + SsoHashMap::Map(map) => map.capacity(), + } + } + + /// Returns the number of elements in the map. + pub fn len(&self) -> usize { + match self { + SsoHashMap::Array(array) => array.len(), + SsoHashMap::Map(map) => map.len(), + } + } + + /// Returns `true` if the map contains no elements. + pub fn is_empty(&self) -> bool { + match self { + SsoHashMap::Array(array) => array.is_empty(), + SsoHashMap::Map(map) => map.is_empty(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + pub fn iter(&self) -> impl Iterator { + self.into_iter() + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + pub fn iter_mut(&mut self) -> impl Iterator { + self.into_iter() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + pub fn keys(&self) -> impl Iterator { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(k, _v)| k)), + SsoHashMap::Map(map) => EitherIter::Right(map.keys()), + } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + pub fn values(&self) -> impl Iterator { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(_k, v)| v)), + SsoHashMap::Map(map) => EitherIter::Right(map.values()), + } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + pub fn values_mut(&mut self) -> impl Iterator { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.iter_mut().map(|(_k, v)| v)), + SsoHashMap::Map(map) => EitherIter::Right(map.values_mut()), + } + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + pub fn drain(&mut self) -> impl Iterator + '_ { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.drain(..)), + SsoHashMap::Map(map) => EitherIter::Right(map.drain()), + } + } +} + +impl SsoHashMap { + /// Changes underlying storage from array to hashmap + /// if array is full. + fn migrate_if_full(&mut self) { + if let SsoHashMap::Array(array) = self { + if array.is_full() { + *self = SsoHashMap::Map(array.drain(..).collect()); + } + } + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `SsoHashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + pub fn reserve(&mut self, additional: usize) { + match self { + SsoHashMap::Array(array) => { + if array.capacity() < (array.len() + additional) { + let mut map: FxHashMap = array.drain(..).collect(); + map.reserve(additional); + *self = SsoHashMap::Map(map); + } + } + SsoHashMap::Map(map) => map.reserve(additional), + } + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + pub fn shrink_to_fit(&mut self) { + if let SsoHashMap::Map(map) = self { + let mut array = ArrayVec::new(); + if map.len() <= array.capacity() { + array.extend(map.drain()); + *self = SsoHashMap::Array(array); + } else { + map.shrink_to_fit(); + } + } + } + + /// Retains only the elements specified by the predicate. + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + match self { + SsoHashMap::Array(array) => array.retain(|(k, v)| f(k, v)), + SsoHashMap::Map(map) => map.retain(f), + } + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + pub fn insert(&mut self, key: K, value: V) -> Option { match self { SsoHashMap::Array(array) => { - for pair in array.iter_mut() { - if pair.0 == key { - pair.1 = value; - return; + for (k, v) in array.iter_mut() { + if *k == key { + let old_value = std::mem::replace(v, value); + return Some(old_value); } } if let Err(error) = array.try_push((key, value)) { @@ -35,27 +205,325 @@ impl SsoHashMap { map.insert(key, value); *self = SsoHashMap::Map(map); } + None } - SsoHashMap::Map(map) => { - map.insert(key, value); + SsoHashMap::Map(map) => map.insert(key, value), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashMap::Array(array) => { + if let Some(index) = array.iter().position(|(k, _v)| k.borrow() == key) { + Some(array.swap_remove(index).1) + } else { + None + } + } + SsoHashMap::Map(map) => map.remove(key), + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + K: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashMap::Array(array) => { + if let Some(index) = array.iter().position(|(k, _v)| k.borrow() == key) { + Some(array.swap_remove(index)) + } else { + None + } } + SsoHashMap::Map(map) => map.remove_entry(key), } } - /// Return value by key if any. - pub fn get(&self, key: &K) -> Option<&V> { + /// Returns a reference to the value corresponding to the key. + pub fn get(&self, key: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { match self { SsoHashMap::Array(array) => { - for pair in array { - if pair.0 == *key { - return Some(&pair.1); + for (k, v) in array { + if k.borrow() == key { + return Some(v); } } - return None; + None } - SsoHashMap::Map(map) => { - return map.get(key); + SsoHashMap::Map(map) => map.get(key), + } + } + + /// Returns a mutable reference to the value corresponding to the key. + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashMap::Array(array) => { + for (k, v) in array { + if (*k).borrow() == key { + return Some(v); + } + } + None } + SsoHashMap::Map(map) => map.get_mut(key), } } + + /// Returns the key-value pair corresponding to the supplied key. + pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashMap::Array(array) => { + for (k, v) in array { + if k.borrow() == key { + return Some((k, v)); + } + } + None + } + SsoHashMap::Map(map) => map.get_key_value(key), + } + } + + /// Returns `true` if the map contains a value for the specified key. + pub fn contains_key(&self, key: &Q) -> bool + where + K: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashMap::Array(array) => array.iter().any(|(k, _v)| k.borrow() == key), + SsoHashMap::Map(map) => map.contains_key(key), + } + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + Entry { ssomap: self, key } + } +} + +impl Default for SsoHashMap { + fn default() -> Self { + Self::new() + } +} + +impl FromIterator<(K, V)> for SsoHashMap { + fn from_iter>(iter: I) -> SsoHashMap { + let mut map: SsoHashMap = Default::default(); + map.extend(iter); + map + } +} + +impl Extend<(K, V)> for SsoHashMap { + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for (key, value) in iter.into_iter() { + self.insert(key, value); + } + } + + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + fn extend_reserve(&mut self, additional: usize) { + match self { + SsoHashMap::Array(array) => { + if array.capacity() < (array.len() + additional) { + let mut map: FxHashMap = array.drain(..).collect(); + map.extend_reserve(additional); + *self = SsoHashMap::Map(map); + } + } + SsoHashMap::Map(map) => map.extend_reserve(additional), + } + } +} + +impl<'a, K, V> Extend<(&'a K, &'a V)> for SsoHashMap +where + K: Eq + Hash + Copy, + V: Copy, +{ + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(k, v)| (k.clone(), v.clone()))) + } + + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.insert(k, v); + } + + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional) + } +} + +impl IntoIterator for SsoHashMap { + type IntoIter = EitherIter< + as IntoIterator>::IntoIter, + as IntoIterator>::IntoIter, + >; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.into_iter()), + SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + } + } +} + +/// adapts Item of array reference iterator to Item of hashmap reference iterator. +fn adapt_array_ref_it(pair: &'a (K, V)) -> (&'a K, &'a V) { + let (a, b) = pair; + (a, b) +} + +/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. +fn adapt_array_mut_it(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) { + let (a, b) = pair; + (a, b) +} + +impl<'a, K, V> IntoIterator for &'a SsoHashMap { + type IntoIter = EitherIter< + std::iter::Map< + <&'a ArrayVec<[(K, V); 8]> as IntoIterator>::IntoIter, + fn(&'a (K, V)) -> (&'a K, &'a V), + >, + <&'a FxHashMap as IntoIterator>::IntoIter, + >; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_ref_it)), + SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + } + } +} + +impl<'a, K, V> IntoIterator for &'a mut SsoHashMap { + type IntoIter = EitherIter< + std::iter::Map< + <&'a mut ArrayVec<[(K, V); 8]> as IntoIterator>::IntoIter, + fn(&'a mut (K, V)) -> (&'a K, &'a mut V), + >, + <&'a mut FxHashMap as IntoIterator>::IntoIter, + >; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter { + match self { + SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_mut_it)), + SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + } + } +} + +impl fmt::Debug for SsoHashMap +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl<'a, K, Q: ?Sized, V> Index<&'a Q> for SsoHashMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, +{ + type Output = V; + + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +/// A view into a single entry in a map. +pub struct Entry<'a, K, V> { + ssomap: &'a mut SsoHashMap, + key: K, +} + +impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + if let Some(value) = self.ssomap.get_mut(&self.key) { + f(value); + } + self + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, value: V) -> &'a mut V { + self.or_insert_with(|| value) + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + self.ssomap.migrate_if_full(); + match self.ssomap { + SsoHashMap::Array(array) => { + let key_ref = &self.key; + let found_index = array.iter().position(|(k, _v)| k == key_ref); + let index = if let Some(index) = found_index { + index + } else { + array.try_push((self.key, default())).unwrap(); + array.len() - 1 + }; + &mut array[index].1 + } + SsoHashMap::Map(map) => map.entry(self.key).or_insert_with(default), + } + } + + /// Returns a reference to this entry's key. + pub fn key(&self) -> &K { + &self.key + } +} + +impl<'a, K: Eq + Hash, V: Default> Entry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + pub fn or_default(self) -> &'a mut V { + self.or_insert_with(Default::default) + } } diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs index ef634b9adce..bcc4240721e 100644 --- a/compiler/rustc_data_structures/src/sso/mod.rs +++ b/compiler/rustc_data_structures/src/sso/mod.rs @@ -1,3 +1,75 @@ +use std::fmt; +use std::iter::ExactSizeIterator; +use std::iter::FusedIterator; +use std::iter::Iterator; + +/// Iterator which may contain instance of +/// one of two specific implementations. +/// +/// Used by both SsoHashMap and SsoHashSet. +#[derive(Clone)] +pub enum EitherIter { + Left(L), + Right(R), +} + +impl Iterator for EitherIter +where + L: Iterator, + R: Iterator, +{ + type Item = L::Item; + + fn next(&mut self) -> Option { + match self { + EitherIter::Left(l) => l.next(), + EitherIter::Right(r) => r.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + EitherIter::Left(l) => l.size_hint(), + EitherIter::Right(r) => r.size_hint(), + } + } +} + +impl ExactSizeIterator for EitherIter +where + L: ExactSizeIterator, + R: ExactSizeIterator, + EitherIter: Iterator, +{ + fn len(&self) -> usize { + match self { + EitherIter::Left(l) => l.len(), + EitherIter::Right(r) => r.len(), + } + } +} + +impl FusedIterator for EitherIter +where + L: FusedIterator, + R: FusedIterator, + EitherIter: Iterator, +{ +} + +impl fmt::Debug for EitherIter +where + L: fmt::Debug, + R: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EitherIter::Left(l) => l.fmt(f), + EitherIter::Right(r) => r.fmt(f), + } + } +} + mod map; mod set; diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index b403c9dcc33..6ec70524368 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -1,26 +1,197 @@ +use super::EitherIter; use crate::fx::FxHashSet; use arrayvec::ArrayVec; +use std::borrow::Borrow; +use std::fmt; use std::hash::Hash; +use std::iter::FromIterator; + /// Small-storage-optimized implementation of a set. /// /// Stores elements in a small array up to a certain length /// and switches to `HashSet` when that length is exceeded. +/// +/// Implements subset of HashSet API. +/// +/// Missing HashSet API: +/// all hasher-related +/// try_reserve (unstable) +/// shrink_to (unstable) +/// drain_filter (unstable) +/// get_or_insert/get_or_insert_owned/get_or_insert_with (unstable) +/// difference/symmetric_difference/intersection/union +/// is_disjoint/is_subset/is_superset +/// PartialEq/Eq (requires sorting the array) +/// BitOr/BitAnd/BitXor/Sub +#[derive(Clone)] pub enum SsoHashSet { Array(ArrayVec<[T; 8]>), Set(FxHashSet), } -impl SsoHashSet { +impl SsoHashSet { /// Creates an empty `SsoHashSet`. pub fn new() -> Self { SsoHashSet::Array(ArrayVec::new()) } + /// Creates an empty `SsoHashSet` with the specified capacity. + pub fn with_capacity(cap: usize) -> Self { + let array = ArrayVec::new(); + if array.capacity() >= cap { + SsoHashSet::Array(array) + } else { + SsoHashSet::Set(FxHashSet::with_capacity_and_hasher(cap, Default::default())) + } + } + + /// Clears the set, removing all values. + pub fn clear(&mut self) { + match self { + SsoHashSet::Array(array) => array.clear(), + SsoHashSet::Set(set) => set.clear(), + } + } + + /// Returns the number of elements the set can hold without reallocating. + pub fn capacity(&self) -> usize { + match self { + SsoHashSet::Array(array) => array.capacity(), + SsoHashSet::Set(set) => set.capacity(), + } + } + + /// Returns the number of elements in the set. + pub fn len(&self) -> usize { + match self { + SsoHashSet::Array(array) => array.len(), + SsoHashSet::Set(set) => set.len(), + } + } + + /// Returns `true` if the set contains no elements. + pub fn is_empty(&self) -> bool { + match self { + SsoHashSet::Array(array) => array.is_empty(), + SsoHashSet::Set(set) => set.is_empty(), + } + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + pub fn iter(&'a self) -> impl Iterator { + self.into_iter() + } + + /// Clears the set, returning all elements in an iterator. + pub fn drain(&mut self) -> impl Iterator + '_ { + match self { + SsoHashSet::Array(array) => EitherIter::Left(array.drain(..)), + SsoHashSet::Set(set) => EitherIter::Right(set.drain()), + } + } +} + +impl SsoHashSet { + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `SsoHashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + pub fn reserve(&mut self, additional: usize) { + match self { + SsoHashSet::Array(array) => { + if array.capacity() < (array.len() + additional) { + let mut set: FxHashSet = array.drain(..).collect(); + set.reserve(additional); + *self = SsoHashSet::Set(set); + } + } + SsoHashSet::Set(set) => set.reserve(additional), + } + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + pub fn shrink_to_fit(&mut self) { + if let SsoHashSet::Set(set) = self { + let mut array = ArrayVec::new(); + if set.len() <= array.capacity() { + array.extend(set.drain()); + *self = SsoHashSet::Array(array); + } else { + set.shrink_to_fit(); + } + } + } + + /// Retains only the elements specified by the predicate. + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + match self { + SsoHashSet::Array(array) => array.retain(|v| f(v)), + SsoHashSet::Set(set) => set.retain(f), + } + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + pub fn take(&mut self, value: &Q) -> Option + where + T: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashSet::Array(array) => { + if let Some(index) = array.iter().position(|val| val.borrow() == value) { + Some(array.swap_remove(index)) + } else { + None + } + } + SsoHashSet::Set(set) => set.take(value), + } + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + pub fn replace(&mut self, value: T) -> Option { + match self { + SsoHashSet::Array(array) => { + if let Some(index) = array.iter().position(|val| *val == value) { + let old_value = std::mem::replace(&mut array[index], value); + Some(old_value) + } else { + None + } + } + SsoHashSet::Set(set) => set.replace(value), + } + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + pub fn get(&self, value: &Q) -> Option<&T> + where + T: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashSet::Array(array) => { + if let Some(index) = array.iter().position(|val| val.borrow() == value) { + Some(&array[index]) + } else { + None + } + } + SsoHashSet::Set(set) => set.get(value), + } + } + /// Adds a value to the set. /// - /// If the set did not have this value present, true is returned. + /// If the set did not have this value present, `true` is returned. /// - /// If the set did have this value present, false is returned. + /// If the set did have this value present, `false` is returned. pub fn insert(&mut self, elem: T) -> bool { match self { SsoHashSet::Array(array) => { @@ -38,4 +209,134 @@ impl SsoHashSet { SsoHashSet::Set(set) => set.insert(elem), } } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + pub fn remove(&mut self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashSet::Array(array) => { + if let Some(index) = array.iter().position(|val| val.borrow() == value) { + array.swap_remove(index); + true + } else { + false + } + } + SsoHashSet::Set(set) => set.remove(value), + } + } + + /// Returns `true` if the set contains a value. + pub fn contains(&self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + match self { + SsoHashSet::Array(array) => array.iter().any(|v| v.borrow() == value), + SsoHashSet::Set(set) => set.contains(value), + } + } +} + +impl Default for SsoHashSet { + fn default() -> Self { + Self::new() + } +} + +impl FromIterator for SsoHashSet { + fn from_iter>(iter: I) -> SsoHashSet { + let mut set: SsoHashSet = Default::default(); + set.extend(iter); + set + } +} + +impl Extend for SsoHashSet { + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for val in iter.into_iter() { + self.insert(val); + } + } + + fn extend_one(&mut self, item: T) { + self.insert(item); + } + + fn extend_reserve(&mut self, additional: usize) { + match self { + SsoHashSet::Array(array) => { + if array.capacity() < (array.len() + additional) { + let mut set: FxHashSet = array.drain(..).collect(); + set.extend_reserve(additional); + *self = SsoHashSet::Set(set); + } + } + SsoHashSet::Set(set) => set.extend_reserve(additional), + } + } +} + +impl<'a, T> Extend<&'a T> for SsoHashSet +where + T: 'a + Eq + Hash + Copy, +{ + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + + fn extend_one(&mut self, &item: &'a T) { + self.insert(item); + } + + fn extend_reserve(&mut self, additional: usize) { + Extend::::extend_reserve(self, additional) + } +} + +impl IntoIterator for SsoHashSet { + type IntoIter = EitherIter< + as IntoIterator>::IntoIter, + as IntoIterator>::IntoIter, + >; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter { + match self { + SsoHashSet::Array(array) => EitherIter::Left(array.into_iter()), + SsoHashSet::Set(set) => EitherIter::Right(set.into_iter()), + } + } +} + +impl<'a, T> IntoIterator for &'a SsoHashSet { + type IntoIter = EitherIter< + <&'a ArrayVec<[T; 8]> as IntoIterator>::IntoIter, + <&'a FxHashSet as IntoIterator>::IntoIter, + >; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter { + match self { + SsoHashSet::Array(array) => EitherIter::Left(array.into_iter()), + SsoHashSet::Set(set) => EitherIter::Right(set.into_iter()), + } + } +} + +impl fmt::Debug for SsoHashSet +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } } -- cgit 1.4.1-3-g733a5 From 41942fac7d0711c6b3d0faa69748e22c0eb41388 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Sat, 26 Sep 2020 14:28:26 -0500 Subject: SsoHashSet reimplemented as a wrapper on top of SsoHashMap SsoHashSet::replace had to be removed because it requires missing API from SsoHashMap. It's not a widely used function, so I think it's ok to omit it for now. EitherIter moved into its own file. Also sprinkled code with #[inline] attributes where appropriate. --- .../rustc_data_structures/src/sso/either_iter.rs | 75 +++++++ compiler/rustc_data_structures/src/sso/map.rs | 18 +- compiler/rustc_data_structures/src/sso/mod.rs | 73 +------ compiler/rustc_data_structures/src/sso/set.rs | 220 +++++++-------------- 4 files changed, 158 insertions(+), 228 deletions(-) create mode 100644 compiler/rustc_data_structures/src/sso/either_iter.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/sso/either_iter.rs b/compiler/rustc_data_structures/src/sso/either_iter.rs new file mode 100644 index 00000000000..af8ffcf4c13 --- /dev/null +++ b/compiler/rustc_data_structures/src/sso/either_iter.rs @@ -0,0 +1,75 @@ +use std::fmt; +use std::iter::ExactSizeIterator; +use std::iter::FusedIterator; +use std::iter::Iterator; + +/// Iterator which may contain instance of +/// one of two specific implementations. +/// +/// Note: For most methods providing custom +/// implementation may margianlly +/// improve performance by avoiding +/// doing Left/Right match on every step +/// and doing it only once instead. +#[derive(Clone)] +pub enum EitherIter { + Left(L), + Right(R), +} + +impl Iterator for EitherIter +where + L: Iterator, + R: Iterator, +{ + type Item = L::Item; + + fn next(&mut self) -> Option { + match self { + EitherIter::Left(l) => l.next(), + EitherIter::Right(r) => r.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + EitherIter::Left(l) => l.size_hint(), + EitherIter::Right(r) => r.size_hint(), + } + } +} + +impl ExactSizeIterator for EitherIter +where + L: ExactSizeIterator, + R: ExactSizeIterator, + EitherIter: Iterator, +{ + fn len(&self) -> usize { + match self { + EitherIter::Left(l) => l.len(), + EitherIter::Right(r) => r.len(), + } + } +} + +impl FusedIterator for EitherIter +where + L: FusedIterator, + R: FusedIterator, + EitherIter: Iterator, +{ +} + +impl fmt::Debug for EitherIter +where + L: fmt::Debug, + R: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EitherIter::Left(l) => l.fmt(f), + EitherIter::Right(r) => r.fmt(f), + } + } +} diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 258368c8ef3..3089f887845 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,4 +1,4 @@ -use super::EitherIter; +use super::either_iter::EitherIter; use crate::fx::FxHashMap; use arrayvec::ArrayVec; use std::borrow::Borrow; @@ -32,6 +32,7 @@ pub enum SsoHashMap { impl SsoHashMap { /// Creates an empty `SsoHashMap`. + #[inline] pub fn new() -> Self { SsoHashMap::Array(ArrayVec::new()) } @@ -81,13 +82,15 @@ impl SsoHashMap { /// An iterator visiting all key-value pairs in arbitrary order. /// The iterator element type is `(&'a K, &'a V)`. - pub fn iter(&self) -> impl Iterator { + #[inline] + pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter { self.into_iter() } /// An iterator visiting all key-value pairs in arbitrary order, /// with mutable references to the values. /// The iterator element type is `(&'a K, &'a mut V)`. + #[inline] pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } @@ -319,12 +322,14 @@ impl SsoHashMap { } /// Gets the given key's corresponding entry in the map for in-place manipulation. + #[inline] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { Entry { ssomap: self, key } } } impl Default for SsoHashMap { + #[inline] fn default() -> Self { Self::new() } @@ -348,6 +353,7 @@ impl Extend<(K, V)> for SsoHashMap { } } + #[inline] fn extend_one(&mut self, (k, v): (K, V)) { self.insert(k, v); } @@ -375,10 +381,12 @@ where self.extend(iter.into_iter().map(|(k, v)| (k.clone(), v.clone()))) } + #[inline] fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { self.insert(k, v); } + #[inline] fn extend_reserve(&mut self, additional: usize) { Extend::<(K, V)>::extend_reserve(self, additional) } @@ -400,12 +408,14 @@ impl IntoIterator for SsoHashMap { } /// adapts Item of array reference iterator to Item of hashmap reference iterator. +#[inline(always)] fn adapt_array_ref_it(pair: &'a (K, V)) -> (&'a K, &'a V) { let (a, b) = pair; (a, b) } /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. +#[inline(always)] fn adapt_array_mut_it(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) { let (a, b) = pair; (a, b) @@ -464,6 +474,7 @@ where { type Output = V; + #[inline] fn index(&self, key: &Q) -> &V { self.get(key).expect("no entry found for key") } @@ -490,6 +501,7 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + #[inline] pub fn or_insert(self, value: V) -> &'a mut V { self.or_insert_with(|| value) } @@ -515,6 +527,7 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + #[inline] pub fn key(&self) -> &K { &self.key } @@ -523,6 +536,7 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { impl<'a, K: Eq + Hash, V: Default> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. + #[inline] pub fn or_default(self) -> &'a mut V { self.or_insert_with(Default::default) } diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs index bcc4240721e..dd21bc8e696 100644 --- a/compiler/rustc_data_structures/src/sso/mod.rs +++ b/compiler/rustc_data_structures/src/sso/mod.rs @@ -1,75 +1,4 @@ -use std::fmt; -use std::iter::ExactSizeIterator; -use std::iter::FusedIterator; -use std::iter::Iterator; - -/// Iterator which may contain instance of -/// one of two specific implementations. -/// -/// Used by both SsoHashMap and SsoHashSet. -#[derive(Clone)] -pub enum EitherIter { - Left(L), - Right(R), -} - -impl Iterator for EitherIter -where - L: Iterator, - R: Iterator, -{ - type Item = L::Item; - - fn next(&mut self) -> Option { - match self { - EitherIter::Left(l) => l.next(), - EitherIter::Right(r) => r.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - EitherIter::Left(l) => l.size_hint(), - EitherIter::Right(r) => r.size_hint(), - } - } -} - -impl ExactSizeIterator for EitherIter -where - L: ExactSizeIterator, - R: ExactSizeIterator, - EitherIter: Iterator, -{ - fn len(&self) -> usize { - match self { - EitherIter::Left(l) => l.len(), - EitherIter::Right(r) => r.len(), - } - } -} - -impl FusedIterator for EitherIter -where - L: FusedIterator, - R: FusedIterator, - EitherIter: Iterator, -{ -} - -impl fmt::Debug for EitherIter -where - L: fmt::Debug, - R: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - EitherIter::Left(l) => l.fmt(f), - EitherIter::Right(r) => r.fmt(f), - } - } -} - +mod either_iter; mod map; mod set; diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index 6ec70524368..353529b0598 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -1,11 +1,10 @@ -use super::EitherIter; -use crate::fx::FxHashSet; -use arrayvec::ArrayVec; use std::borrow::Borrow; use std::fmt; use std::hash::Hash; use std::iter::FromIterator; +use super::map::SsoHashMap; + /// Small-storage-optimized implementation of a set. /// /// Stores elements in a small array up to a certain length @@ -18,77 +17,73 @@ use std::iter::FromIterator; /// try_reserve (unstable) /// shrink_to (unstable) /// drain_filter (unstable) +/// replace /// get_or_insert/get_or_insert_owned/get_or_insert_with (unstable) /// difference/symmetric_difference/intersection/union /// is_disjoint/is_subset/is_superset -/// PartialEq/Eq (requires sorting the array) +/// PartialEq/Eq (requires SsoHashMap implementation) /// BitOr/BitAnd/BitXor/Sub #[derive(Clone)] -pub enum SsoHashSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), +pub struct SsoHashSet { + map: SsoHashMap, +} + +/// Adapter function used ot return +/// result if SsoHashMap functions into +/// result SsoHashSet should return. +#[inline(always)] +fn entry_to_key((k, _v): (K, V)) -> K { + k } impl SsoHashSet { /// Creates an empty `SsoHashSet`. + #[inline] pub fn new() -> Self { - SsoHashSet::Array(ArrayVec::new()) + Self { map: SsoHashMap::new() } } /// Creates an empty `SsoHashSet` with the specified capacity. + #[inline] pub fn with_capacity(cap: usize) -> Self { - let array = ArrayVec::new(); - if array.capacity() >= cap { - SsoHashSet::Array(array) - } else { - SsoHashSet::Set(FxHashSet::with_capacity_and_hasher(cap, Default::default())) - } + Self { map: SsoHashMap::with_capacity(cap) } } /// Clears the set, removing all values. + #[inline] pub fn clear(&mut self) { - match self { - SsoHashSet::Array(array) => array.clear(), - SsoHashSet::Set(set) => set.clear(), - } + self.map.clear() } /// Returns the number of elements the set can hold without reallocating. + #[inline] pub fn capacity(&self) -> usize { - match self { - SsoHashSet::Array(array) => array.capacity(), - SsoHashSet::Set(set) => set.capacity(), - } + self.map.capacity() } /// Returns the number of elements in the set. + #[inline] pub fn len(&self) -> usize { - match self { - SsoHashSet::Array(array) => array.len(), - SsoHashSet::Set(set) => set.len(), - } + self.map.len() } /// Returns `true` if the set contains no elements. + #[inline] pub fn is_empty(&self) -> bool { - match self { - SsoHashSet::Array(array) => array.is_empty(), - SsoHashSet::Set(set) => set.is_empty(), - } + self.map.is_empty() } /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. + #[inline] pub fn iter(&'a self) -> impl Iterator { self.into_iter() } /// Clears the set, returning all elements in an iterator. + #[inline] pub fn drain(&mut self) -> impl Iterator + '_ { - match self { - SsoHashSet::Array(array) => EitherIter::Left(array.drain(..)), - SsoHashSet::Set(set) => EitherIter::Right(set.drain()), - } + self.map.drain().map(entry_to_key) } } @@ -96,95 +91,46 @@ impl SsoHashSet { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `SsoHashSet`. The collection may reserve more space to avoid /// frequent reallocations. + #[inline] pub fn reserve(&mut self, additional: usize) { - match self { - SsoHashSet::Array(array) => { - if array.capacity() < (array.len() + additional) { - let mut set: FxHashSet = array.drain(..).collect(); - set.reserve(additional); - *self = SsoHashSet::Set(set); - } - } - SsoHashSet::Set(set) => set.reserve(additional), - } + self.map.reserve(additional) } /// Shrinks the capacity of the set as much as possible. It will drop /// down as much as possible while maintaining the internal rules /// and possibly leaving some space in accordance with the resize policy. + #[inline] pub fn shrink_to_fit(&mut self) { - if let SsoHashSet::Set(set) = self { - let mut array = ArrayVec::new(); - if set.len() <= array.capacity() { - array.extend(set.drain()); - *self = SsoHashSet::Array(array); - } else { - set.shrink_to_fit(); - } - } + self.map.shrink_to_fit() } /// Retains only the elements specified by the predicate. + #[inline] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool, { - match self { - SsoHashSet::Array(array) => array.retain(|v| f(v)), - SsoHashSet::Set(set) => set.retain(f), - } + self.map.retain(|k, _v| f(k)) } /// Removes and returns the value in the set, if any, that is equal to the given one. + #[inline] pub fn take(&mut self, value: &Q) -> Option where T: Borrow, Q: Hash + Eq, { - match self { - SsoHashSet::Array(array) => { - if let Some(index) = array.iter().position(|val| val.borrow() == value) { - Some(array.swap_remove(index)) - } else { - None - } - } - SsoHashSet::Set(set) => set.take(value), - } - } - - /// Adds a value to the set, replacing the existing value, if any, that is equal to the given - /// one. Returns the replaced value. - pub fn replace(&mut self, value: T) -> Option { - match self { - SsoHashSet::Array(array) => { - if let Some(index) = array.iter().position(|val| *val == value) { - let old_value = std::mem::replace(&mut array[index], value); - Some(old_value) - } else { - None - } - } - SsoHashSet::Set(set) => set.replace(value), - } + self.map.remove_entry(value).map(entry_to_key) } /// Returns a reference to the value in the set, if any, that is equal to the given value. + #[inline] pub fn get(&self, value: &Q) -> Option<&T> where T: Borrow, Q: Hash + Eq, { - match self { - SsoHashSet::Array(array) => { - if let Some(index) = array.iter().position(|val| val.borrow() == value) { - Some(&array[index]) - } else { - None - } - } - SsoHashSet::Set(set) => set.get(value), - } + self.map.get_key_value(value).map(entry_to_key) } /// Adds a value to the set. @@ -192,60 +138,30 @@ impl SsoHashSet { /// If the set did not have this value present, `true` is returned. /// /// If the set did have this value present, `false` is returned. + #[inline] pub fn insert(&mut self, elem: T) -> bool { - match self { - SsoHashSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if let Err(error) = array.try_push(elem) { - let mut set: FxHashSet = array.drain(..).collect(); - set.insert(error.element()); - *self = SsoHashSet::Set(set); - } - true - } - } - SsoHashSet::Set(set) => set.insert(elem), - } + self.map.insert(elem, ()).is_none() } /// Removes a value from the set. Returns whether the value was /// present in the set. + #[inline] pub fn remove(&mut self, value: &Q) -> bool where T: Borrow, Q: Hash + Eq, { - match self { - SsoHashSet::Array(array) => { - if let Some(index) = array.iter().position(|val| val.borrow() == value) { - array.swap_remove(index); - true - } else { - false - } - } - SsoHashSet::Set(set) => set.remove(value), - } + self.map.remove(value).is_some() } /// Returns `true` if the set contains a value. + #[inline] pub fn contains(&self, value: &Q) -> bool where T: Borrow, Q: Hash + Eq, { - match self { - SsoHashSet::Array(array) => array.iter().any(|v| v.borrow() == value), - SsoHashSet::Set(set) => set.contains(value), - } - } -} - -impl Default for SsoHashSet { - fn default() -> Self { - Self::new() + self.map.contains_key(value) } } @@ -257,6 +173,13 @@ impl FromIterator for SsoHashSet { } } +impl Default for SsoHashSet { + #[inline] + fn default() -> Self { + Self::new() + } +} + impl Extend for SsoHashSet { fn extend(&mut self, iter: I) where @@ -267,21 +190,14 @@ impl Extend for SsoHashSet { } } + #[inline] fn extend_one(&mut self, item: T) { self.insert(item); } + #[inline] fn extend_reserve(&mut self, additional: usize) { - match self { - SsoHashSet::Array(array) => { - if array.capacity() < (array.len() + additional) { - let mut set: FxHashSet = array.drain(..).collect(); - set.extend_reserve(additional); - *self = SsoHashSet::Set(set); - } - } - SsoHashSet::Set(set) => set.extend_reserve(additional), - } + self.map.extend_reserve(additional) } } @@ -289,46 +205,42 @@ impl<'a, T> Extend<&'a T> for SsoHashSet where T: 'a + Eq + Hash + Copy, { + #[inline] fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + #[inline] fn extend_one(&mut self, &item: &'a T) { self.insert(item); } + #[inline] fn extend_reserve(&mut self, additional: usize) { Extend::::extend_reserve(self, additional) } } impl IntoIterator for SsoHashSet { - type IntoIter = EitherIter< - as IntoIterator>::IntoIter, - as IntoIterator>::IntoIter, - >; + type IntoIter = std::iter::Map< as IntoIterator>::IntoIter, fn((T, ())) -> T>; type Item = ::Item; + #[inline] fn into_iter(self) -> Self::IntoIter { - match self { - SsoHashSet::Array(array) => EitherIter::Left(array.into_iter()), - SsoHashSet::Set(set) => EitherIter::Right(set.into_iter()), - } + self.map.into_iter().map(entry_to_key) } } impl<'a, T> IntoIterator for &'a SsoHashSet { - type IntoIter = EitherIter< - <&'a ArrayVec<[T; 8]> as IntoIterator>::IntoIter, - <&'a FxHashSet as IntoIterator>::IntoIter, + type IntoIter = std::iter::Map< + <&'a SsoHashMap as IntoIterator>::IntoIter, + fn((&'a T, &'a ())) -> &'a T, >; type Item = ::Item; + #[inline] fn into_iter(self) -> Self::IntoIter { - match self { - SsoHashSet::Array(array) => EitherIter::Left(array.into_iter()), - SsoHashSet::Set(set) => EitherIter::Right(set.into_iter()), - } + self.map.iter().map(entry_to_key) } } -- cgit 1.4.1-3-g733a5 From 92a0668c20b8dea00d8739dce2243113f518b427 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Sun, 27 Sep 2020 23:48:19 -0500 Subject: SsoHashMap minor refactoring, SSO_ARRAY_SIZE introduced --- compiler/rustc_data_structures/src/sso/map.rs | 41 +++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 3089f887845..f466796100c 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -7,6 +7,25 @@ use std::hash::Hash; use std::iter::FromIterator; use std::ops::Index; +// For pointer-sized arguments arrays +// are faster than set/map for up to 64 +// arguments. +// +// On the other hand such a big array +// hurts cache performance, makes passing +// sso structures around very expensive. +// +// Biggest performance benefit is gained +// for reasonably small arrays that stay +// small in vast majority of cases. +// +// '8' is choosen as a sane default, to be +// reevaluated later. +// +// Note: As of now ArrayVec design prevents +// us from making it user-customizable. +const SSO_ARRAY_SIZE: usize = 8; + /// Small-storage-optimized implementation of a map. /// /// Stores elements in a small array up to a certain length @@ -26,7 +45,7 @@ use std::ops::Index; /// Vacant/Occupied entries and related #[derive(Clone)] pub enum SsoHashMap { - Array(ArrayVec<[(K, V); 8]>), + Array(ArrayVec<[(K, V); SSO_ARRAY_SIZE]>), Map(FxHashMap), } @@ -39,9 +58,8 @@ impl SsoHashMap { /// Creates an empty `SsoHashMap` with the specified capacity. pub fn with_capacity(cap: usize) -> Self { - let array = ArrayVec::new(); - if array.capacity() >= cap { - SsoHashMap::Array(array) + if cap <= SSO_ARRAY_SIZE { + Self::new() } else { SsoHashMap::Map(FxHashMap::with_capacity_and_hasher(cap, Default::default())) } @@ -59,7 +77,7 @@ impl SsoHashMap { /// Returns the number of elements the map can hold without reallocating. pub fn capacity(&self) -> usize { match self { - SsoHashMap::Array(array) => array.capacity(), + SsoHashMap::Array(_) => SSO_ARRAY_SIZE, SsoHashMap::Map(map) => map.capacity(), } } @@ -149,7 +167,7 @@ impl SsoHashMap { pub fn reserve(&mut self, additional: usize) { match self { SsoHashMap::Array(array) => { - if array.capacity() < (array.len() + additional) { + if SSO_ARRAY_SIZE < (array.len() + additional) { let mut map: FxHashMap = array.drain(..).collect(); map.reserve(additional); *self = SsoHashMap::Map(map); @@ -164,10 +182,8 @@ impl SsoHashMap { /// and possibly leaving some space in accordance with the resize policy. pub fn shrink_to_fit(&mut self) { if let SsoHashMap::Map(map) = self { - let mut array = ArrayVec::new(); - if map.len() <= array.capacity() { - array.extend(map.drain()); - *self = SsoHashMap::Array(array); + if map.len() <= SSO_ARRAY_SIZE { + *self = SsoHashMap::Array(map.drain().collect()); } else { map.shrink_to_fit(); } @@ -361,7 +377,7 @@ impl Extend<(K, V)> for SsoHashMap { fn extend_reserve(&mut self, additional: usize) { match self { SsoHashMap::Array(array) => { - if array.capacity() < (array.len() + additional) { + if SSO_ARRAY_SIZE < (array.len() + additional) { let mut map: FxHashMap = array.drain(..).collect(); map.extend_reserve(additional); *self = SsoHashMap::Map(map); @@ -517,8 +533,9 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { let index = if let Some(index) = found_index { index } else { + let index = array.len(); array.try_push((self.key, default())).unwrap(); - array.len() - 1 + index }; &mut array[index].1 } -- cgit 1.4.1-3-g733a5 From d061fee177c70ae146db2b9720c85dc1f38215af Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 28 Sep 2020 17:34:27 -0700 Subject: Stable hashing: add comments and tests concerning platform-independence SipHasher128 implements short_write in an endian-independent way, yet its write_xxx Hasher trait methods undo this endian-independence by byte swapping the integer inputs on big-endian hardware. StableHasher then adds endian-independence back by also byte-swapping on big-endian hardware prior to invoking SipHasher128. This double swap may have the appearance of being a no-op, but is in fact by design. In particular, we really do want SipHasher128 to be platform-dependent, in order to be consistent with the libstd SipHasher. Try to clarify this intent. Also, add and update a couple of unit tests. --- compiler/rustc_data_structures/src/sip128.rs | 25 ++++++-- compiler/rustc_data_structures/src/sip128/tests.rs | 56 +++++++++++++---- .../rustc_data_structures/src/stable_hasher.rs | 6 +- .../src/stable_hasher/tests.rs | 73 ++++++++++++++++++++++ 4 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 compiler/rustc_data_structures/src/stable_hasher/tests.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index beb28dd0720..2c4eff618c6 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -125,15 +125,28 @@ impl SipHasher128 { // A specialized write function for values with size <= 8. // - // The hashing of multi-byte integers depends on endianness. E.g.: + // The input must be zero-extended to 64-bits by the caller. This extension + // isn't hashed, but the implementation requires it for correctness. + // + // This function, given the same integer size and value, has the same effect + // on both little- and big-endian hardware. It operates on values without + // depending on their sequence in memory, so is independent of endianness. + // + // However, we want SipHasher128 to be platform-dependent, in order to be + // consistent with the platform-dependent SipHasher in libstd. In other + // words, we want: + // // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])` // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])` // - // This function does the right thing for little-endian hardware. On - // big-endian hardware `x` must be byte-swapped first to give the right - // behaviour. After any byte-swapping, the input must be zero-extended to - // 64-bits. The caller is responsible for the byte-swapping and - // zero-extension. + // Therefore, in order to produce endian-dependent results, SipHasher128's + // `write_xxx` Hasher trait methods byte-swap `x` prior to zero-extending. + // + // If clients of SipHasher128 itself want platform-independent results, they + // *also* must byte-swap integer inputs before invoking the `write_xxx` + // methods on big-endian hardware (that is, two byte-swaps must occur--one + // in the client, and one in SipHasher128). Additionally, they must extend + // `usize` and `isize` types to 64 bits on 32-bit systems. #[inline] fn short_write(&mut self, _x: T, x: u64) { let size = mem::size_of::(); diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs index 80b7fc74756..2e2274a7b77 100644 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -1,7 +1,6 @@ use super::*; use std::hash::{Hash, Hasher}; -use std::{mem, slice}; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -399,20 +398,55 @@ fn test_hash_no_concat_alias() { } #[test] -fn test_write_short_works() { - let test_usize = 0xd0c0b0a0usize; +fn test_short_write_works() { + let test_u8 = 0xFF_u8; + let test_u16 = 0x1122_u16; + let test_u32 = 0x22334455_u32; + let test_u64 = 0x33445566_778899AA_u64; + let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -1_i8; + let test_i16 = -2_i16; + let test_i32 = -3_i32; + let test_i64 = -4_i64; + let test_i128 = -5_i128; + let test_isize = -6_isize; + let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write_usize(test_usize); h1.write(b"bytes"); h1.write(b"string"); - h1.write_u8(0xFFu8); - h1.write_u8(0x01u8); + h1.write_u8(test_u8); + h1.write_u16(test_u16); + h1.write_u32(test_u32); + h1.write_u64(test_u64); + h1.write_u128(test_u128); + h1.write_usize(test_usize); + h1.write_i8(test_i8); + h1.write_i16(test_i16); + h1.write_i32(test_i32); + h1.write_i64(test_i64); + h1.write_i128(test_i128); + h1.write_isize(test_isize); + let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(unsafe { - slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) - }); h2.write(b"bytes"); h2.write(b"string"); - h2.write(&[0xFFu8, 0x01u8]); - assert_eq!(h1.finish128(), h2.finish128()); + h2.write(&test_u8.to_ne_bytes()); + h2.write(&test_u16.to_ne_bytes()); + h2.write(&test_u32.to_ne_bytes()); + h2.write(&test_u64.to_ne_bytes()); + h2.write(&test_u128.to_ne_bytes()); + h2.write(&test_usize.to_ne_bytes()); + h2.write(&test_i8.to_ne_bytes()); + h2.write(&test_i16.to_ne_bytes()); + h2.write(&test_i32.to_ne_bytes()); + h2.write(&test_i64.to_ne_bytes()); + h2.write(&test_i128.to_ne_bytes()); + h2.write(&test_isize.to_ne_bytes()); + + let h1_hash = h1.finish128(); + let h2_hash = h2.finish128(); + + assert_eq!(h1_hash, h2_hash); } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index c1c79b174f4..68875b3fbde 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -5,6 +5,9 @@ use smallvec::SmallVec; use std::hash::{BuildHasher, Hash, Hasher}; use std::mem; +#[cfg(test)] +mod tests; + /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors /// like what architecture you're compiling *from*. @@ -129,7 +132,8 @@ impl Hasher for StableHasher { fn write_isize(&mut self, i: isize) { // Always treat isize as i64 so we get the same results on 32 and 64 bit // platforms. This is important for symbol hashes when cross compiling, - // for example. + // for example. Sign extending here is preferable as it means that the + // same negative number hashes the same on both 32 and 64 bit platforms. self.state.write_i64((i as i64).to_le()); } } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs new file mode 100644 index 00000000000..cd6ff96a555 --- /dev/null +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -0,0 +1,73 @@ +use super::*; + +// The tests below compare the computed hashes to particular expected values +// in order to test that we produce the same results on different platforms, +// regardless of endianness and `usize` and `isize` size differences (this +// of course assumes we run these tests on platforms that differ in those +// ways). The expected values depend on the hashing algorithm used, so they +// need to be updated whenever StableHasher changes its hashing algorithm. + +#[test] +fn test_hash_integers() { + // Test that integers are handled consistently across platforms. + let test_u8 = 0xAB_u8; + let test_u16 = 0xFFEE_u16; + let test_u32 = 0x445577AA_u32; + let test_u64 = 0x01234567_13243546_u64; + let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -100_i8; + let test_i16 = -200_i16; + let test_i32 = -300_i32; + let test_i64 = -400_i64; + let test_i128 = -500_i128; + let test_isize = -600_isize; + + let mut h = StableHasher::new(); + test_u8.hash(&mut h); + test_u16.hash(&mut h); + test_u32.hash(&mut h); + test_u64.hash(&mut h); + test_u128.hash(&mut h); + test_usize.hash(&mut h); + test_i8.hash(&mut h); + test_i16.hash(&mut h); + test_i32.hash(&mut h); + test_i64.hash(&mut h); + test_i128.hash(&mut h); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (2736651863462566372, 8121090595289675650); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_usize() { + // Test that usize specifically is handled consistently across platforms. + let test_usize = 0xABCDEF01_usize; + + let mut h = StableHasher::new(); + test_usize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (5798740672699530587, 11186240177685111648); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_isize() { + // Test that isize specifically is handled consistently across platforms. + let test_isize = -7_isize; + + let mut h = StableHasher::new(); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (14721296605626097289, 11385941877786388409); + + assert_eq!(h.finalize(), expected); +} -- cgit 1.4.1-3-g733a5 From d1d2184db407dbdc0a0872c9efb4ff58457e1c9a Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Fri, 2 Oct 2020 20:13:21 -0500 Subject: SsoHashSet/Map - genericiy over Q removed Due to performance regression, see SsoHashMap comment. --- compiler/rustc_data_structures/src/sso/map.rs | 108 +++++++++++++------------- compiler/rustc_data_structures/src/sso/set.rs | 53 +++++-------- 2 files changed, 72 insertions(+), 89 deletions(-) (limited to 'compiler/rustc_data_structures/src') diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index f466796100c..fa510e58314 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,7 +1,6 @@ use super::either_iter::EitherIter; use crate::fx::FxHashMap; use arrayvec::ArrayVec; -use std::borrow::Borrow; use std::fmt; use std::hash::Hash; use std::iter::FromIterator; @@ -30,19 +29,45 @@ const SSO_ARRAY_SIZE: usize = 8; /// /// Stores elements in a small array up to a certain length /// and switches to `HashMap` when that length is exceeded. -/// -/// Implements subset of HashMap API. -/// -/// Missing HashMap API: -/// all hasher-related -/// try_reserve (unstable) -/// shrink_to (unstable) -/// drain_filter (unstable) -/// into_keys/into_values (unstable) -/// all raw_entry-related -/// PartialEq/Eq (requires sorting the array) -/// Entry::or_insert_with_key (unstable) -/// Vacant/Occupied entries and related +// +// FIXME: Implements subset of HashMap API. +// +// Missing HashMap API: +// all hasher-related +// try_reserve (unstable) +// shrink_to (unstable) +// drain_filter (unstable) +// into_keys/into_values (unstable) +// all raw_entry-related +// PartialEq/Eq (requires sorting the array) +// Entry::or_insert_with_key (unstable) +// Vacant/Occupied entries and related +// +// FIXME: In HashMap most methods accepting key reference +// accept reference to generic `Q` where `K: Borrow`. +// +// However, using this approach in `HashMap::get` apparently +// breaks inlining and noticeably reduces performance. +// +// Performance *should* be the same given that borrow is +// a NOP in most cases, but in practice that's not the case. +// +// Further investigation is required. +// +// Affected methods: +// SsoHashMap::get +// SsoHashMap::get_mut +// SsoHashMap::get_entry +// SsoHashMap::get_key_value +// SsoHashMap::contains_key +// SsoHashMap::remove +// SsoHashMap::remove_entry +// Index::index +// SsoHashSet::take +// SsoHashSet::get +// SsoHashSet::remove +// SsoHashSet::contains + #[derive(Clone)] pub enum SsoHashMap { Array(ArrayVec<[(K, V); SSO_ARRAY_SIZE]>), @@ -232,14 +257,10 @@ impl SsoHashMap { /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. - pub fn remove(&mut self, key: &Q) -> Option - where - K: Borrow, - Q: Hash + Eq, - { + pub fn remove(&mut self, key: &K) -> Option { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k.borrow() == key) { + if let Some(index) = array.iter().position(|(k, _v)| k == key) { Some(array.swap_remove(index).1) } else { None @@ -251,14 +272,10 @@ impl SsoHashMap { /// Removes a key from the map, returning the stored key and value if the /// key was previously in the map. - pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> - where - K: Borrow, - Q: Hash + Eq, - { + pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k.borrow() == key) { + if let Some(index) = array.iter().position(|(k, _v)| k == key) { Some(array.swap_remove(index)) } else { None @@ -269,15 +286,11 @@ impl SsoHashMap { } /// Returns a reference to the value corresponding to the key. - pub fn get(&self, key: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq, - { + pub fn get(&self, key: &K) -> Option<&V> { match self { SsoHashMap::Array(array) => { for (k, v) in array { - if k.borrow() == key { + if k == key { return Some(v); } } @@ -288,15 +301,11 @@ impl SsoHashMap { } /// Returns a mutable reference to the value corresponding to the key. - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq, - { + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { match self { SsoHashMap::Array(array) => { for (k, v) in array { - if (*k).borrow() == key { + if k == key { return Some(v); } } @@ -307,15 +316,11 @@ impl SsoHashMap { } /// Returns the key-value pair corresponding to the supplied key. - pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> - where - K: Borrow, - Q: Hash + Eq, - { + pub fn get_key_value(&self, key: &K) -> Option<(&K, &V)> { match self { SsoHashMap::Array(array) => { for (k, v) in array { - if k.borrow() == key { + if k == key { return Some((k, v)); } } @@ -326,13 +331,9 @@ impl SsoHashMap { } /// Returns `true` if the map contains a value for the specified key. - pub fn contains_key(&self, key: &Q) -> bool - where - K: Borrow, - Q: Hash + Eq, - { + pub fn contains_key(&self, key: &K) -> bool { match self { - SsoHashMap::Array(array) => array.iter().any(|(k, _v)| k.borrow() == key), + SsoHashMap::Array(array) => array.iter().any(|(k, _v)| k == key), SsoHashMap::Map(map) => map.contains_key(key), } } @@ -483,15 +484,14 @@ where } } -impl<'a, K, Q: ?Sized, V> Index<&'a Q> for SsoHashMap +impl<'a, K, V> Index<&'a K> for SsoHashMap where - K: Eq + Hash + Borrow, - Q: Eq + Hash, + K: Eq + Hash, { type Output = V; #[inline] - fn index(&self, key: &Q) -> &V { + fn index(&self, key: &K) -> &V { self.get(key).expect("no entry found for key") } } diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index 353529b0598..23cff0206c5 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::fmt; use std::hash::Hash; use std::iter::FromIterator; @@ -9,20 +8,20 @@ use super::map::SsoHashMap; /// /// Stores elements in a small array up to a certain length /// and switches to `HashSet` when that length is exceeded. -/// -/// Implements subset of HashSet API. -/// -/// Missing HashSet API: -/// all hasher-related -/// try_reserve (unstable) -/// shrink_to (unstable) -/// drain_filter (unstable) -/// replace -/// get_or_insert/get_or_insert_owned/get_or_insert_with (unstable) -/// difference/symmetric_difference/intersection/union -/// is_disjoint/is_subset/is_superset -/// PartialEq/Eq (requires SsoHashMap implementation) -/// BitOr/BitAnd/BitXor/Sub +// +// FIXME: Implements subset of HashSet API. +// +// Missing HashSet API: +// all hasher-related +// try_reserve (unstable) +// shrink_to (unstable) +// drain_filter (unstable) +// replace +// get_or_insert/get_or_insert_owned/get_or_insert_with (unstable) +// difference/symmetric_difference/intersection/union +// is_disjoint/is_subset/is_superset +// PartialEq/Eq (requires SsoHashMap implementation) +// BitOr/BitAnd/BitXor/Sub #[derive(Clone)] pub struct SsoHashSet { map: SsoHashMap, @@ -115,21 +114,13 @@ impl SsoHashSet { /// Removes and returns the value in the set, if any, that is equal to the given one. #[inline] - pub fn take(&mut self, value: &Q) -> Option - where - T: Borrow, - Q: Hash + Eq, - { + pub fn take(&mut self, value: &T) -> Option { self.map.remove_entry(value).map(entry_to_key) } /// Returns a reference to the value in the set, if any, that is equal to the given value. #[inline] - pub fn get(&self, value: &Q) -> Option<&T> - where - T: Borrow, - Q: Hash + Eq, - { + pub fn get(&self, value: &T) -> Option<&T> { self.map.get_key_value(value).map(entry_to_key) } @@ -146,21 +137,13 @@ impl SsoHashSet { /// Removes a value from the set. Returns whether the value was /// present in the set. #[inline] - pub fn remove(&mut self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { + pub fn remove(&mut self, value: &T) -> bool { self.map.remove(value).is_some() } /// Returns `true` if the set contains a value. #[inline] - pub fn contains(&self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { + pub fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } } -- cgit 1.4.1-3-g733a5 From f5aebad28fe69f53497ce0107103c6d5d37b25dc Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 1 Sep 2020 16:15:17 -0700 Subject: Updates to experimental coverage counter injection This is a combination of 18 commits. Commit #2: Additional examples and some small improvements. Commit #3: fixed mir-opt non-mir extensions and spanview title elements Corrected a fairly recent assumption in runtest.rs that all MIR dump files end in .mir. (It was appending .mir to the graphviz .dot and spanview .html file names when generating blessed output files. That also left outdated files in the baseline alongside the files with the incorrect names, which I've now removed.) Updated spanview HTML title elements to match their content, replacing a hardcoded and incorrect name that was left in accidentally when originally submitted. Commit #4: added more test examples also improved Makefiles with support for non-zero exit status and to force validation of tests unless a specific test overrides it with a specific comment. Commit #5: Fixed rare issues after testing on real-world crate Commit #6: Addressed PR feedback, and removed temporary -Zexperimental-coverage -Zinstrument-coverage once again supports the latest capabilities of LLVM instrprof coverage instrumentation. Also fixed a bug in spanview. Commit #7: Fix closure handling, add tests for closures and inner items And cleaned up other tests for consistency, and to make it more clear where spans start/end by breaking up lines. Commit #8: renamed "typical" test results "expected" Now that the `llvm-cov show` tests are improved to normally expect matching actuals, and to allow individual tests to override that expectation. Commit #9: test coverage of inline generic struct function Commit #10: Addressed review feedback * Removed unnecessary Unreachable filter. * Replaced a match wildcard with remining variants. * Added more comments to help clarify the role of successors() in the CFG traversal Commit #11: refactoring based on feedback * refactored `fn coverage_spans()`. * changed the way I expand an empty coverage span to improve performance * fixed a typo that I had accidently left in, in visit.rs Commit #12: Optimized use of SourceMap and SourceFile Commit #13: Fixed a regression, and synched with upstream Some generated test file names changed due to some new change upstream. Commit #14: Stripping out crate disambiguators from demangled names These can vary depending on the test platform. Commit #15: Ignore llvm-cov show diff on test with generics, expand IO error message Tests with generics produce llvm-cov show results with demangled names that can include an unstable "crate disambiguator" (hex value). The value changes when run in the Rust CI Windows environment. I added a sed filter to strip them out (in a prior commit), but sed also appears to fail in the same environment. Until I can figure out a workaround, I'm just going to ignore this specific test result. I added a FIXME to follow up later, but it's not that critical. I also saw an error with Windows GNU, but the IO error did not specify a path for the directory or file that triggered the error. I updated the error messages to provide more info for next, time but also noticed some other tests with similar steps did not fail. Looks spurious. Commit #16: Modify rust-demangler to strip disambiguators by default Commit #17: Remove std::process::exit from coverage tests Due to Issue #77553, programs that call std::process::exit() do not generate coverage results on Windows MSVC. Commit #18: fix: test file paths exceeding Windows max path len --- Cargo.lock | 3 +- .../rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 1 + compiler/rustc_codegen_ssa/src/coverageinfo/map.rs | 13 +- .../src/graph/dominators/mod.rs | 9 + compiler/rustc_middle/src/mir/coverage/mod.rs | 19 + compiler/rustc_middle/src/mir/visit.rs | 2 +- .../rustc_mir/src/transform/instrument_coverage.rs | 1228 +++++- compiler/rustc_mir/src/util/pretty.rs | 81 +- compiler/rustc_mir/src/util/spanview.rs | 59 +- compiler/rustc_session/src/config.rs | 4 - compiler/rustc_session/src/options.rs | 5 - compiler/rustc_span/src/lib.rs | 84 + compiler/rustc_span/src/source_map.rs | 79 +- src/test/mir-opt/graphviz.main.mir_map.0.dot | 5 +- src/test/mir-opt/graphviz.main.mir_map.0.dot.mir | 7 - ...instrument_coverage.bar.InstrumentCoverage.diff | 2 +- ...nstrument_coverage.main.InstrumentCoverage.diff | 3 +- .../mir-opt/spanview_block.main.mir_map.0.html | 9 +- .../mir-opt/spanview_block.main.mir_map.0.html.mir | 66 - .../mir-opt/spanview_statement.main.mir_map.0.html | 11 +- .../spanview_statement.main.mir_map.0.html.mir | 66 - .../spanview_terminator.main.mir_map.0.html | 11 +- .../spanview_terminator.main.mir_map.0.html.mir | 65 - .../instrument-coverage-cov-reports-base/Makefile | 33 +- .../expected_export_coverage.closure.json | 59 + ...pected_export_coverage.coverage_of_if_else.json | 59 - .../expected_export_coverage.drop_trait.json | 59 + .../expected_export_coverage.generics.json | 59 + .../expected_export_coverage.if.json | 59 + .../expected_export_coverage.if_else.json | 59 + .../expected_export_coverage.inner_items.json | 59 + .../expected_export_coverage.lazy_boolean.json | 59 + .../expected_export_coverage.loop_break_value.json | 59 + ...export_coverage.question_mark_error_result.json | 59 + .../expected_export_coverage.simple_loop.json | 59 + .../expected_export_coverage.simple_match.json | 59 + ...xpected_export_coverage.various_conditions.json | 59 + ...xpected_export_coverage.while_early_return.json | 59 + .../expected_show_coverage.closure.txt | 94 + .../expected_show_coverage.drop_trait.txt | 34 + .../expected_show_coverage.generics.txt | 67 + .../expected_show_coverage.if.txt | 29 + .../expected_show_coverage.if_else.txt | 41 + .../expected_show_coverage.inner_items.txt | 58 + .../expected_show_coverage.lazy_boolean.txt | 44 + .../expected_show_coverage.loop_break_value.txt | 14 + ...ed_show_coverage.question_mark_error_result.txt | 36 + .../expected_show_coverage.simple_loop.txt | 36 + .../expected_show_coverage.simple_match.txt | 44 + .../expected_show_coverage.various_conditions.txt | 69 + .../expected_show_coverage.while_early_return.txt | 48 + .../typical_show_coverage.coverage_of_if_else.txt | 64 - .../expected_export_coverage.closure.json | 59 + ...pected_export_coverage.coverage_of_if_else.json | 59 - .../expected_export_coverage.drop_trait.json | 59 + .../expected_export_coverage.generics.json | 59 + .../expected_export_coverage.if.json | 59 + .../expected_export_coverage.if_else.json | 59 + .../expected_export_coverage.inner_items.json | 59 + .../expected_export_coverage.lazy_boolean.json | 59 + .../expected_export_coverage.loop_break_value.json | 59 + ...export_coverage.question_mark_error_result.json | 59 + .../expected_export_coverage.simple_loop.json | 59 + .../expected_export_coverage.simple_match.json | 59 + ...xpected_export_coverage.various_conditions.json | 59 + ...xpected_export_coverage.while_early_return.json | 59 + .../expected_show_coverage.closure.txt | 94 + .../expected_show_coverage.drop_trait.txt | 34 + .../expected_show_coverage.generics.txt | 67 + .../expected_show_coverage.if.txt | 29 + .../expected_show_coverage.if_else.txt | 41 + .../expected_show_coverage.inner_items.txt | 58 + .../expected_show_coverage.lazy_boolean.txt | 44 + .../expected_show_coverage.loop_break_value.txt | 14 + ...ed_show_coverage.question_mark_error_result.txt | 36 + .../expected_show_coverage.simple_loop.txt | 36 + .../expected_show_coverage.simple_match.txt | 44 + .../expected_show_coverage.various_conditions.txt | 69 + .../expected_show_coverage.while_early_return.txt | 48 + .../typical_show_coverage.coverage_of_if_else.txt | 64 - .../Makefile | 2 +- .../instrument-coverage-mir-cov-html-base/Makefile | 7 +- ...n-{closure#0}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#1}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#2}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#3}.-------.InstrumentCoverage.0.html | 82 + .../closure.main.-------.InstrumentCoverage.0.html | 4505 ++++++++++++++++++++ ..._if_else.main.-------.InstrumentCoverage.0.html | 641 --- ...op_trait.main.-------.InstrumentCoverage.0.html | 119 + ...{impl#0}-drop.-------.InstrumentCoverage.0.html | 123 + ...generics.main.-------.InstrumentCoverage.0.html | 167 + ...-set_strength.-------.InstrumentCoverage.0.html | 75 + ...{impl#1}-drop.-------.InstrumentCoverage.0.html | 123 + .../if.main.-------.InstrumentCoverage.0.html | 162 + .../if_else.main.-------.InstrumentCoverage.0.html | 163 + ...lt_trait_func.-------.InstrumentCoverage.0.html | 83 + ...nner_function.-------.InstrumentCoverage.0.html | 107 + ...er_trait_func.-------.InstrumentCoverage.0.html | 72 + ...er_items.main.-------.InstrumentCoverage.0.html | 171 + ..._boolean.main.-------.InstrumentCoverage.0.html | 160 + ...ak_value.main.-------.InstrumentCoverage.0.html | 118 + ...r_result.call.-------.InstrumentCoverage.0.html | 73 + ...r_result.main.-------.InstrumentCoverage.0.html | 101 + ...ple_loop.main.-------.InstrumentCoverage.0.html | 127 + ...le_match.main.-------.InstrumentCoverage.0.html | 190 + ...nditions.main.-------.InstrumentCoverage.0.html | 228 + ...y_return.main.-------.InstrumentCoverage.0.html | 119 + .../Makefile | 2 +- ...n-{closure#0}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#1}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#2}.-------.InstrumentCoverage.0.html | 82 + ...n-{closure#3}.-------.InstrumentCoverage.0.html | 82 + .../closure.main.-------.InstrumentCoverage.0.html | 4505 ++++++++++++++++++++ ..._if_else.main.-------.InstrumentCoverage.0.html | 641 --- ...op_trait.main.-------.InstrumentCoverage.0.html | 119 + ...{impl#0}-drop.-------.InstrumentCoverage.0.html | 123 + ...generics.main.-------.InstrumentCoverage.0.html | 167 + ...-set_strength.-------.InstrumentCoverage.0.html | 75 + ...{impl#1}-drop.-------.InstrumentCoverage.0.html | 123 + .../if.main.-------.InstrumentCoverage.0.html | 162 + .../if_else.main.-------.InstrumentCoverage.0.html | 163 + ...lt_trait_func.-------.InstrumentCoverage.0.html | 83 + ...nner_function.-------.InstrumentCoverage.0.html | 107 + ...er_trait_func.-------.InstrumentCoverage.0.html | 72 + ...er_items.main.-------.InstrumentCoverage.0.html | 171 + ..._boolean.main.-------.InstrumentCoverage.0.html | 160 + ...ak_value.main.-------.InstrumentCoverage.0.html | 118 + ...r_result.call.-------.InstrumentCoverage.0.html | 73 + ...r_result.main.-------.InstrumentCoverage.0.html | 101 + ...ple_loop.main.-------.InstrumentCoverage.0.html | 127 + ...le_match.main.-------.InstrumentCoverage.0.html | 190 + ...nditions.main.-------.InstrumentCoverage.0.html | 228 + ...y_return.main.-------.InstrumentCoverage.0.html | 119 + .../instrument-coverage/closure.rs | 93 + .../instrument-coverage/compiletest-ignore-dir | 2 +- .../instrument-coverage/coverage_of_if_else.rs | 51 - .../instrument-coverage/drop_trait.rs | 33 + .../instrument-coverage/generics.rs | 44 + .../run-make-fulldeps/instrument-coverage/if.rs | 28 + .../instrument-coverage/if_else.rs | 40 + .../instrument-coverage/inner_items.rs | 57 + .../instrument-coverage/lazy_boolean.rs | 43 + .../instrument-coverage/loop_break_value.rs | 13 + .../question_mark_error_result.rs | 35 + .../instrument-coverage/simple_loop.rs | 35 + .../instrument-coverage/simple_match.rs | 43 + .../instrument-coverage/various_conditions.rs | 67 + .../instrument-coverage/while_early_return.rs | 47 + src/tools/compiletest/src/runtest.rs | 14 +- src/tools/rust-demangler/Cargo.toml | 3 +- src/tools/rust-demangler/main.rs | 41 +- 151 files changed, 19306 insertions(+), 2177 deletions(-) delete mode 100644 src/test/mir-opt/graphviz.main.mir_map.0.dot.mir delete mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html.mir delete mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir delete mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.closure.json delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.drop_trait.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.generics.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if_else.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.inner_items.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.lazy_boolean.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.loop_break_value.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.question_mark_error_result.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_loop.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_match.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.various_conditions.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.while_early_return.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.closure.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.drop_trait.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.generics.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.inner_items.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.lazy_boolean.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.loop_break_value.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.question_mark_error_result.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_loop.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_match.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.various_conditions.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.while_early_return.txt delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.closure.json delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.drop_trait.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.generics.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if_else.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.inner_items.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.lazy_boolean.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.loop_break_value.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.question_mark_error_result.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_loop.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_match.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.various_conditions.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.while_early_return.json create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.closure.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.drop_trait.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.generics.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.inner_items.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.lazy_boolean.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.loop_break_value.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.question_mark_error_result.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_loop.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_match.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.various_conditions.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.while_early_return.txt delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/instrument-coverage/closure.rs delete mode 100644 src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/drop_trait.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/generics.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/if.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/if_else.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/inner_items.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/lazy_boolean.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/loop_break_value.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/question_mark_error_result.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/simple_loop.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/simple_match.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/various_conditions.rs create mode 100644 src/test/run-make-fulldeps/instrument-coverage/while_early_return.rs (limited to 'compiler/rustc_data_structures/src') diff --git a/Cargo.lock b/Cargo.lock index fd27f053638..d216b09c66a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2938,8 +2938,9 @@ dependencies = [ [[package]] name = "rust-demangler" -version = "0.0.0" +version = "0.0.1" dependencies = [ + "regex", "rustc-demangle", ] diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ec6c177614d..0098555a373 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -126,6 +126,7 @@ impl CoverageMapGenerator { let (filenames_index, _) = self.filenames.insert_full(c_filename); virtual_file_mapping.push(filenames_index as u32); } + debug!("Adding counter {:?} to map for {:?}", counter, region,); mapping_regions.push(CounterMappingRegion::code_region( counter, current_file_id, diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index 814e43c5fa5..d8bde8ee705 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -143,7 +143,9 @@ impl FunctionCoverage { let id_to_counter = |new_indexes: &IndexVec, id: ExpressionOperandId| { - if id.index() < self.counters.len() { + if id == ExpressionOperandId::ZERO { + Some(Counter::zero()) + } else if id.index() < self.counters.len() { let index = CounterValueReference::from(id.index()); self.counters .get(index) @@ -179,14 +181,19 @@ impl FunctionCoverage { // been assigned a `new_index`. let mapped_expression_index = MappedExpressionIndex::from(counter_expressions.len()); - counter_expressions.push(CounterExpression::new( + let expression = CounterExpression::new( lhs_counter, match op { Op::Add => ExprKind::Add, Op::Subtract => ExprKind::Subtract, }, rhs_counter, - )); + ); + debug!( + "Adding expression {:?} = {:?} at {:?}", + mapped_expression_index, expression, region + ); + counter_expressions.push(expression); new_indexes[original_index] = mapped_expression_index; expression_regions.push((Counter::expression(mapped_expression_index), region)); } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 438a0d0c6ff..1cfbce2355e 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -9,6 +9,7 @@ use super::iterate::reverse_post_order; use super::ControlFlowGraph; use rustc_index::vec::{Idx, IndexVec}; use std::borrow::BorrowMut; +use std::cmp::Ordering; #[cfg(test)] mod tests; @@ -108,6 +109,14 @@ impl Dominators { // FIXME -- could be optimized by using post-order-rank self.dominators(node).any(|n| n == dom) } + + /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator + /// relationship, the dominator will always precede the dominated. (The relative ordering + /// of two unrelated nodes will also be consistent, but otherwise the order has no + /// meaning.) This method cannot be used to determine if either Node dominates the other. + pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option { + self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs]) + } } pub struct Iter<'dom, Node: Idx> { diff --git a/compiler/rustc_middle/src/mir/coverage/mod.rs b/compiler/rustc_middle/src/mir/coverage/mod.rs index ce311c2ee52..0421eabc2dc 100644 --- a/compiler/rustc_middle/src/mir/coverage/mod.rs +++ b/compiler/rustc_middle/src/mir/coverage/mod.rs @@ -14,6 +14,20 @@ rustc_index::newtype_index! { } } +impl ExpressionOperandId { + /// An expression operand for a "zero counter", as described in the following references: + /// + /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter + /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag + /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions + /// + /// This operand can be used to count two or more separate code regions with a single counter, + /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for + /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in + /// the coverage map for the other code regions. + pub const ZERO: Self = Self::from_u32(0); +} + rustc_index::newtype_index! { pub struct CounterValueReference { derive [HashStable] @@ -22,6 +36,11 @@ rustc_index::newtype_index! { } } +impl CounterValueReference { + // Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO. + pub const START: Self = Self::from_u32(1); +} + rustc_index::newtype_index! { pub struct InjectedExpressionIndex { derive [HashStable] diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index a008bd5f75f..c1f8d22c2c6 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -752,7 +752,7 @@ macro_rules! make_mir_visitor { } fn super_coverage(&mut self, - _kind: & $($mutability)? Coverage, + _coverage: & $($mutability)? Coverage, _location: Location) { } diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index 388fb90651c..babe10a0f14 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -1,26 +1,34 @@ use crate::transform::MirPass; use crate::util::pretty; -use crate::util::spanview::{ - source_range_no_file, statement_kind_name, terminator_kind_name, write_spanview_document, - SpanViewable, TOOLTIP_INDENT, -}; +use crate::util::spanview::{self, SpanViewable}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::Lrc; use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; use rustc_middle::hir; +use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ich::StableHashingContext; use rustc_middle::mir; use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Coverage, CoverageInfo, Location, Statement, StatementKind, - TerminatorKind, + AggregateKind, BasicBlock, BasicBlockData, Coverage, CoverageInfo, FakeReadCause, Location, + Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; -use rustc_span::{FileName, Pos, RealFileName, Span, Symbol}; +use rustc_span::source_map::original_sp; +use rustc_span::{ + BytePos, CharPos, FileName, Pos, RealFileName, SourceFile, Span, Symbol, SyntaxContext, +}; + +use std::cmp::Ordering; + +const ID_SEPARATOR: &str = ","; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -33,6 +41,21 @@ pub(crate) fn provide(providers: &mut Providers) { providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); } +/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in +/// other words, the number of counter value references injected into the MIR (plus 1 for the +/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected +/// counters have a counter ID from `1..num_counters-1`. +/// +/// `num_expressions` is the number of counter expressions added to the MIR body. +/// +/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend +/// code generate, to lookup counters and expressions by simple u32 indexes. +/// +/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code +/// including injected counters. (It is OK if some counters are optimized out, but those counters +/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the +/// calls may not work; but computing the number of counters or expressions by adding `1` to the +/// highest ID (for a given instrumented function) is valid. struct CoverageVisitor { info: CoverageInfo, } @@ -57,15 +80,6 @@ impl Visitor<'_> for CoverageVisitor { fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo { let mir_body = tcx.optimized_mir(def_id); - // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected - // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization - // may split and duplicate some BasicBlock sequences. Simply counting the calls may not - // work; but computing the num_counters by adding `1` to the highest counter_id (for a given - // instrumented function) is valid. - // - // `num_expressions` is the number of counter expressions added to the MIR body. Both - // `num_counters` and `num_expressions` are used to initialize new vectors, during backend - // code generate, to lookup counters and expressions by simple u32 indexes. let mut coverage_visitor = CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; @@ -77,25 +91,399 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { // If the InstrumentCoverage pass is called on promoted MIRs, skip them. // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 - if mir_body.source.promoted.is_none() { - Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); + if mir_body.source.promoted.is_some() { + trace!( + "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)", + mir_body.source.def_id() + ); + return; } + + let hir_id = tcx.hir().local_def_id_to_hir_id(mir_body.source.def_id().expect_local()); + let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + + // Only instrument functions, methods, and closures (not constants since they are evaluated + // at compile time by Miri). + // FIXME(#73156): Handle source code coverage in const eval + if !is_fn_like { + trace!( + "InstrumentCoverage skipped for {:?} (not an FnLikeNode)", + mir_body.source.def_id(), + ); + return; + } + // FIXME(richkadel): By comparison, the MIR pass `ConstProp` includes associated constants, + // with functions, methods, and closures. I assume Miri is used for associated constants as + // well. If not, we may need to include them here too. + + trace!("InstrumentCoverage starting for {:?}", mir_body.source.def_id()); + Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); + trace!("InstrumentCoverage starting for {:?}", mir_body.source.def_id()); } } -#[derive(Clone)] -struct CoverageRegion { - pub span: Span, +/// A BasicCoverageBlock (BCB) represents the maximal-length sequence of CFG (MIR) BasicBlocks +/// without conditional branches. +/// +/// The BCB allows coverage analysis to be performed on a simplified projection of the underlying +/// MIR CFG, without altering the original CFG. Note that running the MIR `SimplifyCfg` transform, +/// is not sufficient, and therefore not necessary, since the BCB-based CFG projection is a more +/// aggressive simplification. For example: +/// +/// * The BCB CFG projection ignores (trims) branches not relevant to coverage, such as unwind- +/// related code that is injected by the Rust compiler but has no physical source code to +/// count. This also means a BasicBlock with a `Call` terminator can be merged into its +/// primary successor target block, in the same BCB. +/// * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are +/// not relevant to coverage analysis. `FalseUnwind`, for example, can be treated the same as +/// a `Goto`, and merged with its successor into the same BCB. +/// +/// Each BCB with at least one computed `CoverageSpan` will have no more than one `Counter`. +/// In some cases, a BCB's execution count can be computed by `CounterExpression`. Additional +/// disjoint `CoverageSpan`s in a BCB can also be counted by `CounterExpression` (by adding `ZERO` +/// to the BCB's primary counter or expression). +/// +/// Dominator/dominated relationships (which are fundamental to the coverage analysis algorithm) +/// between two BCBs can be computed using the `mir::Body` `dominators()` with any `BasicBlock` +/// member of each BCB. (For consistency, BCB's use the first `BasicBlock`, also referred to as the +/// `bcb_leader_bb`.) +/// +/// The BCB CFG projection is critical to simplifying the coverage analysis by ensuring graph +/// path-based queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch +/// (control flow) significance. +#[derive(Debug, Clone)] +struct BasicCoverageBlock { pub blocks: Vec, } +impl BasicCoverageBlock { + pub fn leader_bb(&self) -> BasicBlock { + self.blocks[0] + } + + pub fn id(&self) -> String { + format!( + "@{}", + self.blocks + .iter() + .map(|bb| bb.index().to_string()) + .collect::>() + .join(ID_SEPARATOR) + ) + } +} + +struct BasicCoverageBlocks { + vec: IndexVec>, +} + +impl BasicCoverageBlocks { + pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self { + let mut basic_coverage_blocks = + BasicCoverageBlocks { vec: IndexVec::from_elem_n(None, mir_body.basic_blocks().len()) }; + basic_coverage_blocks.extract_from_mir(mir_body); + basic_coverage_blocks + } + + pub fn iter(&self) -> impl Iterator { + self.vec.iter().filter_map(|option| option.as_ref()) + } + + fn extract_from_mir(&mut self, mir_body: &mir::Body<'tcx>) { + // Traverse the CFG but ignore anything following an `unwind` + let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| { + let mut successors = term_kind.successors(); + match &term_kind { + // SwitchInt successors are never unwind, and all of them should be traversed. + + // NOTE: TerminatorKind::FalseEdge targets from SwitchInt don't appear to be + // helpful in identifying unreachable code. I did test the theory, but the following + // changes were not beneficial. (I assumed that replacing some constants with + // non-deterministic variables might effect which blocks were targeted by a + // `FalseEdge` `imaginary_target`. It did not.) + // + // Also note that, if there is a way to identify BasicBlocks that are part of the + // MIR CFG, but not actually reachable, here are some other things to consider: + // + // Injecting unreachable code regions will probably require computing the set + // difference between the basic blocks found without filtering out unreachable + // blocks, and the basic blocks found with the filter; then computing the + // `CoverageSpans` without the filter; and then injecting `Counter`s or + // `CounterExpression`s for blocks that are not unreachable, or injecting + // `Unreachable` code regions otherwise. This seems straightforward, but not + // trivial. + // + // Alternatively, we might instead want to leave the unreachable blocks in + // (bypass the filter here), and inject the counters. This will result in counter + // values of zero (0) for unreachable code (and, notably, the code will be displayed + // with a red background by `llvm-cov show`). + // + // TerminatorKind::SwitchInt { .. } => { + // let some_imaginary_target = successors.clone().find_map(|&successor| { + // let term = mir_body.basic_blocks()[successor].terminator(); + // if let TerminatorKind::FalseEdge { imaginary_target, .. } = term.kind { + // if mir_body.predecessors()[imaginary_target].len() == 1 { + // return Some(imaginary_target); + // } + // } + // None + // }); + // if let Some(imaginary_target) = some_imaginary_target { + // box successors.filter(move |&&successor| successor != imaginary_target) + // } else { + // box successors + // } + // } + // + // Note this also required changing the closure signature for the + // `ShortCurcuitPreorder` to: + // + // F: Fn(&'tcx TerminatorKind<'tcx>) -> Box + 'a>, + TerminatorKind::SwitchInt { .. } => successors, + + // For all other kinds, return only the first successor, if any, and ignore unwinds + _ => successors.next().into_iter().chain(&[]), + } + }); + + // Walk the CFG using a Preorder traversal, which starts from `START_BLOCK` and follows + // each block terminator's `successors()`. Coverage spans must map to actual source code, + // so compiler generated blocks and paths can be ignored. To that end the CFG traversal + // intentionally omits unwind paths. + let mut blocks = Vec::new(); + for (bb, data) in cfg_without_unwind { + if let Some(last) = blocks.last() { + let predecessors = &mir_body.predecessors()[bb]; + if predecessors.len() > 1 || !predecessors.contains(last) { + // The `bb` has more than one _incoming_ edge, and should start its own + // `BasicCoverageBlock`. (Note, the `blocks` vector does not yet include `bb`; + // it contains a sequence of one or more sequential blocks with no intermediate + // branches in or out. Save these as a new `BasicCoverageBlock` before starting + // the new one.) + self.add_basic_coverage_block(blocks.split_off(0)); + debug!( + " because {}", + if predecessors.len() > 1 { + "predecessors.len() > 1".to_owned() + } else { + format!("bb {} is not in precessors: {:?}", bb.index(), predecessors) + } + ); + } + } + blocks.push(bb); + + let term = data.terminator(); + + match term.kind { + TerminatorKind::Return { .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } => { + // The `bb` has more than one _outgoing_ edge, or exits the function. Save the + // current sequence of `blocks` gathered to this point, as a new + // `BasicCoverageBlock`. + self.add_basic_coverage_block(blocks.split_off(0)); + debug!(" because term.kind = {:?}", term.kind); + // Note that this condition is based on `TerminatorKind`, even though it + // theoretically boils down to `successors().len() != 1`; that is, either zero + // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but + // since the Coverage graph (the BCB CFG projection) ignores things like unwind + // branches (which exist in the `Terminator`s `successors()` list) checking the + // number of successors won't work. + } + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } + + if !blocks.is_empty() { + // process any remaining blocks into a final `BasicCoverageBlock` + self.add_basic_coverage_block(blocks.split_off(0)); + debug!(" because the end of the CFG was reached while traversing"); + } + } + + fn add_basic_coverage_block(&mut self, blocks: Vec) { + let leader_bb = blocks[0]; + let bcb = BasicCoverageBlock { blocks }; + debug!("adding BCB: {:?}", bcb); + self.vec[leader_bb] = Some(bcb); + } +} + +impl std::ops::Index for BasicCoverageBlocks { + type Output = BasicCoverageBlock; + + fn index(&self, index: BasicBlock) -> &Self::Output { + self.vec[index].as_ref().expect("is_some if BasicBlock is a BasicCoverageBlock leader") + } +} + +#[derive(Debug, Copy, Clone)] +enum CoverageStatement { + Statement(BasicBlock, Span, usize), + Terminator(BasicBlock, Span), +} + +impl CoverageStatement { + pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { + match *self { + Self::Statement(bb, span, stmt_index) => { + let stmt = &mir_body.basic_blocks()[bb].statements[stmt_index]; + format!( + "{}: @{}[{}]: {:?}", + spanview::source_range_no_file(tcx, &span), + bb.index(), + stmt_index, + stmt + ) + } + Self::Terminator(bb, span) => { + let term = mir_body.basic_blocks()[bb].terminator(); + format!( + "{}: @{}.{}: {:?}", + spanview::source_range_no_file(tcx, &span), + bb.index(), + term_type(&term.kind), + term.kind + ) + } + } + } + + pub fn span(&self) -> &Span { + match self { + Self::Statement(_, span, _) | Self::Terminator(_, span) => span, + } + } +} + +fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str { + match kind { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::Resume => "Resume", + TerminatorKind::Abort => "Abort", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::DropAndReplace { .. } => "DropAndReplace", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::GeneratorDrop => "GeneratorDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } +} + +/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that +/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. +/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent +/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the +/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s. +/// +/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that +/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches +/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` +/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`. +#[derive(Debug, Clone)] +struct CoverageSpan { + span: Span, + bcb_leader_bb: BasicBlock, + coverage_statements: Vec, + is_closure: bool, +} + +impl CoverageSpan { + pub fn for_statement( + statement: &Statement<'tcx>, + span: Span, + bcb: &BasicCoverageBlock, + bb: BasicBlock, + stmt_index: usize, + ) -> Self { + let is_closure = match statement.kind { + StatementKind::Assign(box ( + _, + Rvalue::Aggregate(box AggregateKind::Closure(_, _), _), + )) => true, + _ => false, + }; + + Self { + span, + bcb_leader_bb: bcb.leader_bb(), + coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)], + is_closure, + } + } + + pub fn for_terminator(span: Span, bcb: &'a BasicCoverageBlock, bb: BasicBlock) -> Self { + Self { + span, + bcb_leader_bb: bcb.leader_bb(), + coverage_statements: vec![CoverageStatement::Terminator(bb, span)], + is_closure: false, + } + } + + pub fn merge_from(&mut self, mut other: CoverageSpan) { + debug_assert!(self.is_mergeable(&other)); + self.span = self.span.to(other.span); + if other.is_closure { + self.is_closure = true; + } + self.coverage_statements.append(&mut other.coverage_statements); + } + + pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { + self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos); + if let Some(highest_covstmt) = + self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi()) + { + self.span = self.span.with_hi(highest_covstmt.span().hi()); + } + } + + pub fn is_dominated_by( + &self, + other: &CoverageSpan, + dominators: &Dominators, + ) -> bool { + debug_assert!(!self.is_in_same_bcb(other)); + dominators.is_dominated_by(self.bcb_leader_bb, other.bcb_leader_bb) + } + + pub fn is_mergeable(&self, other: &Self) -> bool { + self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure) + } + + pub fn is_in_same_bcb(&self, other: &Self) -> bool { + self.bcb_leader_bb == other.bcb_leader_bb + } +} + struct Instrumentor<'a, 'tcx> { pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>, + dominators: Option>, + basic_coverage_blocks: Option, function_source_hash: Option, - num_counters: u32, + next_counter_id: u32, num_expressions: u32, } @@ -107,17 +495,19 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { tcx, mir_body, hir_body, + dominators: None, + basic_coverage_blocks: None, function_source_hash: None, - num_counters: 0, + next_counter_id: CounterValueReference::START.as_u32(), num_expressions: 0, } } - /// Counter IDs start from zero and go up. + /// Counter IDs start from one and go up. fn next_counter(&mut self) -> CounterValueReference { - assert!(self.num_counters < u32::MAX - self.num_expressions); - let next = self.num_counters; - self.num_counters += 1; + assert!(self.next_counter_id < u32::MAX - self.num_expressions); + let next = self.next_counter_id; + self.next_counter_id += 1; CounterValueReference::from(next) } @@ -125,12 +515,22 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter /// expression operand IDs must be unique across both types. fn next_expression(&mut self) -> InjectedExpressionIndex { - assert!(self.num_counters < u32::MAX - self.num_expressions); + assert!(self.next_counter_id < u32::MAX - self.num_expressions); let next = u32::MAX - self.num_expressions; self.num_expressions += 1; InjectedExpressionIndex::from(next) } + fn dominators(&self) -> &Dominators { + self.dominators.as_ref().expect("dominators must be initialized before calling") + } + + fn basic_coverage_blocks(&self) -> &BasicCoverageBlocks { + self.basic_coverage_blocks + .as_ref() + .expect("basic_coverage_blocks must be initialized before calling") + } + fn function_source_hash(&mut self) -> u64 { match self.function_source_hash { Some(hash) => hash, @@ -144,86 +544,61 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn inject_counters(&mut self) { let tcx = self.tcx; + let source_map = tcx.sess.source_map(); let def_id = self.mir_body.source.def_id(); let mir_body = &self.mir_body; - let body_span = self.hir_body.value.span; - debug!( - "instrumenting {:?}, span: {}", - def_id, - tcx.sess.source_map().span_to_string(body_span) - ); - - if !tcx.sess.opts.debugging_opts.experimental_coverage { - // Coverage at the function level should be accurate. This is the default implementation - // if `-Z experimental-coverage` is *NOT* enabled. - let block = rustc_middle::mir::START_BLOCK; - let counter = self.make_counter(); - self.inject_statement(counter, body_span, block); - return; - } - // FIXME(richkadel): else if `-Z experimental-coverage` *IS* enabled: Efforts are still in - // progress to identify the correct code region spans and associated counters to generate - // accurate Rust coverage reports. - - let block_span = |data: &BasicBlockData<'tcx>| { - // The default span will be the `Terminator` span; but until we have a smarter solution, - // the coverage region also incorporates at least the statements in this BasicBlock as - // well. Extend the span to encompass all, if possible. - // FIXME(richkadel): Assuming the terminator's span is already known to be contained in `body_span`. - let mut span = data.terminator().source_info.span; - // FIXME(richkadel): It's looking unlikely that we should compute a span from MIR - // spans, but if we do keep something like this logic, we will need a smarter way - // to combine `Statement`s and/or `Terminator`s with `Span`s from different - // files. - for statement_span in data.statements.iter().map(|statement| statement.source_info.span) - { - // Only combine Spans from the function's body_span. - if body_span.contains(statement_span) { - span = span.to(statement_span); - } - } - span + let body_span = self.body_span(); + let source_file = source_map.lookup_source_file(body_span.lo()); + let file_name = match &source_file.name { + FileName::Real(RealFileName::Named(path)) => Symbol::intern(&path.to_string_lossy()), + _ => bug!( + "source_file.name should be a RealFileName, but it was: {:?}", + source_file.name + ), }; - // Traverse the CFG but ignore anything following an `unwind` - let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| { - let mut successors = term_kind.successors(); - match &term_kind { - // SwitchInt successors are never unwind, and all of them should be traversed - TerminatorKind::SwitchInt { .. } => successors, - // For all other kinds, return only the first successor, if any, and ignore unwinds - _ => successors.next().into_iter().chain(&[]), - } - }); + debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span)); - let mut coverage_regions = Vec::with_capacity(cfg_without_unwind.size_hint().0); - for (bb, data) in cfg_without_unwind { - if !body_span.contains(data.terminator().source_info.span) { - continue; - } + self.dominators.replace(mir_body.dominators()); + self.basic_coverage_blocks.replace(BasicCoverageBlocks::from_mir(mir_body)); - // FIXME(richkadel): Regions will soon contain multiple blocks. - let mut blocks = Vec::new(); - blocks.push(bb); - let span = block_span(data); - coverage_regions.push(CoverageRegion { span, blocks }); - } + let coverage_spans = self.coverage_spans(); let span_viewables = if pretty::dump_enabled(tcx, self.pass_name, def_id) { - Some(self.span_viewables(&coverage_regions)) + Some(self.span_viewables(&coverage_spans)) } else { None }; - // Inject counters for the selected spans - for CoverageRegion { span, blocks } in coverage_regions { - debug!( - "Injecting counter at: {:?}:\n{}\n==========", - span, - tcx.sess.source_map().span_to_snippet(span).expect("Error getting source for span"), - ); - let counter = self.make_counter(); - self.inject_statement(counter, span, blocks[0]); + // Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a + // given BCB, but only one actual counter needs to be incremented per BCB. `bb_counters` + // maps each `bcb_leader_bb` to its `Counter`, when injected. Subsequent `CoverageSpan`s + // for a BCB that already has a `Counter` will inject a `CounterExpression` instead, and + // compute its value by adding `ZERO` to the BCB `Counter` value. + let mut bb_counters = IndexVec::from_elem_n(None, mir_body.basic_blocks().len()); + for CoverageSpan { span, bcb_leader_bb: bb, .. } in coverage_spans { + if let Some(&counter_operand) = bb_counters[bb].as_ref() { + let expression = + self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO); + debug!( + "Injecting counter expression {:?} at: {:?}:\n{}\n==========", + expression, + span, + source_map.span_to_snippet(span).expect("Error getting source for span"), + ); + self.inject_statement(file_name, &source_file, expression, span, bb); + } else { + let counter = self.make_counter(); + debug!( + "Injecting counter {:?} at: {:?}:\n{}\n==========", + counter, + span, + source_map.span_to_snippet(span).expect("Error getting source for span"), + ); + let counter_operand = counter.as_operand_id(); + bb_counters[bb] = Some(counter_operand); + self.inject_statement(file_name, &source_file, counter, span, bb); + } } if let Some(span_viewables) = span_viewables { @@ -236,36 +611,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body.source, ) .expect("Unexpected error creating MIR spanview HTML file"); - write_spanview_document(tcx, def_id, span_viewables, &mut file) + let crate_name = tcx.crate_name(def_id.krate); + let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate(); + let title = format!("{}.{} - Coverage Spans", crate_name, item_name); + spanview::write_document(tcx, def_id, span_viewables, &title, &mut file) .expect("Unexpected IO error dumping coverage spans as HTML"); } - - // FIXME(richkadel): Some regions will be counted by "counter expression". Counter - // expressions are supported, but are not yet generated. When they are, remove this `fake_use` - // block. - let fake_use = false; - if fake_use { - let add = false; - let fake_counter = CoverageKind::Counter { - function_source_hash: self.function_source_hash(), - id: CounterValueReference::from_u32(1), - }; - let fake_expression = CoverageKind::Expression { - id: InjectedExpressionIndex::from(u32::MAX - 1), - lhs: ExpressionOperandId::from_u32(1), - op: Op::Add, - rhs: ExpressionOperandId::from_u32(2), - }; - - let lhs = fake_counter.as_operand_id(); - let op = if add { Op::Add } else { Op::Subtract }; - let rhs = fake_expression.as_operand_id(); - - let block = rustc_middle::mir::START_BLOCK; - - let expression = self.make_expression(lhs, op, rhs); - self.inject_statement(expression, body_span, block); - } } fn make_counter(&mut self) -> CoverageKind { @@ -284,8 +635,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs } } - fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) { - let code_region = make_code_region(self.tcx, &span); + fn inject_statement( + &mut self, + file_name: Symbol, + source_file: &Lrc, + coverage_kind: CoverageKind, + span: Span, + block: BasicBlock, + ) { + let code_region = make_code_region(file_name, source_file, span); debug!(" injecting statement {:?} covering {:?}", coverage_kind, code_region); let data = &mut self.mir_body[block]; @@ -297,112 +655,548 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { data.statements.push(statement); } - /// Converts the computed `CoverageRegion`s into `SpanViewable`s. - fn span_viewables(&self, coverage_regions: &Vec) -> Vec { + /// Converts the computed `BasicCoverageBlock`s into `SpanViewable`s. + fn span_viewables(&self, coverage_spans: &Vec) -> Vec { + let tcx = self.tcx; + let mir_body = &self.mir_body; let mut span_viewables = Vec::new(); - for coverage_region in coverage_regions { - span_viewables.push(SpanViewable { - span: coverage_region.span, - id: format!("{}", coverage_region.blocks[0].index()), - tooltip: self.make_tooltip_text(coverage_region), + for coverage_span in coverage_spans { + let bcb = self.bcb_from_coverage_span(coverage_span); + let CoverageSpan { span, bcb_leader_bb: bb, coverage_statements, .. } = coverage_span; + let id = bcb.id(); + let mut sorted_coverage_statements = coverage_statements.clone(); + sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt { + CoverageStatement::Statement(bb, _, index) => (bb, index), + CoverageStatement::Terminator(bb, _) => (bb, usize::MAX), }); + let tooltip = sorted_coverage_statements + .iter() + .map(|covstmt| covstmt.format(tcx, mir_body)) + .collect::>() + .join("\n"); + span_viewables.push(SpanViewable { bb: *bb, span: *span, id, tooltip }); } span_viewables } - /// A custom tooltip renderer used in a spanview HTML+CSS document used for coverage analysis. - fn make_tooltip_text(&self, coverage_region: &CoverageRegion) -> String { - const INCLUDE_COVERAGE_STATEMENTS: bool = false; - let tcx = self.tcx; - let source_map = tcx.sess.source_map(); - let mut text = Vec::new(); - for (i, &bb) in coverage_region.blocks.iter().enumerate() { - if i > 0 { - text.push("\n".to_owned()); + #[inline(always)] + fn bcb_from_coverage_span(&self, coverage_span: &CoverageSpan) -> &BasicCoverageBlock { + &self.basic_coverage_blocks()[coverage_span.bcb_leader_bb] + } + + #[inline(always)] + fn body_span(&self) -> Span { + self.hir_body.value.span + } + + // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of + // the `BasicBlock`(s) in the given `BasicCoverageBlock`. One `CoverageSpan` is generated for + // each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will + // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple + // `Statement`s and/or `Terminator`s.) + fn extract_spans(&self, bcb: &'a BasicCoverageBlock) -> Vec { + let body_span = self.body_span(); + let mir_basic_blocks = self.mir_body.basic_blocks(); + bcb.blocks + .iter() + .map(|bbref| { + let bb = *bbref; + let data = &mir_basic_blocks[bb]; + data.statements + .iter() + .enumerate() + .filter_map(move |(index, statement)| { + filtered_statement_span(statement, body_span).map(|span| { + CoverageSpan::for_statement(statement, span, bcb, bb, index) + }) + }) + .chain( + filtered_terminator_span(data.terminator(), body_span) + .map(|span| CoverageSpan::for_terminator(span, bcb, bb)), + ) + }) + .flatten() + .collect() + } + + /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be + /// counted. + /// + /// The basic steps are: + /// + /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each + /// `BasicCoverageBlock`. + /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position + /// are sorted with longer spans before shorter spans; and equal spans are sorted + /// (deterministically) based on "dominator" relationship (if any). + /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, + /// if another span or spans are already counting the same code region), or should be merged + /// into a broader combined span (because it represents a contiguous, non-branching, and + /// uninterrupted region of source code). + /// + /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since + /// closures have their own MIR, their `Span` in their enclosing function should be left + /// "uncovered". + /// + /// Note the resulting vector of `CoverageSpan`s does may not be fully sorted (and does not need + /// to be). + fn coverage_spans(&self) -> Vec { + let mut initial_spans = + Vec::::with_capacity(self.mir_body.basic_blocks().len() * 2); + for bcb in self.basic_coverage_blocks().iter() { + for coverage_span in self.extract_spans(bcb) { + initial_spans.push(coverage_span); } - text.push(format!("{:?}: {}:", bb, &source_map.span_to_string(coverage_region.span))); - let data = &self.mir_body.basic_blocks()[bb]; - for statement in &data.statements { - let statement_string = match statement.kind { - StatementKind::Coverage(box ref coverage) => match coverage.kind { - CoverageKind::Counter { id, .. } => { - if !INCLUDE_COVERAGE_STATEMENTS { - continue; - } - format!("increment counter #{}", id.index()) - } - CoverageKind::Expression { id, lhs, op, rhs } => { - if !INCLUDE_COVERAGE_STATEMENTS { - continue; - } - format!( - "expression #{} = {} {} {}", - id.index(), - lhs.index(), - if op == Op::Add { "+" } else { "-" }, - rhs.index() - ) - } - CoverageKind::Unreachable => { - if !INCLUDE_COVERAGE_STATEMENTS { - continue; - } - String::from("unreachable") - } - }, - _ => format!("{:?}", statement), - }; - let source_range = source_range_no_file(tcx, &statement.source_info.span); - text.push(format!( - "\n{}{}: {}: {}", - TOOLTIP_INDENT, - source_range, - statement_kind_name(statement), - statement_string - )); + } + + if initial_spans.is_empty() { + // This can happen if, for example, the function is unreachable (contains only a + // `BasicBlock`(s) with an `Unreachable` terminator). + return initial_spans; + } + + initial_spans.sort_unstable_by(|a, b| { + if a.span.lo() == b.span.lo() { + if a.span.hi() == b.span.hi() { + if a.is_in_same_bcb(b) { + Some(Ordering::Equal) + } else { + // Sort equal spans by dominator relationship, in reverse order (so + // dominators always come after the dominated equal spans). When later + // comparing two spans in order, the first will either dominate the second, + // or they will have no dominator relationship. + self.dominators().rank_partial_cmp(b.bcb_leader_bb, a.bcb_leader_bb) + } + } else { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This guarantees that, if a `prev` span overlaps, and is not equal to, a `curr` + // span, the prev span either extends further left of the curr span, or they + // start at the same position and the prev span extends further right of the end + // of the curr span. + b.span.hi().partial_cmp(&a.span.hi()) + } + } else { + a.span.lo().partial_cmp(&b.span.lo()) } - let term = data.terminator(); - let source_range = source_range_no_file(tcx, &term.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - terminator_kind_name(term), - term.kind - )); + .unwrap() + }); + + let refinery = CoverageSpanRefinery::from_sorted_spans(initial_spans, self.dominators()); + refinery.to_refined_spans() + } +} + +struct CoverageSpanRefinery<'a> { + sorted_spans_iter: std::vec::IntoIter, + dominators: &'a Dominators, + some_curr: Option, + curr_original_span: Span, + some_prev: Option, + prev_original_span: Span, + pending_dups: Vec, + refined_spans: Vec, +} + +impl<'a> CoverageSpanRefinery<'a> { + fn from_sorted_spans( + sorted_spans: Vec, + dominators: &'a Dominators, + ) -> Self { + let refined_spans = Vec::with_capacity(sorted_spans.len()); + let mut sorted_spans_iter = sorted_spans.into_iter(); + let prev = sorted_spans_iter.next().expect("at least one span"); + let prev_original_span = prev.span; + Self { + sorted_spans_iter, + dominators, + refined_spans, + some_curr: None, + curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), + some_prev: Some(prev), + prev_original_span, + pending_dups: Vec::new(), + } + } + + /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and + /// de-duplicated `CoverageSpan`s. + fn to_refined_spans(mut self) -> Vec { + while self.next_coverage_span() { + if self.curr().is_mergeable(self.prev()) { + debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); + let prev = self.take_prev(); + self.curr_mut().merge_from(prev); + // Note that curr.span may now differ from curr_original_span + } else if self.prev_ends_before_curr() { + debug!( + " different bcbs and disjoint spans, so keep curr for next iter, and add \ + prev={:?}", + self.prev() + ); + let prev = self.take_prev(); + self.add_refined_span(prev); + } else if self.prev().is_closure { + // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the + // next iter + debug!( + " curr overlaps a closure (prev). Drop curr and keep prev for next iter. \ + prev={:?}", + self.prev() + ); + self.discard_curr(); + } else if self.curr().is_closure { + self.carve_out_span_for_closure(); + } else if self.prev_original_span == self.curr().span { + self.hold_pending_dups_unless_dominated(); + } else { + self.cutoff_prev_at_overlapping_curr(); + } + } + debug!(" AT END, adding last prev={:?}", self.prev()); + let pending_dups = self.pending_dups.split_off(0); + for dup in pending_dups.into_iter() { + debug!(" ...adding at least one pending dup={:?}", dup); + self.add_refined_span(dup); + } + let prev = self.take_prev(); + self.add_refined_span(prev); + + // FIXME(richkadel): Replace some counters with expressions if they can be calculated based + // on branching. (For example, one branch of a SwitchInt can be computed from the counter + // for the CoverageSpan just prior to the SwitchInt minus the sum of the counters of all + // other branches). + + self.to_refined_spans_without_closures() + } + + fn add_refined_span(&mut self, coverage_span: CoverageSpan) { + self.refined_spans.push(coverage_span); + } + + /// Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage + /// regions for the current function leave room for the closure's own coverage regions + /// (injected separately, from the closure's own MIR). + fn to_refined_spans_without_closures(mut self) -> Vec { + self.refined_spans.retain(|covspan| !covspan.is_closure); + self.refined_spans + } + + fn curr(&self) -> &CoverageSpan { + self.some_curr + .as_ref() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + + fn curr_mut(&mut self) -> &mut CoverageSpan { + self.some_curr + .as_mut() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + + fn prev(&self) -> &CoverageSpan { + self.some_prev + .as_ref() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + fn prev_mut(&mut self) -> &mut CoverageSpan { + self.some_prev + .as_mut() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + fn take_prev(&mut self) -> CoverageSpan { + self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the + /// `pending_dups` spans), then one of the following two things happened during the previous + /// iteration: + /// * the `span` of prev was modified (by `curr_mut().merge_from(prev)`); or + /// * the `span` of prev advanced past the end of the span of pending_dups + /// (`prev().span.hi() <= curr().span.lo()`) + /// In either case, no more spans will match the span of `pending_dups`, so + /// add the `pending_dups` if they don't overlap `curr`, and clear the list. + fn check_pending_dups(&mut self) { + if let Some(dup) = self.pending_dups.last() { + if dup.span != self.prev().span { + debug!( + " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ + previous iteration, or prev started a new disjoint span" + ); + if dup.span.hi() <= self.curr().span.lo() { + let pending_dups = self.pending_dups.split_off(0); + for dup in pending_dups.into_iter() { + debug!(" ...adding at least one pending={:?}", dup); + self.add_refined_span(dup); + } + } else { + self.pending_dups.clear(); + } + } + } + } + + /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. + fn next_coverage_span(&mut self) -> bool { + if let Some(curr) = self.some_curr.take() { + self.some_prev = Some(curr); + self.prev_original_span = self.curr_original_span; + } + while let Some(curr) = self.sorted_spans_iter.next() { + debug!("FOR curr={:?}", curr); + if self.prev_starts_after_next(&curr) { + debug!( + " prev.span starts after curr.span, so curr will be dropped (skipping past \ + closure?); prev={:?}", + self.prev() + ); + } else { + // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed + // by `self.curr_mut().merge_from(prev)`. + self.curr_original_span = curr.span; + self.some_curr.replace(curr); + self.check_pending_dups(); + return true; + } + } + false + } + + /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the + /// `curr` coverage span. + fn discard_curr(&mut self) { + self.some_curr = None; + } + + /// Returns true if the curr span should be skipped because prev has already advanced beyond the + /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region + /// of code, such as skipping past a closure. + fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool { + self.prev().span.lo() > next_curr.span.lo() + } + + /// Returns true if the curr span starts past the end of the prev span, which means they don't + /// overlap, so we now know the prev can be added to the refined coverage spans. + fn prev_ends_before_curr(&self) -> bool { + self.prev().span.hi() <= self.curr().span.lo() + } + + /// If `prev`s span extends left of the closure (`curr`), carve out the closure's + /// span from `prev`'s span. (The closure's coverage counters will be injected when + /// processing the closure's own MIR.) Add the portion of the span to the left of the + /// closure; and if the span extends to the right of the closure, update `prev` to + /// that portion of the span. For any `pending_dups`, repeat the same process. + fn carve_out_span_for_closure(&mut self) { + let curr_span = self.curr().span; + let left_cutoff = curr_span.lo(); + let right_cutoff = curr_span.hi(); + let has_pre_closure_span = self.prev().span.lo() < right_cutoff; + let has_post_closure_span = self.prev().span.hi() > right_cutoff; + let mut pending_dups = self.pending_dups.split_off(0); + if has_pre_closure_span { + let mut pre_closure = self.prev().clone(); + pre_closure.span = pre_closure.span.with_hi(left_cutoff); + debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); + if !pending_dups.is_empty() { + for mut dup in pending_dups.iter().cloned() { + dup.span = dup.span.with_hi(left_cutoff); + debug!(" ...and at least one pre_closure dup={:?}", dup); + self.add_refined_span(dup); + } + } + self.add_refined_span(pre_closure); + } + if has_post_closure_span { + // Update prev.span to start after the closure (and discard curr) + self.prev_mut().span = self.prev().span.with_lo(right_cutoff); + self.prev_original_span = self.prev().span; + for dup in pending_dups.iter_mut() { + dup.span = dup.span.with_lo(right_cutoff); + } + self.pending_dups.append(&mut pending_dups); + self.discard_curr(); // since self.prev() was already updated + } else { + pending_dups.clear(); + } + } + + /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if + /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, + /// until their disposition is determined. In this latter case, the `prev` dup is moved into + /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. + fn hold_pending_dups_unless_dominated(&mut self) { + // equal coverage spans are ordered by dominators before dominated (if any) + debug_assert!(!self.prev().is_dominated_by(self.curr(), self.dominators)); + + if self.curr().is_dominated_by(&self.prev(), self.dominators) { + // If one span dominates the other, assocate the span with the dominator only. + // + // For example: + // match somenum { + // x if x < 1 => { ... } + // }... + // The span for the first `x` is referenced by both the pattern block (every + // time it is evaluated) and the arm code (only when matched). The counter + // will be applied only to the dominator block. + // + // The dominator's (`prev`) execution count may be higher than the dominated + // block's execution count, so drop `curr`. + debug!( + " different bcbs but SAME spans, and prev dominates curr. Drop curr and \ + keep prev for next iter. prev={:?}", + self.prev() + ); + self.discard_curr(); + } else { + // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.) + // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as + // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added. + debug!( + " different bcbs but SAME spans, and neither dominates, so keep curr for \ + next iter, and, pending upcoming spans (unless overlapping) add prev={:?}", + self.prev() + ); + let prev = self.take_prev(); + self.pending_dups.push(prev); + } + } + + /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_ + /// statements that end before `curr.lo()` (if any), and add the portion of the + /// combined span for those statements. Any other statements have overlapping spans + /// that can be ignored because `curr` and/or other upcoming statements/spans inside + /// the overlap area will produce their own counters. This disambiguation process + /// avoids injecting multiple counters for overlapping spans, and the potential for + /// double-counting. + fn cutoff_prev_at_overlapping_curr(&mut self) { + debug!( + " different bcbs, overlapping spans, so ignore/drop pending and only add prev \ + if it has statements that end before curr={:?}", + self.prev() + ); + if self.pending_dups.is_empty() { + let curr_span = self.curr().span; + self.prev_mut().cutoff_statements_at(curr_span.lo()); + if self.prev().coverage_statements.is_empty() { + debug!(" ... no non-overlapping statements to add"); + } else { + debug!(" ... adding modified prev={:?}", self.prev()); + let prev = self.take_prev(); + self.add_refined_span(prev); + } + } else { + // with `pending_dups`, `prev` cannot have any statements that don't overlap + self.pending_dups.clear(); } - text.join("") } } +fn filtered_statement_span(statement: &'a Statement<'tcx>, body_span: Span) -> Option { + match statement.kind { + // These statements have spans that are often outside the scope of the executed source code + // for their parent `BasicBlock`. + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + // Coverage should not be encountered, but don't inject coverage coverage + | StatementKind::Coverage(_) + // Ignore `Nop`s + | StatementKind::Nop => None, + + // FIXME(richkadel): Look into a possible issue assigning the span to a + // FakeReadCause::ForGuardBinding, in this example: + // match somenum { + // x if x < 1 => { ... } + // }... + // The BasicBlock within the match arm code included one of these statements, but the span + // for it covered the `1` in this source. The actual statements have nothing to do with that + // source span: + // FakeRead(ForGuardBinding, _4); + // where `_4` is: + // _4 = &_1; (at the span for the first `x`) + // and `_1` is the `Place` for `somenum`. + // + // The arm code BasicBlock already has its own assignment for `x` itself, `_3 = 1`, and I've + // decided it's reasonable for that span (even though outside the arm code) to be part of + // the counted coverage of the arm code execution, but I can't justify including the literal + // `1` in the arm code. I'm pretty sure that, if the `FakeRead(ForGuardBinding)` has a + // purpose in codegen, it's probably in the right BasicBlock, but if so, the `Statement`s + // `source_info.span` can't be right. + // + // Consider correcting the span assignment, assuming there is a better solution, and see if + // the following pattern can be removed here: + StatementKind::FakeRead(cause, _) if cause == FakeReadCause::ForGuardBinding => None, + + // Retain spans from all other statements + StatementKind::FakeRead(_, _) // Not including `ForGuardBinding` + | StatementKind::Assign(_) + | StatementKind::SetDiscriminant { .. } + | StatementKind::LlvmInlineAsm(_) + | StatementKind::Retag(_, _) + | StatementKind::AscribeUserType(_, _) => { + Some(source_info_span(&statement.source_info, body_span)) + } + } +} + +fn filtered_terminator_span(terminator: &'a Terminator<'tcx>, body_span: Span) -> Option { + match terminator.kind { + // These terminators have spans that don't positively contribute to computing a reasonable + // span of actually executed source code. (For example, SwitchInt terminators extracted from + // an `if condition { block }` has a span that includes the executed block, if true, + // but for coverage, the code region executed, up to *and* through the SwitchInt, + // actually stops before the if's block.) + TerminatorKind::Unreachable // Unreachable blocks are not connected to the CFG + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Goto { .. } + // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. + | TerminatorKind::FalseEdge { .. } => None, + + // Retain spans from all other terminators + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Call { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => { + Some(source_info_span(&terminator.source_info, body_span)) + } + } +} + +#[inline(always)] +fn source_info_span(source_info: &SourceInfo, body_span: Span) -> Span { + let span = original_sp(source_info.span, body_span).with_ctxt(SyntaxContext::root()); + if body_span.contains(span) { span } else { body_span } +} + /// Convert the Span into its file name, start line and column, and end line and column -fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = if span.hi() == span.lo() { - start.clone() +fn make_code_region(file_name: Symbol, source_file: &Lrc, span: Span) -> CodeRegion { + let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo()); + let (end_line, end_col) = if span.hi() == span.lo() { + let (end_line, mut end_col) = (start_line, start_col); + // Extend an empty span by one character so the region will be counted. + let CharPos(char_pos) = start_col; + if char_pos > 0 { + start_col = CharPos(char_pos - 1); + } else { + end_col = CharPos(char_pos + 1); + } + (end_line, end_col) } else { - let end = source_map.lookup_char_pos(span.hi()); - debug_assert_eq!( - start.file.name, - end.file.name, - "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", - span.lo(), - start, - span.hi(), - end - ); - end + source_file.lookup_file_pos(span.hi()) }; - match &start.file.name { - FileName::Real(RealFileName::Named(path)) => CodeRegion { - file_name: Symbol::intern(&path.to_string_lossy()), - start_line: start.line as u32, - start_col: start.col.to_u32() + 1, - end_line: end.line as u32, - end_col: end.col.to_u32() + 1, - }, - _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name), + CodeRegion { + file_name, + start_line: start_line as u32, + start_col: start_col.to_u32() + 1, + end_line: end_line as u32, + end_col: end_col.to_u32() + 1, } } diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index c00c3b740ed..3a83fe11d0a 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -150,26 +150,31 @@ fn dump_matched_mir_node<'tcx, F>( if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { let _: io::Result<()> = try { - let mut file = - create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, body.source)?; + let file_basename = + dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source); + let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; if body.source.def_id().is_local() { - write_mir_fn_spanview(tcx, body, spanview, &mut file)?; + write_mir_fn_spanview( + tcx, + body, + spanview, + &file_basename, + &mut file, + )?; } }; } } -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path( +/// Returns the file basename portion (without extension) of a filename path +/// where we should dump a MIR representation output files. +fn dump_file_basename( tcx: TyCtxt<'_>, - extension: &str, pass_num: Option<&dyn Display>, pass_name: &str, disambiguator: &dyn Display, source: MirSource<'tcx>, -) -> PathBuf { +) -> String { let promotion_id = match source.promoted { Some(id) => format!("-{:?}", id), None => String::new(), @@ -184,9 +189,6 @@ fn dump_path( } }; - let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); - let crate_name = tcx.crate_name(source.def_id().krate); let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); // All drop shims have the same DefId, so we have to add the type @@ -206,23 +208,46 @@ fn dump_path( _ => String::new(), }; - let file_name = format!( - "{}.{}{}{}{}.{}.{}.{}", - crate_name, - item_name, - shim_disambiguator, - promotion_id, - pass_num, - pass_name, - disambiguator, - extension, - ); + format!( + "{}.{}{}{}{}.{}.{}", + crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator, + ) +} + +/// Returns the path to the filename where we should dump a given MIR. +/// Also used by other bits of code (e.g., NLL inference) that dump +/// graphviz data or other things. +fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { + let mut file_path = PathBuf::new(); + file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); + + let file_name = format!("{}.{}", basename, extension,); file_path.push(&file_name); file_path } +/// Attempts to open the MIR dump file with the given name and extension. +fn create_dump_file_with_basename( + tcx: TyCtxt<'_>, + file_basename: &str, + extension: &str, +) -> io::Result> { + let file_path = dump_path(tcx, file_basename, extension); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent).map_err(|e| { + io::Error::new( + e.kind(), + format!("IO error creating MIR dump directory: {:?}; {}", parent, e), + ) + })?; + } + Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { + io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e)) + })?)) +} + /// Attempts to open a file where we should dump a given MIR or other /// bit of MIR-related data. Used by `mir-dump`, but also by other /// bits of code (e.g., NLL inference) that dump graphviz data or @@ -235,11 +260,11 @@ pub(crate) fn create_dump_file( disambiguator: &dyn Display, source: MirSource<'tcx>, ) -> io::Result> { - let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source); - if let Some(parent) = file_path.parent() { - fs::create_dir_all(parent)?; - } - Ok(io::BufWriter::new(fs::File::create(&file_path)?)) + create_dump_file_with_basename( + tcx, + &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source), + extension, + ) } /// Write out a human-readable textual representation for the given MIR. diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs index fdc724178b6..d3ef8c64565 100644 --- a/compiler/rustc_mir/src/util/spanview.rs +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -16,9 +16,13 @@ const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT B const NEW_LINE_SPAN: &str = "\n"; const HEADER: &str = r#" - - coverage_of_if_else - Code Regions - - -"#; - -const FOOTER: &str = r#" - -"#; +"#; /// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +#[derive(Clone, Debug)] pub struct SpanViewable { + pub bb: BasicBlock, pub span: Span, pub id: String, pub tooltip: String, @@ -92,6 +92,7 @@ pub fn write_mir_fn_spanview<'tcx, W>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, spanview: MirSpanview, + title: &str, w: &mut W, ) -> io::Result<()> where @@ -126,16 +127,17 @@ where } } } - write_spanview_document(tcx, def_id, span_viewables, w)?; + write_document(tcx, def_id, span_viewables, title, w)?; Ok(()) } /// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated /// list `SpanViewable`s. -pub fn write_spanview_document<'tcx, W>( +pub fn write_document<'tcx, W>( tcx: TyCtxt<'tcx>, def_id: DefId, mut span_viewables: Vec, + title: &str, w: &mut W, ) -> io::Result<()> where @@ -153,6 +155,9 @@ where source_map.span_to_snippet(fn_span).expect("function should have printable source") ); writeln!(w, "{}", HEADER)?; + writeln!(w, "{}", title)?; + writeln!(w, "{}", STYLE_SECTION)?; + writeln!(w, "{}", START_BODY)?; write!( w, r#"
{}"#, @@ -182,6 +187,7 @@ where end_pos.to_usize(), ordered_viewables.len() ); + let curr_id = &ordered_viewables[0].id; let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( tcx, from_pos, @@ -204,13 +210,17 @@ where from_pos = next_from_pos; if next_ordered_viewables.len() != ordered_viewables.len() { ordered_viewables = next_ordered_viewables; - alt = !alt; + if let Some(next_ordered_viewable) = ordered_viewables.first() { + if &next_ordered_viewable.id != curr_id { + alt = !alt; + } + } } } if from_pos < end_pos { write_coverage_gap(tcx, from_pos, end_pos, w)?; } - write!(w, r#"
"#)?; + writeln!(w, r#"
"#)?; writeln!(w, "{}", FOOTER)?; Ok(()) } @@ -273,7 +283,7 @@ fn statement_span_viewable<'tcx>( } let id = format!("{}[{}]", bb.index(), i); let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); - Some(SpanViewable { span, id, tooltip }) + Some(SpanViewable { bb, span, id, tooltip }) } fn terminator_span_viewable<'tcx>( @@ -289,7 +299,7 @@ fn terminator_span_viewable<'tcx>( } let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); - Some(SpanViewable { span, id, tooltip }) + Some(SpanViewable { bb, span, id, tooltip }) } fn block_span_viewable<'tcx>( @@ -304,7 +314,7 @@ fn block_span_viewable<'tcx>( } let id = format!("{}", bb.index()); let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { span, id, tooltip }) + Some(SpanViewable { bb, span, id, tooltip }) } fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { @@ -456,6 +466,7 @@ where remaining_viewables.len() ); // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. + let curr_id = &remaining_viewables[0].id; let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( tcx, from_pos, @@ -480,7 +491,11 @@ where from_pos = next_from_pos; if next_remaining_viewables.len() != remaining_viewables.len() { remaining_viewables = next_remaining_viewables; - subalt = !subalt; + if let Some(next_ordered_viewable) = remaining_viewables.first() { + if &next_ordered_viewable.id != curr_id { + subalt = !subalt; + } + } } } if from_pos <= viewable.span.hi() { @@ -649,8 +664,12 @@ fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); let fn_decl_span = tcx.hir().span(hir_id); let body_span = hir_body(tcx, def_id).value.span; - debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt()); - fn_decl_span.to(body_span) + if fn_decl_span.ctxt() == body_span.ctxt() { + fn_decl_span.to(body_span) + } else { + // This probably occurs for functions defined via macros + body_span + } } fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ab96b0333f4..231e315a22f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1756,10 +1756,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - if debugging_opts.experimental_coverage { - debugging_opts.instrument_coverage = true; - } - if debugging_opts.instrument_coverage { if cg.profile_generate.enabled() || cg.profile_use.is_some() { early_error( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b705ab6d931..a106007c274 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -895,11 +895,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, all statements)."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - experimental_coverage: bool = (false, parse_bool, [TRACKED], - "enable and extend the `-Z instrument-coverage` function-level coverage \ - feature, adding additional experimental (likely inaccurate) counters and \ - code regions (used by `rustc` compiler developers to test new coverage \ - counter placements) (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 96a6956a40c..e7cb8cb6e88 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -60,6 +60,8 @@ use md5::Md5; use sha1::Digest; use sha1::Sha1; +use tracing::debug; + #[cfg(test)] mod tests; @@ -1462,6 +1464,88 @@ impl SourceFile { BytePos::from_u32(pos.0 - self.start_pos.0 + diff) } + + /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. + pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { + // The number of extra bytes due to multibyte chars in the `SourceFile`. + let mut total_extra_bytes = 0; + + for mbc in self.multibyte_chars.iter() { + debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); + if mbc.pos < bpos { + // Every character is at least one byte, so we only + // count the actual extra bytes. + total_extra_bytes += mbc.bytes as u32 - 1; + // We should never see a byte position in the middle of a + // character. + assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32); + } else { + break; + } + } + + assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32()); + CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize) + } + + /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a + /// given `BytePos`. + pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) { + let chpos = self.bytepos_to_file_charpos(pos); + match self.lookup_line(pos) { + Some(a) => { + let line = a + 1; // Line numbers start at 1 + let linebpos = self.lines[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + let col = chpos - linechpos; + debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); + debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + (line, col) + } + None => (0, chpos), + } + } + + /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based) + /// column offset when displayed, for a given `BytePos`. + pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) { + let (line, col_or_chpos) = self.lookup_file_pos(pos); + if line > 0 { + let col = col_or_chpos; + let linebpos = self.lines[line - 1]; + let col_display = { + let start_width_idx = self + .non_narrow_chars + .binary_search_by_key(&linebpos, |x| x.pos()) + .unwrap_or_else(|x| x); + let end_width_idx = self + .non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let special_chars = end_width_idx - start_width_idx; + let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx] + .iter() + .map(|x| x.width()) + .sum(); + col.0 - special_chars + non_narrow + }; + (line, col, col_display) + } else { + let chpos = col_or_chpos; + let col_display = { + let end_width_idx = self + .non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let non_narrow: usize = + self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum(); + chpos.0 - end_width_idx + non_narrow + }; + (0, chpos, col_display) + } + } } /// Normalizes the source code and records the normalizations. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 37596b8ef6f..fdb031fd9b3 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -428,58 +428,22 @@ impl SourceMap { } } + /// Return the SourceFile that contains the given `BytePos` + pub fn lookup_source_file(&self, pos: BytePos) -> Lrc { + let idx = self.lookup_source_file_idx(pos); + (*self.files.borrow().source_files)[idx].clone() + } + /// Looks up source information about a `BytePos`. pub fn lookup_char_pos(&self, pos: BytePos) -> Loc { - let chpos = self.bytepos_to_file_charpos(pos); - match self.lookup_line(pos) { - Ok(SourceFileAndLine { sf: f, line: a }) => { - let line = a + 1; // Line numbers start at 1 - let linebpos = f.lines[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - let col = chpos - linechpos; - - let col_display = { - let start_width_idx = f - .non_narrow_chars - .binary_search_by_key(&linebpos, |x| x.pos()) - .unwrap_or_else(|x| x); - let end_width_idx = f - .non_narrow_chars - .binary_search_by_key(&pos, |x| x.pos()) - .unwrap_or_else(|x| x); - let special_chars = end_width_idx - start_width_idx; - let non_narrow: usize = f.non_narrow_chars[start_width_idx..end_width_idx] - .iter() - .map(|x| x.width()) - .sum(); - col.0 - special_chars + non_narrow - }; - debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - Loc { file: f, line, col, col_display } - } - Err(f) => { - let col_display = { - let end_width_idx = f - .non_narrow_chars - .binary_search_by_key(&pos, |x| x.pos()) - .unwrap_or_else(|x| x); - let non_narrow: usize = - f.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum(); - chpos.0 - end_width_idx + non_narrow - }; - Loc { file: f, line: 0, col: chpos, col_display } - } - } + let sf = self.lookup_source_file(pos); + let (line, col, col_display) = sf.lookup_file_pos_with_col_display(pos); + Loc { file: sf, line, col, col_display } } // If the corresponding `SourceFile` is empty, does not return a line number. pub fn lookup_line(&self, pos: BytePos) -> Result> { - let idx = self.lookup_source_file_idx(pos); - - let f = (*self.files.borrow().source_files)[idx].clone(); + let f = self.lookup_source_file(pos); match f.lookup_line(pos) { Some(line) => Ok(SourceFileAndLine { sf: f, line }), @@ -934,27 +898,8 @@ impl SourceMap { /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_source_file_idx(bpos); - let map = &(*self.files.borrow().source_files)[idx]; - - // The number of extra bytes due to multibyte chars in the `SourceFile`. - let mut total_extra_bytes = 0; - - for mbc in map.multibyte_chars.iter() { - debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); - if mbc.pos < bpos { - // Every character is at least one byte, so we only - // count the actual extra bytes. - total_extra_bytes += mbc.bytes as u32 - 1; - // We should never see a byte position in the middle of a - // character. - assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32); - } else { - break; - } - } - - assert!(map.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32()); - CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes as usize) + let sf = &(*self.files.borrow().source_files)[idx]; + sf.bytepos_to_file_charpos(bpos) } // Returns the index of the `SourceFile` (in `self.files`) that contains `pos`. diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot index df4f11f0f21..8d1da7f1b96 100644 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot @@ -3,8 +3,5 @@ digraph Mir_0_3 { node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; label=>; - bb0__0_3 [shape="none", label=<
0
_0 = const ()
goto
>]; - bb1__0_3 [shape="none", label=<
1
resume
>]; - bb2__0_3 [shape="none", label=<
2
return
>]; - bb0__0_3 -> bb2__0_3 [label=""]; + bb0__0_3 [shape="none", label=<
0
_0 = const ()
return
>]; } diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir deleted file mode 100644 index 8d1da7f1b96..00000000000 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir +++ /dev/null @@ -1,7 +0,0 @@ -digraph Mir_0_3 { - graph [fontname="Courier, monospace"]; - node [fontname="Courier, monospace"]; - edge [fontname="Courier, monospace"]; - label=>; - bb0__0_3 [shape="none", label=<
0
_0 = const ()
return
>]; -} diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 5b2572655cc..5048359e5c6 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -6,7 +6,7 @@ bb0: { _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 -+ Coverage::Counter(0) for /the/src/instrument_coverage.rs:19:18 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:5 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 800754542d9..598727e677c 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,7 +8,7 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { -+ Coverage::Counter(0) for /the/src/instrument_coverage.rs:10:11 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:12:12 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 falseUnwind -> [real: bb1, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } @@ -26,6 +26,7 @@ } bb3: { ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html index 8f6b1307971..8e5268043e7 100644 --- a/src/test/mir-opt/spanview_block.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -1,8 +1,8 @@ - coverage_of_if_else - Code Regions - +
fn main() 0⦊{}⦉02⦊⦉2
+ 5:13-5:13: Return: return">0⦊{}⦉0
diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir deleted file mode 100644 index f8ecf143767..00000000000 --- a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir +++ /dev/null @@ -1,66 +0,0 @@ - - - - coverage_of_if_else - Code Regions - - - -
fn main() 0⦊{}⦉0
- - diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html index 072d22473a9..abbff2270b7 100644 --- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -1,8 +1,8 @@ - coverage_of_if_else - Code Regions - +
fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
+ 5:11-5:13: Assign: _0 = const ()">0[0]⦊{}⦉0[0]0:Return⦊⦉0:Return diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir deleted file mode 100644 index 8a34b8b5dae..00000000000 --- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir +++ /dev/null @@ -1,66 +0,0 @@ - - - - coverage_of_if_else - Code Regions - - - -
fn main() 0[0]⦊{}⦉0[0]0:Return⦊⦉0:Return
- - diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html index e023f0f8aea..55fafd90b0a 100644 --- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -1,8 +1,8 @@ - coverage_of_if_else - Code Regions - + -
fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
+
fn main() {}0:Return⦊⦉0:Return
diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir deleted file mode 100644 index 984b021384b..00000000000 --- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir +++ /dev/null @@ -1,65 +0,0 @@ - - - - coverage_of_if_else - Code Regions - - - -
fn main() {}0:Return⦊⦉0:Return
- - diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile index cb081fb641b..0e05df72c4c 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile @@ -20,25 +20,29 @@ all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) clear_expected_if_blessed: ifdef RUSTC_BLESS_TEST rm -f expected_export_coverage.*.json - rm -f typical_show_coverage.*.txt + rm -f expected_show_coverage.*.txt endif -include clear_expected_if_blessed %: $(SOURCEDIR)/%.rs - # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. - # - # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are - # satisfied with the branch-level instrumentation. + # Compile the test program with coverage instrumentation and generate relevant MIR. $(RUSTC) $(SOURCEDIR)/$@.rs \ - -Zexperimental-coverage \ + -Zinstrument-coverage \ -Clink-dead-code=$(LINK_DEAD_CODE) # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to # output the coverage stats for this run. LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ - $(call RUN,$@) + $(call RUN,$@) || \ + ( \ + status=$$?; \ + grep -q "^\/\/ expect-exit-status-$$status" $(SOURCEDIR)/$@.rs || \ + ( >&2 echo "program exited with an unexpected exit status: $$status"; \ + false \ + ) \ + ) # Postprocess the profiling data so it can be used by the llvm-cov tool "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ @@ -57,11 +61,20 @@ endif > "$(TMPDIR)"/actual_show_coverage.$@.txt ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_show_coverage.$@.txt typical_show_coverage.$@.txt + cp "$(TMPDIR)"/actual_show_coverage.$@.txt expected_show_coverage.$@.txt else # Compare the show coverage output (`--bless` refreshes `typical` files) - $(DIFF) typical_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ - >&2 echo 'diff failed for `llvm-cov show` on $@ (might not be an error)' + # Note `llvm-cov show` output for some programs can vary, but can be ignored + # by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file. + + $(DIFF) expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ + ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ + >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ + ) || \ + ( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \ + false \ + ) + endif # Generate a coverage report in JSON, using `llvm-cov export`, and fail if diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.closure.json new file mode 100644 index 00000000000..9dbd0c4e5d6 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.closure.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/closure.rs", + "summary": { + "functions": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "instantiations": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "lines": { + "count": 91, + "covered": 75, + "percent": 82.41758241758241 + }, + "regions": { + "count": 21, + "covered": 11, + "notcovered": 10, + "percent": 52.38095238095239 + } + } + } + ], + "totals": { + "functions": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "instantiations": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "lines": { + "count": 91, + "covered": 75, + "percent": 82.41758241758241 + }, + "regions": { + "count": 21, + "covered": 11, + "notcovered": 10, + "percent": 52.38095238095239 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json deleted file mode 100644 index 051250d90a2..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../instrument-coverage/coverage_of_if_else.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 19, - "percent": 47.5 - }, - "regions": { - "count": 71, - "covered": 23, - "notcovered": 48, - "percent": 32.3943661971831 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 19, - "percent": 47.5 - }, - "regions": { - "count": 71, - "covered": 23, - "notcovered": 48, - "percent": 32.3943661971831 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.drop_trait.json new file mode 100644 index 00000000000..cdfdca990fa --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.drop_trait.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/drop_trait.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 10, + "covered": 10, + "percent": 100 + }, + "regions": { + "count": 5, + "covered": 5, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 10, + "covered": 10, + "percent": 100 + }, + "regions": { + "count": 5, + "covered": 5, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.generics.json new file mode 100644 index 00000000000..ae405afedc1 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.generics.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/generics.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 16, + "percent": 100 + }, + "regions": { + "count": 6, + "covered": 6, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 16, + "percent": 100 + }, + "regions": { + "count": 6, + "covered": 6, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if.json new file mode 100644 index 00000000000..5231593d8a0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/if.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 19, + "covered": 19, + "percent": 100 + }, + "regions": { + "count": 4, + "covered": 4, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 19, + "covered": 19, + "percent": 100 + }, + "regions": { + "count": 4, + "covered": 4, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if_else.json new file mode 100644 index 00000000000..abc1afc9ab5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 28, + "covered": 19, + "percent": 67.85714285714286 + }, + "regions": { + "count": 7, + "covered": 5, + "notcovered": 2, + "percent": 71.42857142857143 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 28, + "covered": 19, + "percent": 67.85714285714286 + }, + "regions": { + "count": 7, + "covered": 5, + "notcovered": 2, + "percent": 71.42857142857143 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.inner_items.json new file mode 100644 index 00000000000..366f2afc6d7 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.inner_items.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/inner_items.rs", + "summary": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 13, + "covered": 13, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 13, + "covered": 13, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.lazy_boolean.json new file mode 100644 index 00000000000..3b052ad9106 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.lazy_boolean.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/lazy_boolean.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 19, + "percent": 90.47619047619048 + }, + "regions": { + "count": 16, + "covered": 14, + "notcovered": 2, + "percent": 87.5 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 19, + "percent": 90.47619047619048 + }, + "regions": { + "count": 16, + "covered": 14, + "notcovered": 2, + "percent": 87.5 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.loop_break_value.json new file mode 100644 index 00000000000..0b9344f86f4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.loop_break_value.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/loop_break_value.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 11, + "covered": 11, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 11, + "covered": 11, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.question_mark_error_result.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.question_mark_error_result.json new file mode 100644 index 00000000000..f2e95e4a836 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.question_mark_error_result.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/question_mark_error_result.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 15, + "percent": 93.75 + }, + "regions": { + "count": 13, + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 15, + "percent": 93.75 + }, + "regions": { + "count": 13, + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_loop.json new file mode 100644 index 00000000000..5701575189a --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_loop.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/simple_loop.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 18, + "percent": 100 + }, + "regions": { + "count": 7, + "covered": 7, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 18, + "percent": 100 + }, + "regions": { + "count": 7, + "covered": 7, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_match.json new file mode 100644 index 00000000000..df43cb9640d --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.simple_match.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/simple_match.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 9, + "covered": 9, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 9, + "covered": 9, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.various_conditions.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.various_conditions.json new file mode 100644 index 00000000000..82c80024df6 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.various_conditions.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/various_conditions.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 49, + "covered": 23, + "percent": 46.93877551020408 + }, + "regions": { + "count": 51, + "covered": 19, + "notcovered": 32, + "percent": 37.254901960784316 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 49, + "covered": 23, + "percent": 46.93877551020408 + }, + "regions": { + "count": 51, + "covered": 19, + "notcovered": 32, + "percent": 37.254901960784316 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.while_early_return.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.while_early_return.json new file mode 100644 index 00000000000..aa4e9a3c5dd --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.while_early_return.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/while_early_return.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 16, + "percent": 88.88888888888889 + }, + "regions": { + "count": 9, + "covered": 7, + "notcovered": 2, + "percent": 77.77777777777779 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 16, + "percent": 88.88888888888889 + }, + "regions": { + "count": 9, + "covered": 7, + "notcovered": 2, + "percent": 77.77777777777779 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.closure.txt new file mode 100644 index 00000000000..17054490e9b --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.closure.txt @@ -0,0 +1,94 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| let is_false = ! is_true; + 9| 1| + 10| 1| let mut some_string = Some(String::from("the string content")); + 11| 1| println!( + 12| 1| "The string or alt: {}" + 13| 1| , + 14| 1| some_string + 15| 1| . + 16| 1| unwrap_or_else + 17| 1| ( + 18| 1| || + 19| | { + 20| 0| let mut countdown = 0; + 21| 0| if is_false { + 22| 0| countdown = 10; + 23| 0| } + 24| 0| "alt string 1".to_owned() + 25| 1| } + 26| 1| ) + 27| 1| ); + 28| 1| + 29| 1| some_string = Some(String::from("the string content")); + 30| 1| let + 31| 1| a + 32| 1| = + 33| 1| || + 34| | { + 35| 0| let mut countdown = 0; + 36| 0| if is_false { + 37| 0| countdown = 10; + 38| 0| } + 39| 0| "alt string 2".to_owned() + 40| 1| }; + 41| 1| println!( + 42| 1| "The string or alt: {}" + 43| 1| , + 44| 1| some_string + 45| 1| . + 46| 1| unwrap_or_else + 47| 1| ( + 48| 1| a + 49| 1| ) + 50| 1| ); + 51| 1| + 52| 1| some_string = None; + 53| 1| println!( + 54| 1| "The string or alt: {}" + 55| 1| , + 56| 1| some_string + 57| 1| . + 58| 1| unwrap_or_else + 59| 1| ( + 60| 1| || + 61| | { + 62| 1| let mut countdown = 0; + 63| 1| if is_false { + 64| 0| countdown = 10; + 65| 0| } + 66| 1| "alt string 3".to_owned() + 67| 1| } + 68| 1| ) + 69| 1| ); + 70| 1| + 71| 1| some_string = None; + 72| 1| let + 73| 1| a + 74| 1| = + 75| 1| || + 76| | { + 77| 1| let mut countdown = 0; + 78| 1| if is_false { + 79| 0| countdown = 10; + 80| 0| } + 81| 1| "alt string 4".to_owned() + 82| 1| }; + 83| 1| println!( + 84| 1| "The string or alt: {}" + 85| 1| , + 86| 1| some_string + 87| 1| . + 88| 1| unwrap_or_else + 89| 1| ( + 90| 1| a + 91| 1| ) + 92| 1| ); + 93| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.drop_trait.txt new file mode 100644 index 00000000000..72aa020ca16 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.drop_trait.txt @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |struct Firework { + 5| | strength: i32, + 6| |} + 7| | + 8| |impl Drop for Firework { + 9| 2| fn drop(&mut self) { + 10| 2| println!("BOOM times {}!!!", self.strength); + 11| 2| } + 12| |} + 13| | + 14| |fn main() -> Result<(),u8> { + 15| 1| let _firecracker = Firework { strength: 1 }; + 16| 1| + 17| 1| let _tnt = Firework { strength: 100 }; + 18| | + 19| 1| if true { + 20| 1| println!("Exiting with error..."); + 21| 1| return Err(1); + 22| | } + 23| | + 24| | let _ = Firework { strength: 1000 }; + 25| | + 26| | Ok(()) + 27| 1|} + 28| | + 29| |// Expected program output: + 30| |// Exiting with error... + 31| |// BOOM times 100!!! + 32| |// BOOM times 1!!! + 33| |// Error: 1 + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.generics.txt new file mode 100644 index 00000000000..86199d74763 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.generics.txt @@ -0,0 +1,67 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |struct Firework where T: Copy + std::fmt::Display { + 5| | strength: T, + 6| |} + 7| | + 8| |impl Firework where T: Copy + std::fmt::Display { + 9| | #[inline(always)] + 10| 3| fn set_strength(&mut self, new_strength: T) { + 11| 3| self.strength = new_strength; + 12| 3| } + ------------------ + | >::set_strength: + | 10| 2| fn set_strength(&mut self, new_strength: T) { + | 11| 2| self.strength = new_strength; + | 12| 2| } + ------------------ + | >::set_strength: + | 10| 1| fn set_strength(&mut self, new_strength: T) { + | 11| 1| self.strength = new_strength; + | 12| 1| } + ------------------ + 13| |} + 14| | + 15| |impl Drop for Firework where T: Copy + std::fmt::Display { + 16| | #[inline(always)] + 17| 2| fn drop(&mut self) { + 18| 2| println!("BOOM times {}!!!", self.strength); + 19| 2| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + 20| |} + 21| | + 22| |fn main() -> Result<(),u8> { + 23| 1| let mut firecracker = Firework { strength: 1 }; + 24| 1| firecracker.set_strength(2); + 25| 1| + 26| 1| let mut tnt = Firework { strength: 100.1 }; + 27| 1| tnt.set_strength(200.1); + 28| 1| tnt.set_strength(300.3); + 29| | + 30| 1| if true { + 31| 1| println!("Exiting with error..."); + 32| 1| return Err(1); + 33| | } + 34| | + 35| | let _ = Firework { strength: 1000 }; + 36| | + 37| | Ok(()) + 38| 1|} + 39| | + 40| |// Expected program output: + 41| |// Exiting with error... + 42| |// BOOM times 100!!! + 43| |// BOOM times 1!!! + 44| |// Error: 1 + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if.txt new file mode 100644 index 00000000000..bc2f9b108b2 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if.txt @@ -0,0 +1,29 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| | let + 8| 1| is_true + 9| 1| = + 10| 1| std::env::args().len() + 11| 1| == + 12| 1| 1 + 13| 1| ; + 14| 1| let + 15| 1| mut + 16| 1| countdown + 17| 1| = + 18| 1| 0 + 19| | ; + 20| | if + 21| 1| is_true + 22| 1| { + 23| 1| countdown + 24| 1| = + 25| 1| 10 + 26| 1| ; + 27| 1| } + 28| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if_else.txt new file mode 100644 index 00000000000..5f899723e25 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.if_else.txt @@ -0,0 +1,41 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if + 11| 1| is_true + 12| 1| { + 13| 1| countdown + 14| 1| = + 15| 1| 10 + 16| 1| ; + 17| 1| } + 18| | else // Note coverage region difference without semicolon + 19| | { + 20| 0| countdown + 21| 0| = + 22| 0| 100 + 23| | } + 24| | + 25| | if + 26| 1| is_true + 27| 1| { + 28| 1| countdown + 29| 1| = + 30| 1| 10 + 31| 1| ; + 32| 1| } + 33| | else + 34| 0| { + 35| 0| countdown + 36| 0| = + 37| 0| 100 + 38| 0| ; + 39| 0| } + 40| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.inner_items.txt new file mode 100644 index 00000000000..364d25b1646 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.inner_items.txt @@ -0,0 +1,58 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if is_true { + 11| 1| countdown = 10; + 12| 1| } + 13| | + 14| | mod inner_mod { + 15| | const INNER_MOD_CONST: u32 = 1000; + 16| | } + 17| | + 18| | fn inner_function(a: u32) { + 19| 3| let b = 1; + 20| 3| let c = a + b; + 21| 3| println!("c = {}", c) + 22| 3| } + 23| | + 24| | struct InnerStruct { + 25| | inner_struct_field: u32, + 26| | } + 27| | + 28| | const INNER_CONST: u32 = 1234; + 29| | + 30| | trait InnerTrait { + 31| | fn inner_trait_func(&mut self, incr: u32); + 32| | + 33| 1| fn default_trait_func(&mut self) { + 34| 1| inner_function(INNER_CONST); + 35| 1| self.inner_trait_func(INNER_CONST); + 36| 1| } + 37| | } + 38| | + 39| | impl InnerTrait for InnerStruct { + 40| | fn inner_trait_func(&mut self, incr: u32) { + 41| 1| self.inner_struct_field += incr; + 42| 1| inner_function(self.inner_struct_field); + 43| 1| } + 44| | } + 45| | + 46| | type InnerType = String; + 47| | + 48| 1| if is_true { + 49| 1| inner_function(countdown); + 50| 1| } + 51| | + 52| 1| let mut val = InnerStruct { + 53| 1| inner_struct_field: 101, + 54| 1| }; + 55| 1| + 56| 1| val.default_trait_func(); + 57| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.lazy_boolean.txt new file mode 100644 index 00000000000..ded43697515 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.lazy_boolean.txt @@ -0,0 +1,44 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); + 10| 1| if is_true { + 11| 1| a = 1; + 12| 1| b = 10; + 13| 1| c = 100; + 14| 1| } + 15| | let + 16| 1| somebool + 17| | = + 18| 1| a < b + 19| | || + 20| 0| b < c + 21| | ; + 22| | let + 23| 1| somebool + 24| | = + 25| 1| b < a + 26| | || + 27| 1| b < c + 28| | ; + 29| | let + 30| 1| somebool + 31| | = + 32| 1| a < b + 33| | && + 34| 1| b < c + 35| | ; + 36| | let + 37| 1| somebool + 38| | = + 39| 1| b < a + 40| | && + 41| 0| b < c + 42| | ; + 43| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.loop_break_value.txt new file mode 100644 index 00000000000..b0d668c6d76 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.loop_break_value.txt @@ -0,0 +1,14 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| 1|fn main() { + 4| 1| let result + 5| 1| = + 6| 1| loop + 7| 1| { + 8| 1| break + 9| 1| 10 + 10| 1| ; + 11| 1| } + 12| 1| ; + 13| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.question_mark_error_result.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.question_mark_error_result.txt new file mode 100644 index 00000000000..ae288d7d7a0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.question_mark_error_result.txt @@ -0,0 +1,36 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |fn call(return_error: bool) -> Result<(),()> { + 5| 6| if return_error { + 6| 1| Err(()) + 7| | } else { + 8| 5| Ok(()) + 9| | } + 10| 6|} + 11| | + 12| |fn main() -> Result<(),()> { + 13| 1| let mut + 14| 1| countdown = 10 + 15| | ; + 16| 6| for + 17| 6| _ + 18| | in + 19| 1| 0..10 + 20| | { + 21| 6| countdown + 22| 6| -= 1 + 23| | ; + 24| | if + 25| 6| countdown < 5 + 26| | { + 27| 1| call(/*return_error=*/ true)?; + 28| | } + 29| | else + 30| | { + 31| 5| call(/*return_error=*/ false)?; + 32| | } + 33| | } + 34| 0| Ok(()) + 35| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_loop.txt new file mode 100644 index 00000000000..f1acb7c5459 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_loop.txt @@ -0,0 +1,36 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| | + 11| | if + 12| 1| is_true + 13| 1| { + 14| 1| countdown + 15| 1| = + 16| 1| 10 + 17| 1| ; + 18| 1| } + 19| | + 20| | loop + 21| | { + 22| | if + 23| 11| countdown + 24| 11| == + 25| 11| 0 + 26| | { + 27| 1| break + 28| | ; + 29| | } + 30| 10| countdown + 31| 10| -= + 32| 10| 1 + 33| | ; + 34| | } + 35| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_match.txt new file mode 100644 index 00000000000..e42f22cd047 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.simple_match.txt @@ -0,0 +1,44 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 1; + 10| 1| if is_true { + 11| 1| countdown = 0; + 12| 1| } + 13| | + 14| 3| for + 15| 3| _ + 16| | in + 17| 1| 0..2 + 18| | { + 19| | let z + 20| | ; + 21| | match + 22| 2| countdown + 23| 2| { + 24| 2| x + 25| 2| if + 26| 2| x + 27| 2| < + 28| 2| 1 + 29| | => + 30| 1| { + 31| 1| z = countdown + 32| 1| ; + 33| 1| let y = countdown + 34| 1| ; + 35| 1| countdown = 10 + 36| 1| ; + 37| 1| } + 38| | _ + 39| | => + 40| 1| {} + 41| | } + 42| | } + 43| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.various_conditions.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.various_conditions.txt new file mode 100644 index 00000000000..173ff4aa4c4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.various_conditions.txt @@ -0,0 +1,69 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| 1| let mut countdown = 0; + 5| 1| if true { + 6| 1| countdown = 10; + 7| 1| } + 8| | + 9| | const B: u32 = 100; + 10| 1| let x = if countdown > 7 { + 11| 1| countdown -= 4; + 12| 1| B + 13| 0| } else if countdown > 2 { + 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 15| 0| countdown = 0; + 16| 0| } + 17| 0| countdown -= 5; + 18| 0| countdown + 19| | } else { + 20| 0| return; + 21| | }; + 22| | + 23| 1| let mut countdown = 0; + 24| 1| if true { + 25| 1| countdown = 10; + 26| 1| } + 27| | + 28| 1| if countdown > 7 { + 29| 1| countdown -= 4; + 30| 0| } else if countdown > 2 { + 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 32| 0| countdown = 0; + 33| 0| } + 34| 0| countdown -= 5; + 35| | } else { + 36| 0| return; + 37| | } + 38| | + 39| 1| let mut countdown = 0; + 40| 1| if true { + 41| 1| countdown = 1; + 42| 1| } + 43| | + 44| 1| let z = if countdown > 7 { + ^0 + 45| 0| countdown -= 4; + 46| 1| } else if countdown > 2 { + 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 48| 0| countdown = 0; + 49| 0| } + 50| 0| countdown -= 5; + 51| | } else { + 52| 1| let should_be_reachable = countdown; + 53| 1| println!("reached"); + 54| 1| return; + 55| | }; + 56| | + 57| 0| let w = if countdown > 7 { + 58| 0| countdown -= 4; + 59| 0| } else if countdown > 2 { + 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 61| 0| countdown = 0; + 62| 0| } + 63| 0| countdown -= 5; + 64| | } else { + 65| 0| return; + 66| | }; + 67| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.while_early_return.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.while_early_return.txt new file mode 100644 index 00000000000..7dce94f25f3 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_show_coverage.while_early_return.txt @@ -0,0 +1,48 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |fn main() -> Result<(),u8> { + 5| 1| let mut countdown = 10; + 6| 7| while + 7| 7| countdown + 8| 7| > + 9| 7| 0 + 10| | { + 11| | if + 12| 7| countdown + 13| 7| < + 14| 7| 5 + 15| | { + 16| | return + 17| | if + 18| 1| countdown + 19| 1| > + 20| 1| 8 + 21| | { + 22| 0| Ok(()) + 23| | } + 24| | else + 25| | { + 26| 1| Err(1) + 27| | } + 28| | ; + 29| | } + 30| 6| countdown + 31| 6| -= + 32| 6| 1 + 33| | ; + 34| | } + 35| 0| Ok(()) + 36| 1|} + 37| | + 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and + 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux + 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program + 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical + 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. + 43| |// + 44| |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, + 45| |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping + 46| |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the + 47| |// problem exists on MSVC only). + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt deleted file mode 100644 index 87ce3b4048f..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt +++ /dev/null @@ -1,64 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |fn main() { - 4| | let mut countdown = 0; - 5| 2| if true { - ^1 - 6| 2| countdown = 10; - 7| 2| } - 8| | - 9| 2| if countdown > 7 { - ^1 - 10| 2| countdown -= 4; - ^1 - 11| 2| } else if countdown > 2 { - ^0 ^0 - 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 13| 0| countdown = 0; - 14| 0| } - 15| 0| countdown -= 5; - 16| 0| } else { - 17| 0| return; - 18| 0| } - 19| | - 20| | let mut countdown = 0; - 21| 2| if true { - ^1 - 22| 2| countdown = 10; - 23| 2| } - 24| | - 25| 2| if countdown > 7 { - ^1 - 26| 2| countdown -= 4; - ^1 - 27| 2| } else if countdown > 2 { - ^0 ^0 - 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 29| 0| countdown = 0; - 30| 0| } - 31| 0| countdown -= 5; - 32| 0| } else { - 33| 0| return; - 34| 0| } - 35| | - 36| | let mut countdown = 0; - 37| 2| if true { - ^1 - 38| 2| countdown = 10; - 39| 2| } - 40| | - 41| 2| if countdown > 7 { - ^1 - 42| 2| countdown -= 4; - ^1 - 43| 2| } else if countdown > 2 { - ^0 ^0 - 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 45| 0| countdown = 0; - 46| 0| } - 47| 0| countdown -= 5; - 48| 0| } else { - 49| 0| return; - 50| 0| } - 51| 1|} - diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.closure.json new file mode 100644 index 00000000000..9dbd0c4e5d6 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.closure.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/closure.rs", + "summary": { + "functions": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "instantiations": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "lines": { + "count": 91, + "covered": 75, + "percent": 82.41758241758241 + }, + "regions": { + "count": 21, + "covered": 11, + "notcovered": 10, + "percent": 52.38095238095239 + } + } + } + ], + "totals": { + "functions": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "instantiations": { + "count": 5, + "covered": 3, + "percent": 60 + }, + "lines": { + "count": 91, + "covered": 75, + "percent": 82.41758241758241 + }, + "regions": { + "count": 21, + "covered": 11, + "notcovered": 10, + "percent": 52.38095238095239 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json deleted file mode 100644 index 051250d90a2..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../instrument-coverage/coverage_of_if_else.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 19, - "percent": 47.5 - }, - "regions": { - "count": 71, - "covered": 23, - "notcovered": 48, - "percent": 32.3943661971831 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 19, - "percent": 47.5 - }, - "regions": { - "count": 71, - "covered": 23, - "notcovered": 48, - "percent": 32.3943661971831 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.drop_trait.json new file mode 100644 index 00000000000..cdfdca990fa --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.drop_trait.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/drop_trait.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 10, + "covered": 10, + "percent": 100 + }, + "regions": { + "count": 5, + "covered": 5, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 10, + "covered": 10, + "percent": 100 + }, + "regions": { + "count": 5, + "covered": 5, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.generics.json new file mode 100644 index 00000000000..ae405afedc1 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.generics.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/generics.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 16, + "percent": 100 + }, + "regions": { + "count": 6, + "covered": 6, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 16, + "percent": 100 + }, + "regions": { + "count": 6, + "covered": 6, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if.json new file mode 100644 index 00000000000..5231593d8a0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/if.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 19, + "covered": 19, + "percent": 100 + }, + "regions": { + "count": 4, + "covered": 4, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 19, + "covered": 19, + "percent": 100 + }, + "regions": { + "count": 4, + "covered": 4, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if_else.json new file mode 100644 index 00000000000..abc1afc9ab5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 28, + "covered": 19, + "percent": 67.85714285714286 + }, + "regions": { + "count": 7, + "covered": 5, + "notcovered": 2, + "percent": 71.42857142857143 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 28, + "covered": 19, + "percent": 67.85714285714286 + }, + "regions": { + "count": 7, + "covered": 5, + "notcovered": 2, + "percent": 71.42857142857143 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.inner_items.json new file mode 100644 index 00000000000..366f2afc6d7 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.inner_items.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/inner_items.rs", + "summary": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 13, + "covered": 13, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 13, + "covered": 13, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.lazy_boolean.json new file mode 100644 index 00000000000..3b052ad9106 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.lazy_boolean.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/lazy_boolean.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 19, + "percent": 90.47619047619048 + }, + "regions": { + "count": 16, + "covered": 14, + "notcovered": 2, + "percent": 87.5 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 19, + "percent": 90.47619047619048 + }, + "regions": { + "count": 16, + "covered": 14, + "notcovered": 2, + "percent": 87.5 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.loop_break_value.json new file mode 100644 index 00000000000..0b9344f86f4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.loop_break_value.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/loop_break_value.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 11, + "covered": 11, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 11, + "covered": 11, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.question_mark_error_result.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.question_mark_error_result.json new file mode 100644 index 00000000000..f2e95e4a836 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.question_mark_error_result.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/question_mark_error_result.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 15, + "percent": 93.75 + }, + "regions": { + "count": 13, + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 16, + "covered": 15, + "percent": 93.75 + }, + "regions": { + "count": 13, + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_loop.json new file mode 100644 index 00000000000..5701575189a --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_loop.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/simple_loop.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 18, + "percent": 100 + }, + "regions": { + "count": 7, + "covered": 7, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 18, + "percent": 100 + }, + "regions": { + "count": 7, + "covered": 7, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_match.json new file mode 100644 index 00000000000..df43cb9640d --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.simple_match.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/simple_match.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 9, + "covered": 9, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 26, + "covered": 26, + "percent": 100 + }, + "regions": { + "count": 9, + "covered": 9, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.various_conditions.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.various_conditions.json new file mode 100644 index 00000000000..82c80024df6 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.various_conditions.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/various_conditions.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 49, + "covered": 23, + "percent": 46.93877551020408 + }, + "regions": { + "count": 51, + "covered": 19, + "notcovered": 32, + "percent": 37.254901960784316 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 49, + "covered": 23, + "percent": 46.93877551020408 + }, + "regions": { + "count": 51, + "covered": 19, + "notcovered": 32, + "percent": 37.254901960784316 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.while_early_return.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.while_early_return.json new file mode 100644 index 00000000000..aa4e9a3c5dd --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.while_early_return.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/while_early_return.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 16, + "percent": 88.88888888888889 + }, + "regions": { + "count": 9, + "covered": 7, + "notcovered": 2, + "percent": 77.77777777777779 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 18, + "covered": 16, + "percent": 88.88888888888889 + }, + "regions": { + "count": 9, + "covered": 7, + "notcovered": 2, + "percent": 77.77777777777779 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.closure.txt new file mode 100644 index 00000000000..17054490e9b --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.closure.txt @@ -0,0 +1,94 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| let is_false = ! is_true; + 9| 1| + 10| 1| let mut some_string = Some(String::from("the string content")); + 11| 1| println!( + 12| 1| "The string or alt: {}" + 13| 1| , + 14| 1| some_string + 15| 1| . + 16| 1| unwrap_or_else + 17| 1| ( + 18| 1| || + 19| | { + 20| 0| let mut countdown = 0; + 21| 0| if is_false { + 22| 0| countdown = 10; + 23| 0| } + 24| 0| "alt string 1".to_owned() + 25| 1| } + 26| 1| ) + 27| 1| ); + 28| 1| + 29| 1| some_string = Some(String::from("the string content")); + 30| 1| let + 31| 1| a + 32| 1| = + 33| 1| || + 34| | { + 35| 0| let mut countdown = 0; + 36| 0| if is_false { + 37| 0| countdown = 10; + 38| 0| } + 39| 0| "alt string 2".to_owned() + 40| 1| }; + 41| 1| println!( + 42| 1| "The string or alt: {}" + 43| 1| , + 44| 1| some_string + 45| 1| . + 46| 1| unwrap_or_else + 47| 1| ( + 48| 1| a + 49| 1| ) + 50| 1| ); + 51| 1| + 52| 1| some_string = None; + 53| 1| println!( + 54| 1| "The string or alt: {}" + 55| 1| , + 56| 1| some_string + 57| 1| . + 58| 1| unwrap_or_else + 59| 1| ( + 60| 1| || + 61| | { + 62| 1| let mut countdown = 0; + 63| 1| if is_false { + 64| 0| countdown = 10; + 65| 0| } + 66| 1| "alt string 3".to_owned() + 67| 1| } + 68| 1| ) + 69| 1| ); + 70| 1| + 71| 1| some_string = None; + 72| 1| let + 73| 1| a + 74| 1| = + 75| 1| || + 76| | { + 77| 1| let mut countdown = 0; + 78| 1| if is_false { + 79| 0| countdown = 10; + 80| 0| } + 81| 1| "alt string 4".to_owned() + 82| 1| }; + 83| 1| println!( + 84| 1| "The string or alt: {}" + 85| 1| , + 86| 1| some_string + 87| 1| . + 88| 1| unwrap_or_else + 89| 1| ( + 90| 1| a + 91| 1| ) + 92| 1| ); + 93| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.drop_trait.txt new file mode 100644 index 00000000000..72aa020ca16 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.drop_trait.txt @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |struct Firework { + 5| | strength: i32, + 6| |} + 7| | + 8| |impl Drop for Firework { + 9| 2| fn drop(&mut self) { + 10| 2| println!("BOOM times {}!!!", self.strength); + 11| 2| } + 12| |} + 13| | + 14| |fn main() -> Result<(),u8> { + 15| 1| let _firecracker = Firework { strength: 1 }; + 16| 1| + 17| 1| let _tnt = Firework { strength: 100 }; + 18| | + 19| 1| if true { + 20| 1| println!("Exiting with error..."); + 21| 1| return Err(1); + 22| | } + 23| | + 24| | let _ = Firework { strength: 1000 }; + 25| | + 26| | Ok(()) + 27| 1|} + 28| | + 29| |// Expected program output: + 30| |// Exiting with error... + 31| |// BOOM times 100!!! + 32| |// BOOM times 1!!! + 33| |// Error: 1 + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.generics.txt new file mode 100644 index 00000000000..86199d74763 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.generics.txt @@ -0,0 +1,67 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |struct Firework where T: Copy + std::fmt::Display { + 5| | strength: T, + 6| |} + 7| | + 8| |impl Firework where T: Copy + std::fmt::Display { + 9| | #[inline(always)] + 10| 3| fn set_strength(&mut self, new_strength: T) { + 11| 3| self.strength = new_strength; + 12| 3| } + ------------------ + | >::set_strength: + | 10| 2| fn set_strength(&mut self, new_strength: T) { + | 11| 2| self.strength = new_strength; + | 12| 2| } + ------------------ + | >::set_strength: + | 10| 1| fn set_strength(&mut self, new_strength: T) { + | 11| 1| self.strength = new_strength; + | 12| 1| } + ------------------ + 13| |} + 14| | + 15| |impl Drop for Firework where T: Copy + std::fmt::Display { + 16| | #[inline(always)] + 17| 2| fn drop(&mut self) { + 18| 2| println!("BOOM times {}!!!", self.strength); + 19| 2| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + 20| |} + 21| | + 22| |fn main() -> Result<(),u8> { + 23| 1| let mut firecracker = Firework { strength: 1 }; + 24| 1| firecracker.set_strength(2); + 25| 1| + 26| 1| let mut tnt = Firework { strength: 100.1 }; + 27| 1| tnt.set_strength(200.1); + 28| 1| tnt.set_strength(300.3); + 29| | + 30| 1| if true { + 31| 1| println!("Exiting with error..."); + 32| 1| return Err(1); + 33| | } + 34| | + 35| | let _ = Firework { strength: 1000 }; + 36| | + 37| | Ok(()) + 38| 1|} + 39| | + 40| |// Expected program output: + 41| |// Exiting with error... + 42| |// BOOM times 100!!! + 43| |// BOOM times 1!!! + 44| |// Error: 1 + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if.txt new file mode 100644 index 00000000000..bc2f9b108b2 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if.txt @@ -0,0 +1,29 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| | let + 8| 1| is_true + 9| 1| = + 10| 1| std::env::args().len() + 11| 1| == + 12| 1| 1 + 13| 1| ; + 14| 1| let + 15| 1| mut + 16| 1| countdown + 17| 1| = + 18| 1| 0 + 19| | ; + 20| | if + 21| 1| is_true + 22| 1| { + 23| 1| countdown + 24| 1| = + 25| 1| 10 + 26| 1| ; + 27| 1| } + 28| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if_else.txt new file mode 100644 index 00000000000..5f899723e25 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.if_else.txt @@ -0,0 +1,41 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if + 11| 1| is_true + 12| 1| { + 13| 1| countdown + 14| 1| = + 15| 1| 10 + 16| 1| ; + 17| 1| } + 18| | else // Note coverage region difference without semicolon + 19| | { + 20| 0| countdown + 21| 0| = + 22| 0| 100 + 23| | } + 24| | + 25| | if + 26| 1| is_true + 27| 1| { + 28| 1| countdown + 29| 1| = + 30| 1| 10 + 31| 1| ; + 32| 1| } + 33| | else + 34| 0| { + 35| 0| countdown + 36| 0| = + 37| 0| 100 + 38| 0| ; + 39| 0| } + 40| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.inner_items.txt new file mode 100644 index 00000000000..364d25b1646 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.inner_items.txt @@ -0,0 +1,58 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if is_true { + 11| 1| countdown = 10; + 12| 1| } + 13| | + 14| | mod inner_mod { + 15| | const INNER_MOD_CONST: u32 = 1000; + 16| | } + 17| | + 18| | fn inner_function(a: u32) { + 19| 3| let b = 1; + 20| 3| let c = a + b; + 21| 3| println!("c = {}", c) + 22| 3| } + 23| | + 24| | struct InnerStruct { + 25| | inner_struct_field: u32, + 26| | } + 27| | + 28| | const INNER_CONST: u32 = 1234; + 29| | + 30| | trait InnerTrait { + 31| | fn inner_trait_func(&mut self, incr: u32); + 32| | + 33| 1| fn default_trait_func(&mut self) { + 34| 1| inner_function(INNER_CONST); + 35| 1| self.inner_trait_func(INNER_CONST); + 36| 1| } + 37| | } + 38| | + 39| | impl InnerTrait for InnerStruct { + 40| | fn inner_trait_func(&mut self, incr: u32) { + 41| 1| self.inner_struct_field += incr; + 42| 1| inner_function(self.inner_struct_field); + 43| 1| } + 44| | } + 45| | + 46| | type InnerType = String; + 47| | + 48| 1| if is_true { + 49| 1| inner_function(countdown); + 50| 1| } + 51| | + 52| 1| let mut val = InnerStruct { + 53| 1| inner_struct_field: 101, + 54| 1| }; + 55| 1| + 56| 1| val.default_trait_func(); + 57| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.lazy_boolean.txt new file mode 100644 index 00000000000..ded43697515 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.lazy_boolean.txt @@ -0,0 +1,44 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); + 10| 1| if is_true { + 11| 1| a = 1; + 12| 1| b = 10; + 13| 1| c = 100; + 14| 1| } + 15| | let + 16| 1| somebool + 17| | = + 18| 1| a < b + 19| | || + 20| 0| b < c + 21| | ; + 22| | let + 23| 1| somebool + 24| | = + 25| 1| b < a + 26| | || + 27| 1| b < c + 28| | ; + 29| | let + 30| 1| somebool + 31| | = + 32| 1| a < b + 33| | && + 34| 1| b < c + 35| | ; + 36| | let + 37| 1| somebool + 38| | = + 39| 1| b < a + 40| | && + 41| 0| b < c + 42| | ; + 43| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.loop_break_value.txt new file mode 100644 index 00000000000..b0d668c6d76 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.loop_break_value.txt @@ -0,0 +1,14 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| 1|fn main() { + 4| 1| let result + 5| 1| = + 6| 1| loop + 7| 1| { + 8| 1| break + 9| 1| 10 + 10| 1| ; + 11| 1| } + 12| 1| ; + 13| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.question_mark_error_result.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.question_mark_error_result.txt new file mode 100644 index 00000000000..ae288d7d7a0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.question_mark_error_result.txt @@ -0,0 +1,36 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |fn call(return_error: bool) -> Result<(),()> { + 5| 6| if return_error { + 6| 1| Err(()) + 7| | } else { + 8| 5| Ok(()) + 9| | } + 10| 6|} + 11| | + 12| |fn main() -> Result<(),()> { + 13| 1| let mut + 14| 1| countdown = 10 + 15| | ; + 16| 6| for + 17| 6| _ + 18| | in + 19| 1| 0..10 + 20| | { + 21| 6| countdown + 22| 6| -= 1 + 23| | ; + 24| | if + 25| 6| countdown < 5 + 26| | { + 27| 1| call(/*return_error=*/ true)?; + 28| | } + 29| | else + 30| | { + 31| 5| call(/*return_error=*/ false)?; + 32| | } + 33| | } + 34| 0| Ok(()) + 35| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_loop.txt new file mode 100644 index 00000000000..f1acb7c5459 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_loop.txt @@ -0,0 +1,36 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| | + 11| | if + 12| 1| is_true + 13| 1| { + 14| 1| countdown + 15| 1| = + 16| 1| 10 + 17| 1| ; + 18| 1| } + 19| | + 20| | loop + 21| | { + 22| | if + 23| 11| countdown + 24| 11| == + 25| 11| 0 + 26| | { + 27| 1| break + 28| | ; + 29| | } + 30| 10| countdown + 31| 10| -= + 32| 10| 1 + 33| | ; + 34| | } + 35| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_match.txt new file mode 100644 index 00000000000..e42f22cd047 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.simple_match.txt @@ -0,0 +1,44 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| | // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 1; + 10| 1| if is_true { + 11| 1| countdown = 0; + 12| 1| } + 13| | + 14| 3| for + 15| 3| _ + 16| | in + 17| 1| 0..2 + 18| | { + 19| | let z + 20| | ; + 21| | match + 22| 2| countdown + 23| 2| { + 24| 2| x + 25| 2| if + 26| 2| x + 27| 2| < + 28| 2| 1 + 29| | => + 30| 1| { + 31| 1| z = countdown + 32| 1| ; + 33| 1| let y = countdown + 34| 1| ; + 35| 1| countdown = 10 + 36| 1| ; + 37| 1| } + 38| | _ + 39| | => + 40| 1| {} + 41| | } + 42| | } + 43| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.various_conditions.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.various_conditions.txt new file mode 100644 index 00000000000..173ff4aa4c4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.various_conditions.txt @@ -0,0 +1,69 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |fn main() { + 4| 1| let mut countdown = 0; + 5| 1| if true { + 6| 1| countdown = 10; + 7| 1| } + 8| | + 9| | const B: u32 = 100; + 10| 1| let x = if countdown > 7 { + 11| 1| countdown -= 4; + 12| 1| B + 13| 0| } else if countdown > 2 { + 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 15| 0| countdown = 0; + 16| 0| } + 17| 0| countdown -= 5; + 18| 0| countdown + 19| | } else { + 20| 0| return; + 21| | }; + 22| | + 23| 1| let mut countdown = 0; + 24| 1| if true { + 25| 1| countdown = 10; + 26| 1| } + 27| | + 28| 1| if countdown > 7 { + 29| 1| countdown -= 4; + 30| 0| } else if countdown > 2 { + 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 32| 0| countdown = 0; + 33| 0| } + 34| 0| countdown -= 5; + 35| | } else { + 36| 0| return; + 37| | } + 38| | + 39| 1| let mut countdown = 0; + 40| 1| if true { + 41| 1| countdown = 1; + 42| 1| } + 43| | + 44| 1| let z = if countdown > 7 { + ^0 + 45| 0| countdown -= 4; + 46| 1| } else if countdown > 2 { + 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 48| 0| countdown = 0; + 49| 0| } + 50| 0| countdown -= 5; + 51| | } else { + 52| 1| let should_be_reachable = countdown; + 53| 1| println!("reached"); + 54| 1| return; + 55| | }; + 56| | + 57| 0| let w = if countdown > 7 { + 58| 0| countdown -= 4; + 59| 0| } else if countdown > 2 { + 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 61| 0| countdown = 0; + 62| 0| } + 63| 0| countdown -= 5; + 64| | } else { + 65| 0| return; + 66| | }; + 67| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.while_early_return.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.while_early_return.txt new file mode 100644 index 00000000000..7dce94f25f3 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_show_coverage.while_early_return.txt @@ -0,0 +1,48 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |fn main() -> Result<(),u8> { + 5| 1| let mut countdown = 10; + 6| 7| while + 7| 7| countdown + 8| 7| > + 9| 7| 0 + 10| | { + 11| | if + 12| 7| countdown + 13| 7| < + 14| 7| 5 + 15| | { + 16| | return + 17| | if + 18| 1| countdown + 19| 1| > + 20| 1| 8 + 21| | { + 22| 0| Ok(()) + 23| | } + 24| | else + 25| | { + 26| 1| Err(1) + 27| | } + 28| | ; + 29| | } + 30| 6| countdown + 31| 6| -= + 32| 6| 1 + 33| | ; + 34| | } + 35| 0| Ok(()) + 36| 1|} + 37| | + 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and + 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux + 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program + 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical + 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. + 43| |// + 44| |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, + 45| |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping + 46| |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the + 47| |// problem exists on MSVC only). + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt deleted file mode 100644 index 87ce3b4048f..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt +++ /dev/null @@ -1,64 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |fn main() { - 4| | let mut countdown = 0; - 5| 2| if true { - ^1 - 6| 2| countdown = 10; - 7| 2| } - 8| | - 9| 2| if countdown > 7 { - ^1 - 10| 2| countdown -= 4; - ^1 - 11| 2| } else if countdown > 2 { - ^0 ^0 - 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 13| 0| countdown = 0; - 14| 0| } - 15| 0| countdown -= 5; - 16| 0| } else { - 17| 0| return; - 18| 0| } - 19| | - 20| | let mut countdown = 0; - 21| 2| if true { - ^1 - 22| 2| countdown = 10; - 23| 2| } - 24| | - 25| 2| if countdown > 7 { - ^1 - 26| 2| countdown -= 4; - ^1 - 27| 2| } else if countdown > 2 { - ^0 ^0 - 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 29| 0| countdown = 0; - 30| 0| } - 31| 0| countdown -= 5; - 32| 0| } else { - 33| 0| return; - 34| 0| } - 35| | - 36| | let mut countdown = 0; - 37| 2| if true { - ^1 - 38| 2| countdown = 10; - 39| 2| } - 40| | - 41| 2| if countdown > 7 { - ^1 - 42| 2| countdown -= 4; - ^1 - 43| 2| } else if countdown > 2 { - ^0 ^0 - 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 45| 0| countdown = 0; - 46| 0| } - 47| 0| countdown -= 5; - 48| 0| } else { - 49| 0| return; - 50| 0| } - 51| 1|} - diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile index ba2126a6b3f..c42530e233e 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile @@ -8,4 +8,4 @@ LINK_DEAD_CODE=yes # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile index 5cd425979ea..f59c72dd399 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile @@ -20,12 +20,9 @@ endif -include clear_expected_if_blessed %: $(SOURCEDIR)/%.rs - # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. - # - # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are - # satisfied with the branch-level instrumentation. + # Compile the test program with coverage instrumentation and generate relevant MIR. $(RUSTC) $(SOURCEDIR)/$@.rs \ - -Zexperimental-coverage \ + -Zinstrument-coverage \ -Clink-dead-code=$(LINK_DEAD_CODE) \ -Zdump-mir=InstrumentCoverage \ -Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@ diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..43f75c574d0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#0} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 2".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..8f07ec5fcde --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#1} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 4".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..ca9031a1094 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#2} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 1".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..820f8d9c6cf --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#3} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 3".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..740db365864 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,4505 @@ + + + +closure.main - Coverage Spans + + + +
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = ! is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ + ) + ); + + some_string = None; + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index fcb6afb2636..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,641 +0,0 @@ - - - - coverage_of_if_else - Code Regions - - - -
fn main() { - let mut countdown = 0; - 1⦊3⦊2⦊if 0⦊true⦉0 { - countdown = 10; - }⦉2⦉3⦉1 - - 5⦊8⦊24⦊if 4⦊countdown > 7⦉4 { - 7⦊countdown -= 4⦉7; - } else 9⦊if 6⦊countdown > 2⦉6 { - 20⦊22⦊21⦊if 14⦊11⦊13⦊19⦊15⦊12⦊16⦊17⦊18⦊countdown < 1 || countdown > 5⦉18⦉17⦉16 || countdown != 9⦉12⦉15⦉19⦉13⦉11⦉14 { - countdown = 0; - 23⦊}⦉20⦉22⦉21⦉21 - countdown -= 5⦉23; - } else { - return; - }⦉9⦉24⦉8⦉5 - - let mut countdown = 0; - 27⦊28⦊26⦊if 25⦊true⦉25 { - countdown = 10; - }⦉26⦉28⦉27 - - 49⦊33⦊30⦊if 29⦊countdown > 7⦉29 { - 32⦊countdown -= 4⦉32; - } else 34⦊if 31⦊countdown > 2⦉31 { - 46⦊47⦊45⦊if 44⦊38⦊39⦊40⦊36⦊37⦊41⦊42⦊43⦊countdown < 1 || countdown > 5⦉43⦉42⦉41 || countdown != 9⦉37⦉36⦉40⦉39⦉38⦉44 { - countdown = 0; - 48⦊}⦉46⦉47⦉45⦉45 - countdown -= 5⦉48; - } else { - return; - }⦉34⦉30⦉33⦉49 - - let mut countdown = 0; - 52⦊51⦊53⦊if 50⦊true⦉50 { - countdown = 10; - }⦉53⦉51⦉52 - - 74⦊55⦊58⦊if 54⦊countdown > 7⦉54 { - 57⦊countdown -= 4⦉57; - } else 59⦊if 56⦊countdown > 2⦉56 { - 71⦊72⦊70⦊if 63⦊64⦊65⦊62⦊69⦊61⦊67⦊68⦊66⦊countdown < 1 || countdown > 5⦉66⦉68⦉67 || countdown != 9⦉61⦉69⦉62⦉65⦉64⦉63 { - countdown = 0; - 73⦊}⦉71⦉72⦉70⦉70 - countdown -= 5⦉73; - } else { - return; - }⦉59⦉58⦉55⦉74 -75⦊}⦉7577⦊⦉77
- - diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..494e6f20ea7 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + +drop_trait.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊_firecracker = Firework { strength: 1 }; + + let _tnt = Firework { strength: 100 }⦉@0; + + if @0⦊true⦉@0 { + @1,3,4,5,9,10⦊println!("Exiting with error..."); + return Err(1)⦉@1,3,4,5,9,10; + } + + let _ = @2,6,7,8⦊Firework { strength: 1000 }; + + Ok(())⦉@2,6,7,8 +}@11⦊⦉@11
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9530d12fb49 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html @@ -0,0 +1,123 @@ + + + +drop_trait.{impl#0}-drop - Coverage Spans + + + +
fn drop(&mut self) @0,1,2,3⦊{ + println!("BOOM times {}!!!", self.strength); + }⦉@0,1,2,3
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6dc893d28ff --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,167 @@ + + + +generics.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0,1,2,3⦊mut firecracker = Firework { strength: 1 }; + firecracker.set_strength(2); + + let mut tnt = Firework { strength: 100.1 }; + tnt.set_strength(200.1); + tnt.set_strength(300.3)⦉@0,1,2,3; + + if @0,1,2,3⦊true⦉@0,1,2,3 { + @4,6,7,8,12,13⦊println!("Exiting with error..."); + return Err(1)⦉@4,6,7,8,12,13; + } + + let _ = @5,9,10,11⦊Firework { strength: 1000 }; + + Ok(())⦉@5,9,10,11 +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..e31e47b81d4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + +generics.{impl#0}-set_strength - Coverage Spans + + + +
fn set_strength(&mut self, new_strength: T) @0⦊{ + self.strength = new_strength; + }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..99a7df4a670 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html @@ -0,0 +1,123 @@ + + + +generics.{impl#1}-drop - Coverage Spans + + + +
fn drop(&mut self) @0,1,2,3⦊{ + println!("BOOM times {}!!!", self.strength); + }⦉@0,1,2,3
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..0379d900e94 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,162 @@ + + + +if.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let + @0,1,2,3⦊is_true + = + std::env::args().len() + == + 1 + ; + let + mut + countdown + = + 0⦉@0,1,2,3 + ; + if + @0,1,2,3⦊is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b51c5c84c0d --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,163 @@ + + + +if_else.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if + is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 + else // Note coverage region difference without semicolon + { + @5⦊countdown + = + 100⦉@5 + } + + if + @7⦊is_true⦉@7 + @8,10⦊{ + countdown + = + 10 + ; + }⦉@8,10 + else + @9⦊{ + countdown + = + 100 + ; + }⦉@9 +}@11⦊⦉@11
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6998bb32a3f --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html @@ -0,0 +1,83 @@ + + + +inner_items.main-InnerTrait-default_trait_func - Coverage Spans + + + +
fn default_trait_func(&mut self) @0,1,2⦊{ + inner_function(INNER_CONST); + self.inner_trait_func(INNER_CONST); + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..c87ff329f3f --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,107 @@ + + + +inner_items.main-inner_function - Coverage Spans + + + +
fn inner_function(a: u32) { + let @0⦊b = 1⦉@0; + let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; + @1,2,3,4⦊println!("c = {}", c) + }⦉@1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..1dc29d400d8 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html @@ -0,0 +1,72 @@ + + + +inner_items.main-{impl#0}-inner_trait_func - Coverage Spans + + + +
fn inner_trait_func(&mut self, incr: u32) { + @0⦊self.inner_struct_field += incr⦉@0; + @1,2⦊inner_function(self.inner_struct_field); + }⦉@1,2
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9a1256025d9 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,171 @@ + + + +inner_items.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6 + + mod inner_mod { + const INNER_MOD_CONST: u32 = 1000; + } + + fn inner_function(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + } + + struct InnerStruct { + inner_struct_field: u32, + } + + const INNER_CONST: u32 = 1234; + + trait InnerTrait { + fn inner_trait_func(&mut self, incr: u32); + + fn default_trait_func(&mut self) { + inner_function(INNER_CONST); + self.inner_trait_func(INNER_CONST); + } + } + + impl InnerTrait for InnerStruct { + fn inner_trait_func(&mut self, incr: u32) { + self.inner_struct_field += incr; + inner_function(self.inner_struct_field); + } + } + + type InnerType = String; + + if @7⦊is_true⦉@7 @8,10,11⦊{ + inner_function(countdown); + }⦉@8,10,11 + + let @12,13⦊mut val = InnerStruct { + inner_struct_field: 101, + }; + + val.default_trait_func(); +}⦉@12,13
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..defe743df60 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,160 @@ + + + +lazy_boolean.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0)⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + a = 1; + b = 10; + c = 100; + }⦉@4,6 + let + @11⦊somebool⦉@11 + = + @7⦊a < b⦉@7 + || + @10⦊b < c⦉@10 + ; + let + @15⦊somebool⦉@15 + = + @11⦊b < a⦉@11 + || + @14⦊b < c⦉@14 + ; + let + @19⦊somebool⦉@19 + = + @15⦊a < b⦉@15 + && + @18⦊b < c⦉@18 + ; + let + @23⦊somebool⦉@23 + = + @19⦊b < a⦉@19 + && + @22⦊b < c⦉@22 + ; +}@23⦊⦉@23
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..dc26c796637 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,118 @@ + + + +loop_break_value.main - Coverage Spans + + + +
fn main() @0,1⦊{ + let result + = + loop + { + break + 10 + ; + } + ; +}⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..0c253d5e5c2 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html @@ -0,0 +1,73 @@ + + + +question_mark_error_result.call - Coverage Spans + + + +
fn call(return_error: bool) -> Result<(),()> { + if @0⦊return_error⦉@0 { + @1,3⦊Err(())⦉@1,3 + } else { + @2⦊Ok(())⦉@2 + } +}@4⦊⦉@4
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2589b0454da --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,101 @@ + + + +question_mark_error_result.main - Coverage Spans + + + +
fn main() -> Result<(),()> { + let @0,1⦊mut + countdown = 10⦉@0,1 + ; + @2,3,4⦊for + _⦉@2,3,4 + in + @0,1⦊0..10⦉@0,1 + { + @6,8⦊countdown + -= 1⦉@6,8 + ; + if + @9⦊countdown < 5⦉@9 + { + @10,12,13,14⦊call(/*return_error=*/ true)?⦉@10,12,13,14; + } + else + { + @11,21,22⦊call(/*return_error=*/ false)?⦉@11,21,22; + } + } + @5⦊Ok(())⦉@5 +}@31⦊⦉@31
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4b21d3fc263 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,127 @@ + + + +simple_loop.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0⦉@0,1,2,3; + + if + @0,1,2,3⦊is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 + + loop + { + if + @8,9⦊countdown + == + 0⦉@8,9 + { + @10,12⦊break⦉@10,12 + ; + } + @11⦊countdown + -= + 1⦉@11 + ; + } +}@10,12⦊⦉@10,12
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..5ba770ef607 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,190 @@ + + + +simple_match.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 1⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 0; + }⦉@4,6 + + @9,10,11⦊for + _⦉@9,10,11 + in + @7,8⦊0..2⦉@7,8 + { + let z + ; + match + @13,15,17⦊countdown + { + x + if + x + < + 1⦉@13,15,17 + => + @18⦊{ + z = countdown + ; + let y = countdown + ; + countdown = 10 + ; + }⦉@18 + _ + => + @16⦊{}⦉@16 + } + } +}@12⦊⦉@12
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..28f1d013c83 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,228 @@ + + + +various_conditions.main - Coverage Spans + + + +
fn main() { + let @0⦊mut countdown = 0⦉@0; + if @0⦊true⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + + const B: u32 = 100; + let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { + @5,7⦊countdown -= 4⦉@5,7; + @8⦊B⦉@8 + } else if @6⦊countdown > 2⦉@6 { + if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18 || @14⦊countdown != 9⦉@14 @20,22⦊{ + countdown = 0; + }⦉@20,22 + @23⦊countdown -= 5⦉@23; + @24⦊countdown⦉@24 + } else { + @10⦊return⦉@10; + }; + + let @25⦊mut countdown = 0⦉@25; + if @25⦊true⦉@25 @26,28⦊{ + countdown = 10; + }⦉@26,28 + + if @29⦊countdown > 7⦉@29 { + @30,32⦊countdown -= 4⦉@30,32; + } else if @31⦊countdown > 2⦉@31 { + if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43 || @39⦊countdown != 9⦉@39 @45,47⦊{ + countdown = 0; + }⦉@45,47 + @48⦊countdown -= 5⦉@48; + } else { + @35⦊return⦉@35; + } + + let @50⦊mut countdown = 0⦉@50; + if @50⦊true⦉@50 @51,53⦊{ + countdown = 1; + }⦉@51,53 + + let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { + @55,57⦊countdown -= 4⦉@55,57; + } else if @56⦊countdown > 2⦉@56 { + if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68 || @64⦊countdown != 9⦉@64 @70,72⦊{ + countdown = 0; + }⦉@70,72 + @73⦊countdown -= 5⦉@73; + } else { + let @60,75,76⦊should_be_reachable = countdown; + println!("reached"); + return⦉@60,75,76; + }; + + let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { + @78,80⦊countdown -= 4⦉@78,80; + } else if @79⦊countdown > 2⦉@79 { + if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91 || @87⦊countdown != 9⦉@87 @93,95⦊{ + countdown = 0; + }⦉@93,95 + @96⦊countdown -= 5⦉@96; + } else { + @83⦊return⦉@83; + }; +}@102⦊⦉@102
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b96789a9219 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + +while_early_return.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + @1,2⦊while + countdown + > + 0⦉@1,2 + { + if + @3,5⦊countdown + < + 5⦉@3,5 + { + return + if + @6,8⦊countdown + > + 8⦉@6,8 + { + @9,11⦊Ok(())⦉@9,11 + } + else + { + @10⦊Err(1)⦉@10 + } + ; + } + @7⦊countdown + -= + 1⦉@7 + ; + } + @4⦊Ok(())⦉@4 +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile index 0578949b3c8..2d82c3b3453 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile @@ -8,4 +8,4 @@ LINK_DEAD_CODE=yes # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..43f75c574d0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#0} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 2".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..8f07ec5fcde --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#1} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 4".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..ca9031a1094 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#2} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 1".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..820f8d9c6cf --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + +closure.main-{closure#3} - Coverage Spans + + + +
|| + { + let @0⦊mut countdown = 0⦉@0; + if @0⦊is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + @4,5⦊"alt string 3".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..740db365864 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,4505 @@ + + + +closure.main - Coverage Spans + + + +
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = ! is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ + ) + ); + + some_string = None; + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index fcb6afb2636..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,641 +0,0 @@ - - - - coverage_of_if_else - Code Regions - - - -
fn main() { - let mut countdown = 0; - 1⦊3⦊2⦊if 0⦊true⦉0 { - countdown = 10; - }⦉2⦉3⦉1 - - 5⦊8⦊24⦊if 4⦊countdown > 7⦉4 { - 7⦊countdown -= 4⦉7; - } else 9⦊if 6⦊countdown > 2⦉6 { - 20⦊22⦊21⦊if 14⦊11⦊13⦊19⦊15⦊12⦊16⦊17⦊18⦊countdown < 1 || countdown > 5⦉18⦉17⦉16 || countdown != 9⦉12⦉15⦉19⦉13⦉11⦉14 { - countdown = 0; - 23⦊}⦉20⦉22⦉21⦉21 - countdown -= 5⦉23; - } else { - return; - }⦉9⦉24⦉8⦉5 - - let mut countdown = 0; - 27⦊28⦊26⦊if 25⦊true⦉25 { - countdown = 10; - }⦉26⦉28⦉27 - - 49⦊33⦊30⦊if 29⦊countdown > 7⦉29 { - 32⦊countdown -= 4⦉32; - } else 34⦊if 31⦊countdown > 2⦉31 { - 46⦊47⦊45⦊if 44⦊38⦊39⦊40⦊36⦊37⦊41⦊42⦊43⦊countdown < 1 || countdown > 5⦉43⦉42⦉41 || countdown != 9⦉37⦉36⦉40⦉39⦉38⦉44 { - countdown = 0; - 48⦊}⦉46⦉47⦉45⦉45 - countdown -= 5⦉48; - } else { - return; - }⦉34⦉30⦉33⦉49 - - let mut countdown = 0; - 52⦊51⦊53⦊if 50⦊true⦉50 { - countdown = 10; - }⦉53⦉51⦉52 - - 74⦊55⦊58⦊if 54⦊countdown > 7⦉54 { - 57⦊countdown -= 4⦉57; - } else 59⦊if 56⦊countdown > 2⦉56 { - 71⦊72⦊70⦊if 63⦊64⦊65⦊62⦊69⦊61⦊67⦊68⦊66⦊countdown < 1 || countdown > 5⦉66⦉68⦉67 || countdown != 9⦉61⦉69⦉62⦉65⦉64⦉63 { - countdown = 0; - 73⦊}⦉71⦉72⦉70⦉70 - countdown -= 5⦉73; - } else { - return; - }⦉59⦉58⦉55⦉74 -75⦊}⦉7577⦊⦉77
- - diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..494e6f20ea7 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + +drop_trait.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊_firecracker = Firework { strength: 1 }; + + let _tnt = Firework { strength: 100 }⦉@0; + + if @0⦊true⦉@0 { + @1,3,4,5,9,10⦊println!("Exiting with error..."); + return Err(1)⦉@1,3,4,5,9,10; + } + + let _ = @2,6,7,8⦊Firework { strength: 1000 }; + + Ok(())⦉@2,6,7,8 +}@11⦊⦉@11
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9530d12fb49 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html @@ -0,0 +1,123 @@ + + + +drop_trait.{impl#0}-drop - Coverage Spans + + + +
fn drop(&mut self) @0,1,2,3⦊{ + println!("BOOM times {}!!!", self.strength); + }⦉@0,1,2,3
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6dc893d28ff --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,167 @@ + + + +generics.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0,1,2,3⦊mut firecracker = Firework { strength: 1 }; + firecracker.set_strength(2); + + let mut tnt = Firework { strength: 100.1 }; + tnt.set_strength(200.1); + tnt.set_strength(300.3)⦉@0,1,2,3; + + if @0,1,2,3⦊true⦉@0,1,2,3 { + @4,6,7,8,12,13⦊println!("Exiting with error..."); + return Err(1)⦉@4,6,7,8,12,13; + } + + let _ = @5,9,10,11⦊Firework { strength: 1000 }; + + Ok(())⦉@5,9,10,11 +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..e31e47b81d4 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + +generics.{impl#0}-set_strength - Coverage Spans + + + +
fn set_strength(&mut self, new_strength: T) @0⦊{ + self.strength = new_strength; + }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..99a7df4a670 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html @@ -0,0 +1,123 @@ + + + +generics.{impl#1}-drop - Coverage Spans + + + +
fn drop(&mut self) @0,1,2,3⦊{ + println!("BOOM times {}!!!", self.strength); + }⦉@0,1,2,3
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..0379d900e94 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,162 @@ + + + +if.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let + @0,1,2,3⦊is_true + = + std::env::args().len() + == + 1 + ; + let + mut + countdown + = + 0⦉@0,1,2,3 + ; + if + @0,1,2,3⦊is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b51c5c84c0d --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,163 @@ + + + +if_else.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if + is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 + else // Note coverage region difference without semicolon + { + @5⦊countdown + = + 100⦉@5 + } + + if + @7⦊is_true⦉@7 + @8,10⦊{ + countdown + = + 10 + ; + }⦉@8,10 + else + @9⦊{ + countdown + = + 100 + ; + }⦉@9 +}@11⦊⦉@11
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6998bb32a3f --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-InnerTrait-default_trait_func.-------.InstrumentCoverage.0.html @@ -0,0 +1,83 @@ + + + +inner_items.main-InnerTrait-default_trait_func - Coverage Spans + + + +
fn default_trait_func(&mut self) @0,1,2⦊{ + inner_function(INNER_CONST); + self.inner_trait_func(INNER_CONST); + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..c87ff329f3f --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-inner_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,107 @@ + + + +inner_items.main-inner_function - Coverage Spans + + + +
fn inner_function(a: u32) { + let @0⦊b = 1⦉@0; + let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; + @1,2,3,4⦊println!("c = {}", c) + }⦉@1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..1dc29d400d8 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main-{impl#0}-inner_trait_func.-------.InstrumentCoverage.0.html @@ -0,0 +1,72 @@ + + + +inner_items.main-{impl#0}-inner_trait_func - Coverage Spans + + + +
fn inner_trait_func(&mut self, incr: u32) { + @0⦊self.inner_struct_field += incr⦉@0; + @1,2⦊inner_function(self.inner_struct_field); + }⦉@1,2
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9a1256025d9 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,171 @@ + + + +inner_items.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6 + + mod inner_mod { + const INNER_MOD_CONST: u32 = 1000; + } + + fn inner_function(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + } + + struct InnerStruct { + inner_struct_field: u32, + } + + const INNER_CONST: u32 = 1234; + + trait InnerTrait { + fn inner_trait_func(&mut self, incr: u32); + + fn default_trait_func(&mut self) { + inner_function(INNER_CONST); + self.inner_trait_func(INNER_CONST); + } + } + + impl InnerTrait for InnerStruct { + fn inner_trait_func(&mut self, incr: u32) { + self.inner_struct_field += incr; + inner_function(self.inner_struct_field); + } + } + + type InnerType = String; + + if @7⦊is_true⦉@7 @8,10,11⦊{ + inner_function(countdown); + }⦉@8,10,11 + + let @12,13⦊mut val = InnerStruct { + inner_struct_field: 101, + }; + + val.default_trait_func(); +}⦉@12,13
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..defe743df60 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,160 @@ + + + +lazy_boolean.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0)⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + a = 1; + b = 10; + c = 100; + }⦉@4,6 + let + @11⦊somebool⦉@11 + = + @7⦊a < b⦉@7 + || + @10⦊b < c⦉@10 + ; + let + @15⦊somebool⦉@15 + = + @11⦊b < a⦉@11 + || + @14⦊b < c⦉@14 + ; + let + @19⦊somebool⦉@19 + = + @15⦊a < b⦉@15 + && + @18⦊b < c⦉@18 + ; + let + @23⦊somebool⦉@23 + = + @19⦊b < a⦉@19 + && + @22⦊b < c⦉@22 + ; +}@23⦊⦉@23
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..dc26c796637 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,118 @@ + + + +loop_break_value.main - Coverage Spans + + + +
fn main() @0,1⦊{ + let result + = + loop + { + break + 10 + ; + } + ; +}⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..0c253d5e5c2 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.call.-------.InstrumentCoverage.0.html @@ -0,0 +1,73 @@ + + + +question_mark_error_result.call - Coverage Spans + + + +
fn call(return_error: bool) -> Result<(),()> { + if @0⦊return_error⦉@0 { + @1,3⦊Err(())⦉@1,3 + } else { + @2⦊Ok(())⦉@2 + } +}@4⦊⦉@4
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2589b0454da --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.question_mark_error_result/question_mark_error_result.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,101 @@ + + + +question_mark_error_result.main - Coverage Spans + + + +
fn main() -> Result<(),()> { + let @0,1⦊mut + countdown = 10⦉@0,1 + ; + @2,3,4⦊for + _⦉@2,3,4 + in + @0,1⦊0..10⦉@0,1 + { + @6,8⦊countdown + -= 1⦉@6,8 + ; + if + @9⦊countdown < 5⦉@9 + { + @10,12,13,14⦊call(/*return_error=*/ true)?⦉@10,12,13,14; + } + else + { + @11,21,22⦊call(/*return_error=*/ false)?⦉@11,21,22; + } + } + @5⦊Ok(())⦉@5 +}@31⦊⦉@31
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4b21d3fc263 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,127 @@ + + + +simple_loop.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 0⦉@0,1,2,3; + + if + @0,1,2,3⦊is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6 + + loop + { + if + @8,9⦊countdown + == + 0⦉@8,9 + { + @10,12⦊break⦉@10,12 + ; + } + @11⦊countdown + -= + 1⦉@11 + ; + } +}@10,12⦊⦉@10,12
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..5ba770ef607 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,190 @@ + + + +simple_match.main - Coverage Spans + + + +
fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + + let mut countdown = 1⦉@0,1,2,3; + if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 0; + }⦉@4,6 + + @9,10,11⦊for + _⦉@9,10,11 + in + @7,8⦊0..2⦉@7,8 + { + let z + ; + match + @13,15,17⦊countdown + { + x + if + x + < + 1⦉@13,15,17 + => + @18⦊{ + z = countdown + ; + let y = countdown + ; + countdown = 10 + ; + }⦉@18 + _ + => + @16⦊{}⦉@16 + } + } +}@12⦊⦉@12
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..28f1d013c83 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,228 @@ + + + +various_conditions.main - Coverage Spans + + + +
fn main() { + let @0⦊mut countdown = 0⦉@0; + if @0⦊true⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3 + + const B: u32 = 100; + let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { + @5,7⦊countdown -= 4⦉@5,7; + @8⦊B⦉@8 + } else if @6⦊countdown > 2⦉@6 { + if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18 || @14⦊countdown != 9⦉@14 @20,22⦊{ + countdown = 0; + }⦉@20,22 + @23⦊countdown -= 5⦉@23; + @24⦊countdown⦉@24 + } else { + @10⦊return⦉@10; + }; + + let @25⦊mut countdown = 0⦉@25; + if @25⦊true⦉@25 @26,28⦊{ + countdown = 10; + }⦉@26,28 + + if @29⦊countdown > 7⦉@29 { + @30,32⦊countdown -= 4⦉@30,32; + } else if @31⦊countdown > 2⦉@31 { + if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43 || @39⦊countdown != 9⦉@39 @45,47⦊{ + countdown = 0; + }⦉@45,47 + @48⦊countdown -= 5⦉@48; + } else { + @35⦊return⦉@35; + } + + let @50⦊mut countdown = 0⦉@50; + if @50⦊true⦉@50 @51,53⦊{ + countdown = 1; + }⦉@51,53 + + let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { + @55,57⦊countdown -= 4⦉@55,57; + } else if @56⦊countdown > 2⦉@56 { + if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68 || @64⦊countdown != 9⦉@64 @70,72⦊{ + countdown = 0; + }⦉@70,72 + @73⦊countdown -= 5⦉@73; + } else { + let @60,75,76⦊should_be_reachable = countdown; + println!("reached"); + return⦉@60,75,76; + }; + + let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { + @78,80⦊countdown -= 4⦉@78,80; + } else if @79⦊countdown > 2⦉@79 { + if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91 || @87⦊countdown != 9⦉@87 @93,95⦊{ + countdown = 0; + }⦉@93,95 + @96⦊countdown -= 5⦉@96; + } else { + @83⦊return⦉@83; + }; +}@102⦊⦉@102
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b96789a9219 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + +while_early_return.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + @1,2⦊while + countdown + > + 0⦉@1,2 + { + if + @3,5⦊countdown + < + 5⦉@3,5 + { + return + if + @6,8⦊countdown + > + 8⦉@6,8 + { + @9,11⦊Ok(())⦉@9,11 + } + else + { + @10⦊Err(1)⦉@10 + } + ; + } + @7⦊countdown + -= + 1⦉@7 + ; + } + @4⦊Ok(())⦉@4 +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/instrument-coverage/closure.rs b/src/test/run-make-fulldeps/instrument-coverage/closure.rs new file mode 100644 index 00000000000..66bbbc55399 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/closure.rs @@ -0,0 +1,93 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = ! is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + } + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + } + ) + ); + + some_string = None; + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir index d57f66a4489..abf8df8fdc9 100644 --- a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir +++ b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir @@ -1,3 +1,3 @@ # Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* -# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. \ No newline at end of file +# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs deleted file mode 100644 index 91741cf8f0d..00000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![allow(unused_assignments)] - -fn main() { - let mut countdown = 0; - if true { - countdown = 10; - } - - if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - } - - let mut countdown = 0; - if true { - countdown = 10; - } - - if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - } - - let mut countdown = 0; - if true { - countdown = 10; - } - - if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - } -} diff --git a/src/test/run-make-fulldeps/instrument-coverage/drop_trait.rs b/src/test/run-make-fulldeps/instrument-coverage/drop_trait.rs new file mode 100644 index 00000000000..d15bfc0f877 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/drop_trait.rs @@ -0,0 +1,33 @@ +#![allow(unused_assignments)] +// expect-exit-status-1 + +struct Firework { + strength: i32, +} + +impl Drop for Firework { + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(),u8> { + let _firecracker = Firework { strength: 1 }; + + let _tnt = Firework { strength: 100 }; + + if true { + println!("Exiting with error..."); + return Err(1); + } + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/src/test/run-make-fulldeps/instrument-coverage/generics.rs b/src/test/run-make-fulldeps/instrument-coverage/generics.rs new file mode 100644 index 00000000000..f4e64026944 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/generics.rs @@ -0,0 +1,44 @@ +#![allow(unused_assignments)] +// expect-exit-status-1 + +struct Firework where T: Copy + std::fmt::Display { + strength: T, +} + +impl Firework where T: Copy + std::fmt::Display { + #[inline(always)] + fn set_strength(&mut self, new_strength: T) { + self.strength = new_strength; + } +} + +impl Drop for Firework where T: Copy + std::fmt::Display { + #[inline(always)] + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(),u8> { + let mut firecracker = Firework { strength: 1 }; + firecracker.set_strength(2); + + let mut tnt = Firework { strength: 100.1 }; + tnt.set_strength(200.1); + tnt.set_strength(300.3); + + if true { + println!("Exiting with error..."); + return Err(1); + } + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/src/test/run-make-fulldeps/instrument-coverage/if.rs b/src/test/run-make-fulldeps/instrument-coverage/if.rs new file mode 100644 index 00000000000..8ad5042ff7b --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/if.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let + is_true + = + std::env::args().len() + == + 1 + ; + let + mut + countdown + = + 0 + ; + if + is_true + { + countdown + = + 10 + ; + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/if_else.rs b/src/test/run-make-fulldeps/instrument-coverage/if_else.rs new file mode 100644 index 00000000000..3ae4b7a7316 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/if_else.rs @@ -0,0 +1,40 @@ +#![allow(unused_assignments)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if + is_true + { + countdown + = + 10 + ; + } + else // Note coverage region difference without semicolon + { + countdown + = + 100 + } + + if + is_true + { + countdown + = + 10 + ; + } + else + { + countdown + = + 100 + ; + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/inner_items.rs b/src/test/run-make-fulldeps/instrument-coverage/inner_items.rs new file mode 100644 index 00000000000..1e2fe5a9353 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/inner_items.rs @@ -0,0 +1,57 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } + + mod inner_mod { + const INNER_MOD_CONST: u32 = 1000; + } + + fn inner_function(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + } + + struct InnerStruct { + inner_struct_field: u32, + } + + const INNER_CONST: u32 = 1234; + + trait InnerTrait { + fn inner_trait_func(&mut self, incr: u32); + + fn default_trait_func(&mut self) { + inner_function(INNER_CONST); + self.inner_trait_func(INNER_CONST); + } + } + + impl InnerTrait for InnerStruct { + fn inner_trait_func(&mut self, incr: u32) { + self.inner_struct_field += incr; + inner_function(self.inner_struct_field); + } + } + + type InnerType = String; + + if is_true { + inner_function(countdown); + } + + let mut val = InnerStruct { + inner_struct_field: 101, + }; + + val.default_trait_func(); +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/lazy_boolean.rs b/src/test/run-make-fulldeps/instrument-coverage/lazy_boolean.rs new file mode 100644 index 00000000000..1d83eb30dea --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/lazy_boolean.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0); + if is_true { + a = 1; + b = 10; + c = 100; + } + let + somebool + = + a < b + || + b < c + ; + let + somebool + = + b < a + || + b < c + ; + let + somebool + = + a < b + && + b < c + ; + let + somebool + = + b < a + && + b < c + ; +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/loop_break_value.rs b/src/test/run-make-fulldeps/instrument-coverage/loop_break_value.rs new file mode 100644 index 00000000000..ba66d136de1 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/loop_break_value.rs @@ -0,0 +1,13 @@ +#![allow(unused_assignments)] + +fn main() { + let result + = + loop + { + break + 10 + ; + } + ; +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/question_mark_error_result.rs b/src/test/run-make-fulldeps/instrument-coverage/question_mark_error_result.rs new file mode 100644 index 00000000000..3a8f30e0482 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/question_mark_error_result.rs @@ -0,0 +1,35 @@ +#![allow(unused_assignments)] +// expect-exit-status-1 + +fn call(return_error: bool) -> Result<(),()> { + if return_error { + Err(()) + } else { + Ok(()) + } +} + +fn main() -> Result<(),()> { + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + call(/*return_error=*/ true)?; + } + else + { + call(/*return_error=*/ false)?; + } + } + Ok(()) +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/simple_loop.rs b/src/test/run-make-fulldeps/instrument-coverage/simple_loop.rs new file mode 100644 index 00000000000..6f7f23475b8 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/simple_loop.rs @@ -0,0 +1,35 @@ +#![allow(unused_assignments)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + + if + is_true + { + countdown + = + 10 + ; + } + + loop + { + if + countdown + == + 0 + { + break + ; + } + countdown + -= + 1 + ; + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/simple_match.rs b/src/test/run-make-fulldeps/instrument-coverage/simple_match.rs new file mode 100644 index 00000000000..c9a24f7a9d3 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/simple_match.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 1; + if is_true { + countdown = 0; + } + + for + _ + in + 0..2 + { + let z + ; + match + countdown + { + x + if + x + < + 1 + => + { + z = countdown + ; + let y = countdown + ; + countdown = 10 + ; + } + _ + => + {} + } + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/various_conditions.rs b/src/test/run-make-fulldeps/instrument-coverage/various_conditions.rs new file mode 100644 index 00000000000..da206e28f31 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/various_conditions.rs @@ -0,0 +1,67 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let mut countdown = 0; + if true { + countdown = 10; + } + + const B: u32 = 100; + let x = if countdown > 7 { + countdown -= 4; + B + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + countdown + } else { + return; + }; + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + let mut countdown = 0; + if true { + countdown = 1; + } + + let z = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + let should_be_reachable = countdown; + println!("reached"); + return; + }; + + let w = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + }; +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/while_early_return.rs b/src/test/run-make-fulldeps/instrument-coverage/while_early_return.rs new file mode 100644 index 00000000000..14ba36238d6 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/while_early_return.rs @@ -0,0 +1,47 @@ +#![allow(unused_assignments)] +// expect-exit-status-1 + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while + countdown + > + 0 + { + if + countdown + < + 5 + { + return + if + countdown + > + 8 + { + Ok(()) + } + else + { + Err(1) + } + ; + } + countdown + -= + 1 + ; + } + Ok(()) +} + +// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and +// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux +// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program +// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical +// to the coverage test for early returns, but this is a limitation that should be fixed. +// +// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, +// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping +// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the +// problem exists on MSVC only). diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index acad316d807..d85558ea2f5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3199,8 +3199,18 @@ impl<'test> TestCx<'test> { from_file = format!("{}.{}.mir", test_name, first_pass); to_file = Some(second_file); } else { - expected_file = - format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); + let ext_re = Regex::new(r#"(\.(mir|dot|html))$"#).unwrap(); + let cap = ext_re + .captures_iter(test_name) + .next() + .expect("test_name has an invalid extension"); + let extension = cap.get(1).unwrap().as_str(); + expected_file = format!( + "{}{}{}", + test_name.trim_end_matches(extension), + bit_width, + extension, + ); from_file = test_name.to_string(); assert!( test_names.next().is_none(), diff --git a/src/tools/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml index 0b8d974d255..c978bbe20e8 100644 --- a/src/tools/rust-demangler/Cargo.toml +++ b/src/tools/rust-demangler/Cargo.toml @@ -1,10 +1,11 @@ [package] authors = ["The Rust Project Developers"] name = "rust-demangler" -version = "0.0.0" +version = "0.0.1" edition = "2018" [dependencies] +regex = "1.0" rustc-demangle = "0.1" [[bin]] diff --git a/src/tools/rust-demangler/main.rs b/src/tools/rust-demangler/main.rs index a9f1011c450..e1e49230ad1 100644 --- a/src/tools/rust-demangler/main.rs +++ b/src/tools/rust-demangler/main.rs @@ -22,18 +22,51 @@ //! --instr-profile=main.profdata ./main --show-line-counts-or-regions //! ``` +use regex::Regex; use rustc_demangle::demangle; use std::io::{self, Read, Write}; +const REPLACE_COLONS: &str = "::"; + fn main() -> io::Result<()> { + let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{16}\]::").unwrap()); + + let mut args = std::env::args(); + let progname = args.next().unwrap(); + for arg in args { + if arg == "--disambiguators" || arg == "-d" { + strip_crate_disambiguators = None; + } else { + eprintln!(); + eprintln!("Usage: {} [-d|--disambiguators]", progname); + eprintln!(); + eprintln!( + "This tool converts a list of Rust mangled symbols (one per line) into a\n + corresponding list of demangled symbols." + ); + eprintln!(); + eprintln!( + "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\ + include crate disambiguators (a 16 character hex value in square brackets).\n\ + Crate disambiguators are removed by default." + ); + eprintln!(); + std::process::exit(1) + } + } + let mut buffer = String::new(); io::stdin().read_to_string(&mut buffer)?; let lines = buffer.lines(); - let mut demangled = Vec::new(); + let mut demangled_lines = Vec::new(); for mangled in lines { - demangled.push(demangle(mangled).to_string()); + let mut demangled = demangle(mangled).to_string(); + if let Some(re) = &strip_crate_disambiguators { + demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string(); + } + demangled_lines.push(demangled); } - demangled.push("".to_string()); - io::stdout().write_all(demangled.join("\n").as_bytes())?; + demangled_lines.push("".to_string()); + io::stdout().write_all(demangled_lines.join("\n").as_bytes())?; Ok(()) } -- cgit 1.4.1-3-g733a5