From 4990021082b329d628134e42d65680f4e7195b3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 09:18:33 -0400 Subject: [PATCH 1/7] test const_copy to make sure bytewise pointer copies are working --- library/core/tests/lib.rs | 1 + library/core/tests/ptr.rs | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7e9d7d2710180..9505ec31609f5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -84,6 +84,7 @@ #![feature(const_option)] #![feature(const_option_ext)] #![feature(const_result)] +#![feature(const_intrinsic_copy)] #![feature(integer_atomics)] #![feature(int_roundings)] #![feature(slice_group_by)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index c5242ad04de84..40b2b49bdbd7d 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1,4 +1,5 @@ use core::cell::RefCell; +use core::mem::{self, MaybeUninit}; use core::num::NonZeroUsize; use core::ptr; use core::ptr::*; @@ -781,3 +782,42 @@ fn nonnull_tagged_pointer_with_provenance() { } } } + +#[test] +fn test_const_copy() { + const { + let ptr1 = &1; + let mut ptr2 = &666; + + // Copy ptr1 to ptr2, bytewise. + unsafe { + ptr::copy( + &ptr1 as *const _ as *const MaybeUninit, + &mut ptr2 as *mut _ as *mut MaybeUninit, + mem::size_of::<&i32>(), + ); + } + + // Make sure they still work. + assert!(*ptr1 == 1); + assert!(*ptr2 == 1); + }; + + const { + let ptr1 = &1; + let mut ptr2 = &666; + + // Copy ptr1 to ptr2, bytewise. + unsafe { + ptr::copy_nonoverlapping( + &ptr1 as *const _ as *const MaybeUninit, + &mut ptr2 as *mut _ as *mut MaybeUninit, + mem::size_of::<&i32>(), + ); + } + + // Make sure they still work. + assert!(*ptr1 == 1); + assert!(*ptr2 == 1); + }; +} From 7026845706009dfeca4511a1842e6ac18b1dfcd7 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 4 Jun 2022 21:17:34 +0900 Subject: [PATCH 2/7] Add regresion test for #87142 --- src/test/ui/generator/issue-87142.rs | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/ui/generator/issue-87142.rs diff --git a/src/test/ui/generator/issue-87142.rs b/src/test/ui/generator/issue-87142.rs new file mode 100644 index 0000000000000..fc10d04d46cfb --- /dev/null +++ b/src/test/ui/generator/issue-87142.rs @@ -0,0 +1,32 @@ +// compile-flags: -Cdebuginfo=2 +// build-pass + +// Regression test for #87142 +// This test needs the above flags and the "lib" crate type. + +#![feature(type_alias_impl_trait, generator_trait, generators)] +#![crate_type = "lib"] + +use std::ops::Generator; + +pub trait GeneratorProviderAlt: Sized { + type Gen: Generator<(), Return = (), Yield = ()>; + + fn start(ctx: Context) -> Self::Gen; +} + +pub struct Context { + pub link: Box, +} + +impl GeneratorProviderAlt for () { + type Gen = impl Generator<(), Return = (), Yield = ()>; + fn start(ctx: Context) -> Self::Gen { + move || { + match ctx { + _ => (), + } + yield (); + } + } +} From fc8b13cb96a5b45bb7028ca0f50d1444f0f95582 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:01:56 +0200 Subject: [PATCH 3/7] Adapt rustc_data_structures tests to run in strict miri Some tests took too long and owning_ref is fundamentally flawed, so don't run these tests or run them with a shorter N. This makes miri with `-Zmiri-strict-provenance` usable to find UB. --- compiler/rustc_data_structures/src/base_n/tests.rs | 4 +++- compiler/rustc_data_structures/src/graph/scc/tests.rs | 3 +++ compiler/rustc_data_structures/src/owning_ref/tests.rs | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs index b68ef1eb7f4c4..2be2f0532c99c 100644 --- a/compiler/rustc_data_structures/src/base_n/tests.rs +++ b/compiler/rustc_data_structures/src/base_n/tests.rs @@ -15,7 +15,9 @@ fn test_encode() { test(u64::MAX as u128, base); test(u128::MAX, base); - for i in 0..1_000 { + const N: u128 = if cfg!(miri) { 10 } else { 1000 }; + + for i in 0..N { test(i * 983, base); } } diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 364005e67e63f..9940fee60d7d8 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -156,7 +156,10 @@ fn test_deep_linear() { v … */ + #[cfg(not(miri))] const NR_NODES: usize = 1 << 14; + #[cfg(miri)] + const NR_NODES: usize = 1 << 3; let mut nodes = vec![]; for i in 1..NR_NODES { nodes.push((i - 1, i)); diff --git a/compiler/rustc_data_structures/src/owning_ref/tests.rs b/compiler/rustc_data_structures/src/owning_ref/tests.rs index 7b8179e90bd07..320c03d5139f4 100644 --- a/compiler/rustc_data_structures/src/owning_ref/tests.rs +++ b/compiler/rustc_data_structures/src/owning_ref/tests.rs @@ -1,3 +1,5 @@ +// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it. +#[cfg(not(miri))] mod owning_ref { use super::super::OwningRef; use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef}; @@ -361,6 +363,8 @@ mod owning_handle { } } +// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it. +#[cfg(not(miri))] mod owning_ref_mut { use super::super::BoxRef; use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut}; From 7e3bee6d8ecf2bd1270b99ea1425f594d6adaf54 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:03:21 +0200 Subject: [PATCH 4/7] Fix stacked borrows invalidation in rustc_data_structures sip128 It creates the src pointer first, which is then invalidated by a unique borrow of the destination pointer. Swap the borrows around to fix this. Found with miri. --- compiler/rustc_data_structures/src/sip128.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index abd25f46ad54f..90793a97ed0d8 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -255,8 +255,9 @@ impl SipHasher128 { // elements from spill (at most LEN - 1 bytes could have overflowed // into the spill). The memcpy call is optimized away because the size // is known. And the whole copy is optimized away for LEN == 1. + let dst = self.buf.as_mut_ptr() as *mut u8; let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1); + ptr::copy_nonoverlapping(src, dst, LEN - 1); // This function should only be called when the write fills the buffer. // Therefore, when LEN == 1, the new `self.nbuf` must be zero. From 784eebcc604a10c697f6dce2f82155268333c57c Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sat, 4 Jun 2022 11:03:45 -0700 Subject: [PATCH 5/7] Don't generate "Impls on Foreign Types" for std Hack: many traits and types in std are re-exported from core or alloc. In general, rustdoc is capable of recognizing these implementations as being on local types. However, in at least one case, rustdoc gets confused and labels an implementation as being on a foreign type. To make sure that confusion doesn't pass on to the reader, consider all implementations in std, core, and alloc to be on local types. --- src/librustdoc/formats/mod.rs | 17 +++++++++++++++-- src/librustdoc/html/render/mod.rs | 5 ++--- src/librustdoc/html/render/print_item.rs | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 9f26ccc74d182..b236bd7be4f0c 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; pub(crate) use renderer::{run_format, FormatRenderer}; use crate::clean::{self, ItemId}; -use cache::Cache; +use crate::html::render::Context; /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. @@ -65,7 +65,8 @@ impl Impl { // Returns true if this is an implementation on a "local" type, meaning: // the type is in the current crate, or the type and the trait are both // re-exported by the current crate. - pub(crate) fn is_on_local_type(&self, cache: &Cache) -> bool { + pub(crate) fn is_on_local_type(&self, cx: &Context<'_>) -> bool { + let cache = cx.cache(); let for_type = &self.inner_impl().for_; if let Some(for_type_did) = for_type.def_id(cache) { // The "for" type is local if it's in the paths for the current crate. @@ -80,6 +81,18 @@ impl Impl { if for_type_did.krate == trait_did.krate { return true; } + // Hack: many traits and types in std are re-exported from + // core or alloc. In general, rustdoc is capable of recognizing + // these implementations as being on local types. However, in at + // least one case (https://github.com/rust-lang/rust/issues/97610), + // rustdoc gets confused and labels an implementation as being on + // a foreign type. To make sure that confusion doesn't pass on to + // the reader, consider all implementations in std, core, and alloc + // to be on local types. + let crate_name = cx.tcx().crate_name(trait_did.krate); + if matches!(crate_name.as_str(), "std" | "core" | "alloc") { + return true; + } } return false; }; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 0b801a20995d3..23ce634cf286b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2281,11 +2281,10 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean |sym| format!("{0}", sym, ItemType::Method), ); - let cache = cx.cache(); - if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) { + if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) { let mut res = implementors .iter() - .filter(|i| !i.is_on_local_type(cache)) + .filter(|i| !i.is_on_local_type(cx)) .filter_map(|i| extract_for_impl_name(&i.impl_item, cx)) .collect::>(); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 8683e6dfcd99e..d115185562ce4 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -823,7 +823,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } let (local, foreign) = - implementors.iter().partition::, _>(|i| i.is_on_local_type(cache)); + implementors.iter().partition::, _>(|i| i.is_on_local_type(cx)); let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter().partition(|i| i.inner_impl().kind.is_auto()); From 76c6845a8592931edd1e80dbccfd8cbd047e4f2b Mon Sep 17 00:00:00 2001 From: Elliot Roberts Date: Tue, 31 May 2022 16:59:28 -0700 Subject: [PATCH 6/7] Iterate over `maybe_unused_trait_imports` when checking dead trait imports --- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/query.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 4 +- compiler/rustc_typeck/src/check_unused.rs | 56 ++++++++--------------- 6 files changed, 29 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 38d8e0b581953..31b27abd0c8a2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1728,8 +1728,8 @@ rustc_queries! { query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } } - query maybe_unused_trait_import(def_id: LocalDefId) -> bool { - desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) } + query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet { + desc { "fetching potentially unused trait imports" } } query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] { desc { "looking up all possibly unused extern crates" } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a0d92e2a5dd94..4cdeae2f4492c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2886,8 +2886,8 @@ pub fn provide(providers: &mut ty::query::Providers) { assert_eq!(id, LOCAL_CRATE); tcx.crate_name }; - providers.maybe_unused_trait_import = - |tcx, id| tcx.resolutions(()).maybe_unused_trait_imports.contains(&id); + providers.maybe_unused_trait_imports = + |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.maybe_unused_extern_crates = |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..]; providers.names_imported_by_glob_use = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a493aaac276b1..3a2d3408b9d93 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,7 +28,7 @@ pub use generics::*; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; @@ -138,7 +138,7 @@ pub struct ResolverOutputs { pub has_pub_restricted: bool, pub access_levels: AccessLevels, pub extern_crate_map: FxHashMap, - pub maybe_unused_trait_imports: FxHashSet, + pub maybe_unused_trait_imports: FxIndexSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub reexport_map: FxHashMap>, pub glob_map: FxHashMap>, diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 65f41c5266d17..59794c4d3f0d8 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -37,7 +37,7 @@ use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, T use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 73c8a9d28bd5f..49c15d2c9ef1f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -28,7 +28,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -941,7 +941,7 @@ pub struct Resolver<'a> { visibilities: FxHashMap, has_pub_restricted: bool, used_imports: FxHashSet, - maybe_unused_trait_imports: FxHashSet, + maybe_unused_trait_imports: FxIndexSet, maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// Privacy errors are delayed until the end in order to deduplicate them. diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index 00f0d1e6f02a9..f28184c74d355 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -16,48 +16,32 @@ pub fn check_crate(tcx: TyCtxt<'_>) { used_trait_imports.extend(imports.iter()); } - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Use) { - if tcx.visibility(id.def_id).is_public() { - continue; - } - let item = tcx.hir().item(id); - if item.span.is_dummy() { - continue; - } - if let hir::ItemKind::Use(path, _) = item.kind { - check_import(tcx, &mut used_trait_imports, item.item_id(), path.span); - } + for &id in tcx.maybe_unused_trait_imports(()) { + debug_assert_eq!(tcx.def_kind(id), DefKind::Use); + if tcx.visibility(id).is_public() { + continue; + } + if used_trait_imports.contains(&id) { + continue; } + let item = tcx.hir().expect_item(id); + if item.span.is_dummy() { + continue; + } + let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { + let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { + format!("unused import: `{}`", snippet) + } else { + "unused import".to_owned() + }; + lint.build(&msg).emit(); + }); } unused_crates_lint(tcx); } -fn check_import<'tcx>( - tcx: TyCtxt<'tcx>, - used_trait_imports: &mut FxHashSet, - item_id: hir::ItemId, - span: Span, -) { - if !tcx.maybe_unused_trait_import(item_id.def_id) { - return; - } - - if used_trait_imports.contains(&item_id.def_id) { - return; - } - - tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| { - let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { - format!("unused import: `{}`", snippet) - } else { - "unused import".to_owned() - }; - lint.build(&msg).emit(); - }); -} - fn unused_crates_lint(tcx: TyCtxt<'_>) { let lint = lint::builtin::UNUSED_EXTERN_CRATES; From dd38fecb78dcccf2c8b506cf901bdce1ba1a6df8 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sat, 4 Jun 2022 14:31:17 -0400 Subject: [PATCH 7/7] Fix pretty printing named bound regions under -Zverbose --- compiler/rustc_middle/src/ty/print/pretty.rs | 54 +++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 64c63e3d567d0..08879afa64a0e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2190,34 +2190,40 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // this is not *quite* right and changes the ordering of some output // anyways. let (new_value, map) = if self.tcx().sess.verbose() { - // anon index + 1 (BrEnv takes 0) -> name - let mut region_map: FxHashMap<_, _> = Default::default(); - let bound_vars = value.bound_vars(); - for var in bound_vars { - let ty::BoundVariableKind::Region(var) = var else { continue }; - match var { - ty::BrAnon(_) | ty::BrEnv => { - start_or_continue(&mut self, "for<", ", "); - let name = next_name(&self); - do_continue(&mut self, name); - region_map.insert(var, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)); - } - ty::BrNamed(def_id, kw::UnderscoreLifetime) => { - start_or_continue(&mut self, "for<", ", "); - let name = next_name(&self); - do_continue(&mut self, name); - region_map.insert(var, ty::BrNamed(def_id, name)); - } - ty::BrNamed(_, name) => { - start_or_continue(&mut self, "for<", ", "); - do_continue(&mut self, name); + let regions: Vec<_> = value + .bound_vars() + .into_iter() + .map(|var| { + let ty::BoundVariableKind::Region(var) = var else { + // This doesn't really matter because it doesn't get used, + // it's just an empty value + return ty::BrAnon(0); + }; + match var { + ty::BrAnon(_) | ty::BrEnv => { + start_or_continue(&mut self, "for<", ", "); + let name = next_name(&self); + do_continue(&mut self, name); + ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) + } + ty::BrNamed(def_id, kw::UnderscoreLifetime) => { + start_or_continue(&mut self, "for<", ", "); + let name = next_name(&self); + do_continue(&mut self, name); + ty::BrNamed(def_id, name) + } + ty::BrNamed(def_id, name) => { + start_or_continue(&mut self, "for<", ", "); + do_continue(&mut self, name); + ty::BrNamed(def_id, name) + } } - } - } + }) + .collect(); start_or_continue(&mut self, "", "> "); self.tcx.replace_late_bound_regions(value.clone(), |br| { - let kind = region_map[&br.kind]; + let kind = regions[br.var.as_usize()]; self.tcx.mk_region(ty::ReLateBound( ty::INNERMOST, ty::BoundRegion { var: br.var, kind },