diff options
107 files changed, 2154 insertions, 882 deletions
diff --git a/Cargo.lock b/Cargo.lock index 970b1719aa1..150a70341f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,6 +581,7 @@ dependencies = [ "libc", "num-integer", "num-traits", + "serde", "time", "winapi", ] @@ -731,6 +732,16 @@ dependencies = [ ] [[package]] +name = "collect-license-metadata" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "spdx-rs", +] + +[[package]] name = "color-eyre" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1553,6 +1564,15 @@ dependencies = [ ] [[package]] +name = "generate-copyright" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", +] + +[[package]] name = "generic-array" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4865,6 +4885,35 @@ dependencies = [ ] [[package]] +name = "spdx-expression" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77" +dependencies = [ + "nom", + "serde", + "thiserror", + "tracing", +] + +[[package]] +name = "spdx-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3c02f6eb7e7b4100c272f685a9ccaccaab302324e8c7ec3e2ee72340fb29ff3" +dependencies = [ + "chrono", + "log", + "nom", + "serde", + "spdx-expression", + "strum", + "strum_macros", + "thiserror", + "uuid", +] + +[[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4968,6 +5017,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] name = "syn" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5597,6 +5665,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.0", +] + +[[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 13a98eedde8..000c10a1f90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,8 @@ members = [ "src/tools/bump-stage0", "src/tools/replace-version-placeholder", "src/tools/lld-wrapper", + "src/tools/collect-license-metadata", + "src/tools/generate-copyright", ] exclude = [ diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 85693259cd0..e14c9ea9a5d 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -9,6 +9,8 @@ use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub}; use std::str::FromStr; use bitflags::bitflags; +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::StableOrd; use rustc_index::vec::{Idx, IndexVec}; #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; @@ -403,6 +405,11 @@ pub struct Size { raw: u64, } +// Safety: Ord is implement as just comparing numerical values and numerical values +// are not changed by (de-)serialization. +#[cfg(feature = "nightly")] +unsafe impl StableOrd for Size {} + // This is debug-printed a lot in larger structs, don't waste too much space there impl fmt::Debug for Size { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 695ccec0b1c..9974ebff311 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -16,7 +16,7 @@ use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::DUMMY_SP; use thin_vec::thin_vec; @@ -594,14 +594,38 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); - // Resume argument type: `ResumeTy` - let unstable_span = - self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None); + // Resume argument type, which should be `&mut Context<'_>`. + // NOTE: Using the `'static` lifetime here is technically cheating. + // The `Future::poll` argument really is `&'a mut Context<'b>`, but we cannot + // express the fact that we are not storing it across yield-points yet, + // and we would thus run into lifetime errors. + // See <https://github.com/rust-lang/rust/issues/68923>. + // Our lowering makes sure we are not mis-using the `_task_context` input type + // in the sense that we are indeed not using it across yield points. We + // get a fresh `&mut Context` for each resume / call of `Future::poll`. + // This "cheating" was previously done with a `ResumeTy` that contained a raw + // pointer, and a `get_context` accessor that pulled the `Context` lifetimes + // out of thin air. + let context_lifetime_ident = Ident::with_dummy_span(kw::StaticLifetime); + let context_lifetime = self.arena.alloc(hir::Lifetime { + hir_id: self.next_id(), + ident: context_lifetime_ident, + res: hir::LifetimeName::Static, + }); + let context_path = + hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span), None); + let context_ty = hir::MutTy { + ty: self.arena.alloc(hir::Ty { + hir_id: self.next_id(), + kind: hir::TyKind::Path(context_path), + span: self.lower_span(span), + }), + mutbl: hir::Mutability::Mut, + }; let input_ty = hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::Path(resume_ty), - span: unstable_span, + kind: hir::TyKind::Rptr(context_lifetime, context_ty), + span: self.lower_span(span), }; // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`. @@ -659,12 +683,9 @@ impl<'hir> LoweringContext<'_, 'hir> { .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); let hir_id = self.lower_node_id(closure_node_id); + let unstable_span = + self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); if track_caller { - let unstable_span = self.mark_span_with_reason( - DesugaringKind::Async, - span, - self.allow_gen_future.clone(), - ); self.lower_attrs( hir_id, &[Attribute { @@ -711,7 +732,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// mut __awaitee => loop { /// match unsafe { ::std::future::Future::poll( /// <::std::pin::Pin>::new_unchecked(&mut __awaitee), - /// ::std::future::get_context(task_context), + /// task_context, /// ) } { /// ::std::task::Poll::Ready(result) => break result, /// ::std::task::Poll::Pending => {} @@ -752,7 +773,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // unsafe { // ::std::future::Future::poll( // ::std::pin::Pin::new_unchecked(&mut __awaitee), - // ::std::future::get_context(task_context), + // task_context, // ) // } let poll_expr = { @@ -770,16 +791,10 @@ impl<'hir> LoweringContext<'_, 'hir> { arena_vec![self; ref_mut_awaitee], Some(expr_hir_id), ); - let get_context = self.expr_call_lang_item_fn_mut( - gen_future_span, - hir::LangItem::GetContext, - arena_vec![self; task_context], - Some(expr_hir_id), - ); let call = self.expr_call_lang_item_fn( span, hir::LangItem::FuturePoll, - arena_vec![self; new_unchecked, get_context], + arena_vec![self; new_unchecked, task_context], Some(expr_hir_id), ); self.arena.alloc(self.expr_unsafe(call)) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 1aad6738bba..3617bf58be9 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -121,9 +121,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn prove_predicates( &mut self, - predicates: impl IntoIterator< - Item = impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug, - >, + predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, ) { @@ -135,7 +133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn prove_predicate( &mut self, - predicate: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug, + predicate: impl ToPredicate<'tcx> + std::fmt::Debug, locations: Locations, category: ConstraintCategory<'tcx>, ) { diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index a39178016ce..d98f4e43fe8 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -140,7 +140,7 @@ impl stable_hasher::StableHasherResult for Fingerprint { } } -impl_stable_hash_via_hash!(Fingerprint); +impl_stable_traits_for_trivial_type!(Fingerprint); impl<E: Encoder> Encodable<E> for Fingerprint { #[inline] diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 76a1288e6d3..ba94f3776eb 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -4,8 +4,6 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::ptr; -use crate::fingerprint::Fingerprint; - mod private { #[derive(Clone, Copy, Debug)] pub struct PrivateZst; @@ -110,86 +108,5 @@ where } } -/// A helper type that you can wrap round your own type in order to automatically -/// cache the stable hash on creation and not recompute it whenever the stable hash -/// of the type is computed. -/// This is only done in incremental mode. You can also opt out of caching by using -/// StableHash::ZERO for the hash, in which case the hash gets computed each time. -/// This is useful if you have values that you intern but never (can?) use for stable -/// hashing. -#[derive(Copy, Clone)] -pub struct WithStableHash<T> { - pub internee: T, - pub stable_hash: Fingerprint, -} - -impl<T: PartialEq> PartialEq for WithStableHash<T> { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.internee.eq(&other.internee) - } -} - -impl<T: Eq> Eq for WithStableHash<T> {} - -impl<T: Ord> PartialOrd for WithStableHash<T> { - fn partial_cmp(&self, other: &WithStableHash<T>) -> Option<Ordering> { - Some(self.internee.cmp(&other.internee)) - } -} - -impl<T: Ord> Ord for WithStableHash<T> { - fn cmp(&self, other: &WithStableHash<T>) -> Ordering { - self.internee.cmp(&other.internee) - } -} - -impl<T> Deref for WithStableHash<T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.internee - } -} - -impl<T: Hash> Hash for WithStableHash<T> { - #[inline] - fn hash<H: Hasher>(&self, s: &mut H) { - if self.stable_hash != Fingerprint::ZERO { - self.stable_hash.hash(s) - } else { - self.internee.hash(s) - } - } -} - -impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithStableHash<T> { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) { - // No cached hash available. This can only mean that incremental is disabled. - // We don't cache stable hashes in non-incremental mode, because they are used - // so rarely that the performance actually suffers. - - // We need to build the hash as if we cached it and then hash that hash, as - // otherwise the hashes will differ between cached and non-cached mode. - let stable_hash: Fingerprint = { - let mut hasher = StableHasher::new(); - self.internee.hash_stable(hcx, &mut hasher); - hasher.finish() - }; - if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO { - assert_eq!( - stable_hash, self.stable_hash, - "cached stable hash does not match freshly computed stable hash" - ); - } - stable_hash.hash_stable(hcx, hasher); - } else { - self.stable_hash.hash_stable(hcx, hasher); - } - } -} - #[cfg(test)] mod tests; diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index d607a5c8314..d13313dfd0e 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,4 +1,4 @@ -use crate::stable_hasher::{HashStable, StableHasher}; +use crate::stable_hasher::{HashStable, StableHasher, StableOrd}; use std::borrow::Borrow; use std::cmp::Ordering; use std::iter::FromIterator; @@ -308,7 +308,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for SortedMap<K, V> { } } -impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> { +impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.data.hash_stable(ctx, hasher); diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 0ec32dc4307..c2f0ae32896 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -120,13 +120,20 @@ where self.items.hash(hasher) } } + impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V> where K: HashStable<C>, V: HashStable<C>, { fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) { - self.items.hash_stable(ctx, hasher) + let SortedIndexMultiMap { + items, + // We can ignore this field because it is not observable from the outside. + idx_sorted_by_item_key: _, + } = self; + + items.hash_stable(ctx, hasher) } } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index cd392a7b678..1a728f82f00 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -219,7 +219,35 @@ pub trait ToStableHashKey<HCX> { fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType; } -/// Implement HashStable by just calling `Hash::hash()`. +/// Trait for marking a type as having a sort order that is +/// stable across compilation session boundaries. More formally: +/// +/// ```txt +/// Ord::cmp(a1, b1) == Ord:cmp(a2, b2) +/// where a2 = decode(encode(a1, context1), context2) +/// b2 = decode(encode(b1, context1), context2) +/// ``` +/// +/// i.e. the result of `Ord::cmp` is not influenced by encoding +/// the values in one session and then decoding them in another +/// session. +/// +/// This is trivially true for types where encoding and decoding +/// don't change the bytes of the values that are used during +/// comparison and comparison only depends on these bytes (as +/// opposed to some non-local state). Examples are u32, String, +/// Path, etc. +/// +/// But it is not true for: +/// - `*const T` and `*mut T` because the values of these pointers +/// will change between sessions. +/// - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete +/// values depend on state that might be different between +/// compilation sessions. +pub unsafe trait StableOrd: Ord {} + +/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since +/// that has the same requirements. /// /// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting. /// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013) @@ -227,7 +255,7 @@ pub trait ToStableHashKey<HCX> { /// here in this module. /// /// Use `#[derive(HashStable_Generic)]` instead. -macro_rules! impl_stable_hash_via_hash { +macro_rules! impl_stable_traits_for_trivial_type { ($t:ty) => { impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t { #[inline] @@ -235,26 +263,28 @@ macro_rules! impl_stable_hash_via_hash { ::std::hash::Hash::hash(self, hasher); } } + + unsafe impl $crate::stable_hasher::StableOrd for $t {} }; } -impl_stable_hash_via_hash!(i8); -impl_stable_hash_via_hash!(i16); -impl_stable_hash_via_hash!(i32); -impl_stable_hash_via_hash!(i64); -impl_stable_hash_via_hash!(isize); +impl_stable_traits_for_trivial_type!(i8); +impl_stable_traits_for_trivial_type!(i16); +impl_stable_traits_for_trivial_type!(i32); +impl_stable_traits_for_trivial_type!(i64); +impl_stable_traits_for_trivial_type!(isize); -impl_stable_hash_via_hash!(u8); -impl_stable_hash_via_hash!(u16); -impl_stable_hash_via_hash!(u32); -impl_stable_hash_via_hash!(u64); -impl_stable_hash_via_hash!(usize); +impl_stable_traits_for_trivial_type!(u8); +impl_stable_traits_for_trivial_type!(u16); +impl_stable_traits_for_trivial_type!(u32); +impl_stable_traits_for_trivial_type!(u64); +impl_stable_traits_for_trivial_type!(usize); -impl_stable_hash_via_hash!(u128); -impl_stable_hash_via_hash!(i128); +impl_stable_traits_for_trivial_type!(u128); +impl_stable_traits_for_trivial_type!(i128); -impl_stable_hash_via_hash!(char); -impl_stable_hash_via_hash!(()); +impl_stable_traits_for_trivial_type!(char); +impl_stable_traits_for_trivial_type!(()); impl<CTX> HashStable<CTX> for ! { fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { @@ -444,6 +474,10 @@ impl<CTX> HashStable<CTX> for String { } } +// Safety: String comparison only depends on their contents and the +// contents are not changed by (de-)serialization. +unsafe impl StableOrd for String {} + impl<HCX> ToStableHashKey<HCX> for String { type KeyType = String; #[inline] @@ -459,6 +493,9 @@ impl<CTX> HashStable<CTX> for bool { } } +// Safety: sort order of bools is not changed by (de-)serialization. +unsafe impl StableOrd for bool {} + impl<T, CTX> HashStable<CTX> for Option<T> where T: HashStable<CTX>, @@ -474,6 +511,9 @@ where } } +// Safety: the Option wrapper does not add instability to comparison. +unsafe impl<T: StableOrd> StableOrd for Option<T> {} + impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2> where T1: HashStable<CTX>, @@ -550,8 +590,8 @@ where } } -impl_stable_hash_via_hash!(::std::path::Path); -impl_stable_hash_via_hash!(::std::path::PathBuf); +impl_stable_traits_for_trivial_type!(::std::path::Path); +impl_stable_traits_for_trivial_type!(::std::path::PathBuf); impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R> where @@ -584,27 +624,26 @@ where impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V> where - K: ToStableHashKey<HCX>, + K: HashStable<HCX> + StableOrd, V: HashStable<HCX>, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| { - let key = key.to_stable_hash_key(hcx); - key.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - }); + self.len().hash_stable(hcx, hasher); + for entry in self.iter() { + entry.hash_stable(hcx, hasher); + } } } impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K> where - K: ToStableHashKey<HCX>, + K: HashStable<HCX> + StableOrd, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| { - let key = key.to_stable_hash_key(hcx); - key.hash_stable(hcx, hasher); - }); + self.len().hash_stable(hcx, hasher); + for entry in self.iter() { + entry.hash_stable(hcx, hasher); + } } } diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl index 0894bbcaad4..a5cb8a88819 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -17,6 +17,8 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait .generics_label = lifetimes in impl do not match this {$item_kind} in trait + .where_label = this `where` clause might not match the one in the trait + .bounds_label = this bound might be missing in the impl hir_analysis_drop_impl_on_wrong_item = the `Drop` trait may only be implemented for local structs, enums, and unions diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 93613ef27d4..060f40919f5 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -1,5 +1,5 @@ use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; use rustc_span::{def_id::DefPathHash, HashStableContext}; use std::fmt; @@ -146,6 +146,10 @@ impl ItemLocalId { pub const INVALID: ItemLocalId = ItemLocalId::MAX; } +// Safety: Ord is implement as just comparing the LocalItemId's numerical +// values and these are not changed by (de-)serialization. +unsafe impl StableOrd for ItemLocalId {} + /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`. pub const CRATE_HIR_ID: HirId = HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) }; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 038509031b1..b51257df713 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -286,10 +286,9 @@ language_item_table! { // FIXME(swatinem): the following lang items are used for async lowering and // should become obsolete eventually. - ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None; - GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; + Context, sym::Context, context, Target::Struct, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 82a77416a19..1d6f9b29176 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -751,17 +751,45 @@ fn check_region_bounds_on_impl_item<'tcx>( .get_generics(impl_m.def_id.expect_local()) .expect("expected impl item to have generics or else we can't compare them") .span; - let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() { - Some( - tcx.hir() - .get_generics(local_def_id) - .expect("expected trait item to have generics or else we can't compare them") - .span, - ) - } else { - None - }; + let mut generics_span = None; + let mut bounds_span = vec![]; + let mut where_span = None; + if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id) + && let Some(trait_generics) = trait_node.generics() + { + generics_span = Some(trait_generics.span); + // FIXME: we could potentially look at the impl's bounds to not point at bounds that + // *are* present in the impl. + for p in trait_generics.predicates { + if let hir::WherePredicate::BoundPredicate(pred) = p { + for b in pred.bounds { + if let hir::GenericBound::Outlives(lt) = b { + bounds_span.push(lt.ident.span); + } + } + } + } + if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id) + && let Some(impl_generics) = impl_node.generics() + { + let mut impl_bounds = 0; + for p in impl_generics.predicates { + if let hir::WherePredicate::BoundPredicate(pred) = p { + for b in pred.bounds { + if let hir::GenericBound::Outlives(_) = b { + impl_bounds += 1; + } + } + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if impl_generics.has_where_clause_predicates { + where_span = Some(impl_generics.where_clause_span); + } + } + } let reported = tcx .sess .create_err(LifetimesOrBoundsMismatchOnTrait { @@ -769,9 +797,10 @@ fn check_region_bounds_on_impl_item<'tcx>( item_kind: assoc_item_kind_str(impl_m), ident: impl_m.ident(tcx), generics_span, + bounds_span, + where_span, }) .emit_unless(delay); - return Err(reported); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index afbb27155a2..5156d432b5b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -43,6 +43,10 @@ pub struct LifetimesOrBoundsMismatchOnTrait { pub span: Span, #[label(generics_label)] pub generics_span: Option<Span>, + #[label(where_label)] + pub where_span: Option<Span>, + #[label(bounds_label)] + pub bounds_span: Vec<Span>, pub item_kind: &'static str, pub ident: Ident, } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 9db05eedbde..8b2719c2f8a 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -7,7 +7,8 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable}; use std::ops::ControlFlow; /// Defines the `TermsContext` basically houses an arena where we can @@ -75,11 +76,30 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; // ``` // we may not use `'c` in the hidden type. - struct OpaqueTypeLifetimeCollector { + struct OpaqueTypeLifetimeCollector<'tcx> { + tcx: TyCtxt<'tcx>, + root_def_id: DefId, variances: Vec<ty::Variance>, } - impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector { + impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> { + #[instrument(level = "trace", skip(self), ret)] + fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> { + if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) { + let child_variances = self.tcx.variances_of(def_id); + for (a, v) in substs.iter().zip(child_variances) { + if *v != ty::Bivariant { + a.visit_with(self)?; + } + } + ControlFlow::CONTINUE + } else { + substs.visit_with(self) + } + } + } + + impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { @@ -87,6 +107,19 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } r.super_visit_with(self) } + + #[instrument(level = "trace", skip(self), ret)] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + match t.kind() { + ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs), + ty::Projection(proj) + if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => + { + self.visit_opaque(proj.item_def_id, proj.substs) + } + _ => t.super_visit_with(self), + } + } } // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt @@ -111,7 +144,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } } - let mut collector = OpaqueTypeLifetimeCollector { variances }; + let mut collector = + OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 3078e0cbeda..8a875e05b19 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1918,15 +1918,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { receiver: Option<&'tcx hir::Expr<'tcx>>, args: &'tcx [hir::Expr<'tcx>], ) -> bool { - // Do not call `fn_sig` on non-functions. - if !matches!( - self.tcx.def_kind(def_id), - DefKind::Fn | DefKind::AssocFn | DefKind::Variant | DefKind::Ctor(..) - ) { + let ty = self.tcx.type_of(def_id); + if !ty.is_fn() { return false; } - - let sig = self.tcx.fn_sig(def_id).skip_binder(); + let sig = ty.fn_sig(self.tcx).skip_binder(); let args_referencing_param: Vec<_> = sig .inputs() .iter() diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ba4ddfd5cf..db93cfab2c0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1482,15 +1482,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident_name: Symbol, } + // FIXME: This really should be taking scoping, etc into account. impl<'v> Visitor<'v> for LetVisitor<'v> { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind { - if let Binding(_, _, ident, ..) = pat.kind && - ident.name == self.ident_name { - self.result = *init; - } + if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind + && let Binding(_, _, ident, ..) = pat.kind + && ident.name == self.ident_name + { + self.result = *init; + } else { + hir::intravisit::walk_stmt(self, ex); } - hir::intravisit::walk_stmt(self, ex); } } @@ -1498,9 +1500,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { visitor.visit_body(&body); let parent = self.tcx.hir().get_parent_node(seg1.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) && - let Some(expr) = visitor.result { - let self_ty = self.node_ty(expr.hir_id); + if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) + && let Some(expr) = visitor.result + && let Some(self_ty) = self.node_ty_opt(expr.hir_id) + { let probe = self.lookup_probe( seg2.ident, self_ty, @@ -1513,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(), "you may have meant to call an instance method", ".".to_string(), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 662136ca18d..3256ca1fb20 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -341,7 +341,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { - let ty::Opaque(def_id, substs) = *ty.kind() else { return None; }; + let (def_id, substs) = match *ty.kind() { + ty::Opaque(def_id, substs) => (def_id, substs), + ty::Projection(data) + if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => + { + (data.item_def_id, data.substs) + } + _ => return None, + }; let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a6205f4d3a5..2b8f6557c82 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -747,6 +747,7 @@ fn test_unstable_options_tracking_hash() { tracked!(link_only, true); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); + tracked!(maximal_hir_to_mir_coverage, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index cf1d82f4c06..0fa81b7e4e0 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -10,7 +10,7 @@ declare_tool_lint! { /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to /// always be passed by value. This is usually used for types that are thin wrappers around /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which - /// is a reference to an `Interned<TyS>`) + /// is a reference to an `Interned<TyKind>`) pub rustc::PASS_BY_VALUE, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a7836ea8e7a..b5db94f8c06 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -633,13 +633,34 @@ trait UnusedDelimLint { left_pos: Option<BytePos>, right_pos: Option<BytePos>, ) { + // If `value` has `ExprKind::Err`, unused delim lint can be broken. + // For example, the following code caused ICE. + // This is because the `ExprKind::Call` in `value` has `ExprKind::Err` as its argument + // and this leads to wrong spans. #104897 + // + // ``` + // fn f(){(print!(á + // ``` + use rustc_ast::visit::{walk_expr, Visitor}; + struct ErrExprVisitor { + has_error: bool, + } + impl<'ast> Visitor<'ast> for ErrExprVisitor { + fn visit_expr(&mut self, expr: &'ast ast::Expr) { + if let ExprKind::Err = expr.kind { + self.has_error = true; + return; + } + walk_expr(self, expr) + } + } + let mut visitor = ErrExprVisitor { has_error: false }; + visitor.visit_expr(value); + if visitor.has_error { + return; + } let spans = match value.kind { ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => { - if let StmtKind::Expr(expr) = &block.stmts[0].kind - && let ExprKind::Err = expr.kind - { - return - } if let Some(span) = block.stmts[0].span.find_ancestor_inside(value.span) { Some((value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))) } else { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9aed75931bf..6de68841fe9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -1,3 +1,5 @@ +#![allow(rustc::usage_of_ty_tykind)] + /// This higher-order macro declares a list of types which can be allocated by `Arena`. /// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type @@ -89,8 +91,8 @@ macro_rules! arena_types { [] hir_id_set: rustc_hir::HirIdSet, // Interned types - [] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>, - [] predicates: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::PredicateS<'tcx>>, + [] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>, + [] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>, [] consts: rustc_middle::ty::ConstS<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 5f911d5884a..221105ac48f 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -103,7 +103,7 @@ impl hash::Hash for Allocation { /// Interned types generally have an `Outer` type and an `Inner` type, where /// `Outer` is a newtype around `Interned<Inner>`, and all the operations are /// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an -/// outer type and `TyS` is its inner type. +/// outer type and `TyKind` is its inner type. /// /// Here things are different because only const allocations are interned. This /// means that both the inner type (`Allocation`) and the outer type diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c39d04d3819..82ca1b87535 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,5 +1,7 @@ //! Type context book-keeping. +#![allow(rustc::usage_of_ty_tykind)] + use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::hir::place::Place as HirPlace; @@ -19,15 +21,15 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, - UintTy, Visibility, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region, + RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, + Visibility, }; use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts}; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; @@ -68,6 +70,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; @@ -137,13 +140,13 @@ pub struct CtxtInterners<'tcx> { // Specifically use a speedy hash algorithm for these hash sets, since // they're accessed quite often. - type_: InternedSet<'tcx, WithStableHash<TyS<'tcx>>>, + type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>, const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>, region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, - predicate: InternedSet<'tcx, WithStableHash<PredicateS<'tcx>>>, + predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, @@ -194,15 +197,12 @@ impl<'tcx> CtxtInterners<'tcx> { let stable_hash = self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); - let ty_struct = TyS { - kind, + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: kind, + stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - }; - - InternedInSet( - self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }), - ) + })) }) .0, )) @@ -246,16 +246,12 @@ impl<'tcx> CtxtInterners<'tcx> { let stable_hash = self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); - let predicate_struct = PredicateS { - kind, + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: kind, + stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - }; - - InternedInSet( - self.arena - .alloc(WithStableHash { internee: predicate_struct, stable_hash }), - ) + })) }) .0, )) @@ -2104,7 +2100,7 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); for &InternedInSet(t) in types { - let variant = match t.kind { + let variant = match t.internee { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error(_) => /* unimportant */ continue, @@ -2214,51 +2210,26 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> { } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind - } -} - -impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> { - fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<TyS<'tcx>>>) -> bool { - // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals - // `x == y`. - self.0.kind == other.0.kind - } -} - -impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {} - -impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> { - fn hash<H: Hasher>(&self, s: &mut H) { - // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. - self.0.kind.hash(s) - } -} - -impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> - for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> -{ - fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { - &self.0.kind +impl<'tcx, T> Borrow<T> for InternedInSet<'tcx, WithCachedTypeInfo<T>> { + fn borrow<'a>(&'a self) -> &'a T { + &self.0.internee } } -impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> { - fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>) -> bool { +impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, WithCachedTypeInfo<T>> { + fn eq(&self, other: &InternedInSet<'tcx, WithCachedTypeInfo<T>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. - self.0.kind == other.0.kind + self.0.internee == other.0.internee } } -impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {} +impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {} -impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> { +impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, WithCachedTypeInfo<T>> { fn hash<H: Hasher>(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. - self.0.kind.hash(s) + self.0.internee.hash(s) } } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index a8da93e4c69..48329da3e63 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -101,6 +101,20 @@ impl GenericParamDef { _ => None, } } + + pub fn to_error<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + preceding_substs: &[ty::GenericArg<'tcx>], + ) -> ty::GenericArg<'tcx> { + match &self.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(), + ty::GenericParamDefKind::Const { .. } => { + tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into() + } + } + } } #[derive(Default)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9e73236f8d5..cd679ffdfbc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -9,6 +9,8 @@ //! //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html +#![allow(rustc::usage_of_ty_tykind)] + pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; pub use self::AssocItemContainer::*; @@ -32,7 +34,7 @@ use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; @@ -50,6 +52,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -445,86 +448,22 @@ pub struct CReaderCacheKey { pub pos: usize, } -/// Represents a type. -/// -/// IMPORTANT: -/// - This is a very "dumb" struct (with no derives and no `impls`). -/// - Values of this type are always interned and thus unique, and are stored -/// as an `Interned<TyS>`. -/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>` -/// should be used everywhere instead of `TyS`. In particular, `Ty` has most -/// of the relevant methods. -#[derive(PartialEq, Eq, PartialOrd, Ord)] -#[allow(rustc::usage_of_ty_tykind)] -pub(crate) struct TyS<'tcx> { - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::kind()` instead. - kind: TyKind<'tcx>, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::flags()` instead. - flags: TypeFlags, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This is a kind of confusing thing: it stores the smallest - /// binder such that - /// - /// (a) the binder itself captures nothing but - /// (b) all the late-bound things within the type are captured - /// by some sub-binder. - /// - /// So, for a type without any late-bound things, like `u32`, this - /// will be *innermost*, because that is the innermost binder that - /// captures nothing. But for a type `&'D u32`, where `'D` is a - /// late-bound region with De Bruijn index `D`, this would be `D + 1` - /// -- the binder itself does not capture `D`, but `D` is captured - /// by an inner binder. - /// - /// We call this concept an "exclusive" binder `D` because all - /// De Bruijn indices within the type are contained within `0..D` - /// (exclusive). - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `TyS`, whenever possible. +/// Use this rather than `TyKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] -pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>); +pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>); impl<'tcx> TyCtxt<'tcx> { /// A "bool" type used in rustc_mir_transform unit tests when we /// have not spun up a TyCtxt. - pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash { - internee: TyS { - kind: ty::Bool, + pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = + Ty(Interned::new_unchecked(&WithCachedTypeInfo { + internee: ty::Bool, + stable_hash: Fingerprint::ZERO, flags: TypeFlags::empty(), outer_exclusive_binder: DebruijnIndex::from_usize(0), - }, - stable_hash: Fingerprint::ZERO, - })); -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TyS { - kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - - outer_exclusive_binder: _, - } = self; - - kind.hash_stable(hcx, hasher) - } + })); } impl ty::EarlyBoundRegion { @@ -535,28 +474,18 @@ impl ty::EarlyBoundRegion { } } -/// Represents a predicate. -/// -/// See comments on `TyS`, which apply here too (albeit for -/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). -#[derive(Debug)] -pub(crate) struct PredicateS<'tcx> { - kind: Binder<'tcx, PredicateKind<'tcx>>, - flags: TypeFlags, - /// See the comment for the corresponding field of [TyS]. - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `PredicateS`, whenever possible. +/// Use this rather than `PredicateKind`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash<PredicateS<'tcx>>>); +pub struct Predicate<'tcx>( + Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, +); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.0.kind + self.0.internee } #[inline(always)] @@ -631,21 +560,6 @@ impl<'tcx> Predicate<'tcx> { } } -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for PredicateS<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let PredicateS { - ref kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - outer_exclusive_binder: _, - } = self; - - kind.hash_stable(hcx, hasher); - } -} - impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) @@ -1028,7 +942,7 @@ impl<'tcx> Term<'tcx> { unsafe { match ptr & TAG_MASK { TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), @@ -1072,7 +986,7 @@ impl<'tcx> TermKind<'tcx> { TermKind::Ty(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); - (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize) + (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize) } TermKind::Const(ct) => { // Ensure we can use the tag bits. @@ -1150,8 +1064,8 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { } } -pub trait ToPredicate<'tcx, Predicate> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate; +pub trait ToPredicate<'tcx, P = Predicate<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P; } impl<'tcx, T> ToPredicate<'tcx, T> for T { @@ -1160,21 +1074,21 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T { } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, PredicateKind<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(self) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Clause<'tcx> { +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); @@ -1193,25 +1107,25 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTraitPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyRegionOutlivesPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTypeOutlivesPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyProjectionPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) } @@ -2692,8 +2606,7 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(PredicateS<'_>, 48); - static_assert_size!(TyS<'_>, 40); - static_assert_size!(WithStableHash<TyS<'_>>, 56); + static_assert_size!(PredicateKind<'_>, 32); + static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 56); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5984686044b..9cbda95a4df 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -722,8 +722,17 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) } ExistentialPredicate::AutoTrait(did) => { - let trait_ref = self.rebind(tcx.mk_trait_ref(did, [self_ty])); - trait_ref.without_const().to_predicate(tcx) + let generics = tcx.generics_of(did); + let trait_ref = if generics.params.len() == 1 { + tcx.mk_trait_ref(did, [self_ty]) + } else { + // If this is an ill-formed auto trait, then synthesize + // new error substs for the missing generics. + let err_substs = + ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]); + tcx.mk_trait_ref(did, err_substs) + }; + self.rebind(trait_ref).without_const().to_predicate(tcx) } } } @@ -1602,7 +1611,7 @@ impl<'tcx> Region<'tcx> { impl<'tcx> Ty<'tcx> { #[inline(always)] pub fn kind(self) -> &'tcx TyKind<'tcx> { - &self.0.0.kind + &self.0.0 } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 141c8354c18..a1b084a5e89 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,10 +6,11 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; use core::intrinsics; @@ -84,7 +85,7 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); - (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize) + (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. @@ -162,7 +163,7 @@ impl<'tcx> GenericArg<'tcx> { &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>), ))), TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), @@ -352,6 +353,22 @@ impl<'tcx> InternalSubsts<'tcx> { } } + // Extend an `original_substs` list to the full number of substs expected by `def_id`, + // filling in the missing parameters with error ty/ct or 'static regions. + pub fn extend_with_error( + tcx: TyCtxt<'tcx>, + def_id: DefId, + original_substs: &[GenericArg<'tcx>], + ) -> SubstsRef<'tcx> { + ty::InternalSubsts::for_item(tcx, def_id, |def, substs| { + if let Some(subst) = original_substs.get(def.index as usize) { + *subst + } else { + def.to_error(tcx, substs) + } + }) + } + #[inline] pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx { self.iter() diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index b456e2aa37a..007f3b55ec8 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -948,20 +948,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { original_source_scope: SourceScope, pattern_span: Span, ) { - let tcx = self.tcx; - let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id); - let parent_root = tcx.maybe_lint_level_root_bounded( - self.source_scopes[original_source_scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root, - self.hir_id, - ); - if current_root != parent_root { - self.source_scope = - self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None); - } + let parent_id = self.source_scopes[original_source_scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id); } fn get_unit_temp(&mut self) -> Place<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 5ddae5f5300..33f49ffdaf6 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -85,6 +85,7 @@ use std::mem; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::HirId; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -567,25 +568,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>, { let source_scope = self.source_scope; - let tcx = self.tcx; if let LintLevel::Explicit(current_hir_id) = lint_level { - // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound - // to avoid adding Hir dependencies on our parents. - // We estimate the true lint roots here to avoid creating a lot of source scopes. - - let parent_root = tcx.maybe_lint_level_root_bounded( - self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root, - self.hir_id, - ); - let current_root = tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir_id); - - if parent_root != current_root { - self.source_scope = self.new_source_scope( - region_scope.1.span, - LintLevel::Explicit(current_root), - None, - ); - } + let parent_id = + self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root; + self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id); } self.push_scope(region_scope); let mut block; @@ -758,6 +744,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )) } + /// Possibly creates a new source scope if `current_root` and `parent_root` + /// are different, or if -Zmaximal-hir-to-mir-coverage is enabled. + pub(crate) fn maybe_new_source_scope( + &mut self, + span: Span, + safety: Option<Safety>, + current_id: HirId, + parent_id: HirId, + ) { + let (current_root, parent_root) = + if self.tcx.sess.opts.unstable_opts.maximal_hir_to_mir_coverage { + // Some consumers of rustc need to map MIR locations back to HIR nodes. Currently the + // the only part of rustc that tracks MIR -> HIR is the `SourceScopeLocalData::lint_root` + // field that tracks lint levels for MIR locations. Normally the number of source scopes + // is limited to the set of nodes with lint annotations. The -Zmaximal-hir-to-mir-coverage + // flag changes this behavior to maximize the number of source scopes, increasing the + // granularity of the MIR->HIR mapping. + (current_id, parent_id) + } else { + // Use `maybe_lint_level_root_bounded` with `self.hir_id` as a bound + // to avoid adding Hir dependencies on our parents. + // We estimate the true lint roots here to avoid creating a lot of source scopes. + ( + self.tcx.maybe_lint_level_root_bounded(current_id, self.hir_id), + self.tcx.maybe_lint_level_root_bounded(parent_id, self.hir_id), + ) + }; + + if current_root != parent_root { + let lint_level = LintLevel::Explicit(current_root); + self.source_scope = self.new_source_scope(span, lint_level, safety); + } + } + /// Creates a new source scope, nested in the current one. pub(crate) fn new_source_scope( &mut self, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 84c63219920..03f25392a7c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1414,7 +1414,10 @@ impl<'a> Parser<'a> { Ok((Some(vr), TrailingToken::MaybeComma)) }, - ) + ).map_err(|mut err|{ + err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"); + err + }) } /// Parses `struct Foo { ... }`. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4d8bff28b05..bebb012660a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -943,6 +943,10 @@ impl<'a> Parser<'a> { Err(e) => { // Parsing failed, therefore it must be something more serious // than just a missing separator. + for xx in &e.children { + // propagate the help message from sub error 'e' to main error 'expect_err; + expect_err.children.push(xx.clone()); + } expect_err.emit(); e.cancel(); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 2234837050b..1f65cc8b609 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1548,7 +1548,13 @@ impl<'tcx> Liveness<'_, 'tcx> { .or_insert_with(|| (ln, var, vec![id_and_sp])); }); - let can_remove = matches!(&pat.kind, hir::PatKind::Struct(_, _, true)); + let can_remove = match pat.kind { + hir::PatKind::Struct(_, fields, true) => { + // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix + fields.iter().all(|f| f.is_shorthand) + } + _ => false, + }; for (_, (ln, var, hir_ids_and_spans)) in vars { if self.used_on_entry(ln, var) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d8c4b0845d0..7a20100fd31 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -10,7 +10,7 @@ use crate::{lint, HashStableContext}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::ToStableHashKey; +use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_target::abi::Align; use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; @@ -288,6 +288,9 @@ pub enum OutputType { DepInfo, } +// Safety: Trivial C-Style enums have a stable sort order across compilation sessions. +unsafe impl StableOrd for OutputType {} + impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType { type KeyType = Self; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 01a9361e786..8e9198b79df 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1382,6 +1382,9 @@ options! { "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], "show macro backtraces (default: no)"), + maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED], + "save as much information as possible about the correspondence between MIR and HIR \ + as source scopes (default: no)"), merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED], "control the operation of the MergeFunctions LLVM pass, taking \ the same values as the target option of the same name"), diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index f5555846d20..0ad1f1a0da7 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -274,7 +274,7 @@ impl Ord for DefId { impl PartialOrd for DefId { #[inline] fn partial_cmp(&self, other: &DefId) -> Option<std::cmp::Ordering> { - Some(Ord::cmp(self, other)) + Some(self.cmp(other)) } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e446c96db3..61253845497 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -165,6 +165,7 @@ symbols! { Capture, Center, Clone, + Context, Continue, Copy, Count, @@ -264,7 +265,6 @@ symbols! { Relaxed, Release, Result, - ResumeTy, Return, Right, Rust, @@ -754,7 +754,6 @@ symbols! { generic_associated_types_extended, generic_const_exprs, generic_param_attrs, - get_context, global_allocator, global_asm, globs, diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 61743d78e9e..0102d268b42 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -70,7 +70,7 @@ pub fn codegen_select_candidate<'tcx>( // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. for err in errors { if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { - infcx.err_ctxt().report_overflow_error_cycle(&cycle); + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); } } return Err(CodegenObligationError::FulfillmentError); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e9e65336299..d01c6bac296 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt; #[instrument(skip(infcx), level = "debug")] pub fn is_const_evaluatable<'tcx>( infcx: &InferCtxt<'tcx>, - ct: ty::Const<'tcx>, + unexpanded_ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { let tcx = infcx.tcx; - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => uv, - // FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger - ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"), + match unexpanded_ct.kind() { + ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (), ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) @@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>( }; if tcx.features().generic_const_exprs { - let ct = tcx.expand_abstract_consts(ct); + let ct = tcx.expand_abstract_consts(unexpanded_ct); let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { tcx.def_kind(uv.def.did) == DefKind::AnonConst @@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>( } } - let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); - match concrete { - Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error( - infcx - .tcx - .sess - .delay_span_bug(span, "Missing value for constant, but no error reported?"), - )), - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), - Ok(_) => Ok(()), + match unexpanded_ct.kind() { + ty::ConstKind::Expr(_) => { + // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but + // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it + // is evaluatable or not. For now we just ICE until this is implemented this. + Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug( + span, + "evaluating `ConstKind::Expr` is not currently supported", + ))) + } + ty::ConstKind::Unevaluated(uv) => { + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); + match concrete { + Err(ErrorHandled::TooGeneric) => { + Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( + span, + "Missing value for constant, but no error reported?", + ))) + } + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Ok(_) => Ok(()), + } + } + _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), } } else { + let uv = match unexpanded_ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + ty::ConstKind::Expr(_) => { + bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled") + } + _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), + }; + // FIXME: We should only try to evaluate a given constant here if it is fully concrete // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. // @@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>( && satisfied_from_param_env( tcx, infcx, - tcx.expand_abstract_consts(ct), + tcx.expand_abstract_consts(unexpanded_ct), param_env, ) => { @@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>( impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> { type BreakTy = (); fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + debug!("is_const_evaluatable: candidate={:?}", c); if let Ok(()) = self.infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new_in_snapshot(self.infcx); if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()) @@ -187,7 +208,7 @@ fn satisfied_from_param_env<'tcx>( let result = b_ct.visit_with(&mut v); if let ControlFlow::Break(()) = result { - debug!("is_const_evaluatable: abstract_const ~~> ok"); + debug!("is_const_evaluatable: yes"); return true; } } @@ -195,5 +216,6 @@ fn satisfied_from_param_env<'tcx>( } } + debug!("is_const_evaluatable: no"); false } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 12cc72d30c8..dda7b2b2fa5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -99,26 +99,36 @@ pub trait InferCtxtExt<'tcx> { } pub trait TypeErrCtxtExt<'tcx> { + fn report_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + mutate: impl FnOnce(&mut Diagnostic), + ) -> ! + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + fn report_fulfillment_errors( &self, errors: &[FulfillmentError<'tcx>], body_id: Option<hir::BodyId>, ) -> ErrorGuaranteed; - fn report_overflow_error<T>( + fn report_overflow_obligation<T>( &self, obligation: &Obligation<'tcx, T>, suggest_increasing_limit: bool, ) -> ! where - T: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + T: ToPredicate<'tcx> + Clone; fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); - fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; + fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, @@ -458,8 +468,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// occurrences in any case. fn report_overflow_error<T>( &self, - obligation: &Obligation<'tcx, T>, + predicate: &T, + span: Span, suggest_increasing_limit: bool, + mutate: impl FnOnce(&mut Diagnostic), ) -> ! where T: fmt::Display @@ -467,8 +479,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, { - let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); + let predicate = self.resolve_vars_if_possible(predicate.clone()); let mut pred_str = predicate.to_string(); + if pred_str.len() > 50 { // We don't need to save the type to a file, we will be talking about this type already // in a separate note when we explain the obligation, so it will be available that way. @@ -483,7 +496,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let mut err = struct_span_err!( self.tcx.sess, - obligation.cause.span, + span, E0275, "overflow evaluating the requirement `{}`", pred_str, @@ -493,20 +506,46 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - self.note_obligation_cause_code( - &mut err, - &obligation.predicate, - obligation.param_env, - obligation.cause.code(), - &mut vec![], - &mut Default::default(), - ); + mutate(&mut err); err.emit(); self.tcx.sess.abort_if_errors(); bug!(); } + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_obligation<T>( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: ToPredicate<'tcx> + Clone, + { + let predicate = obligation.predicate.clone().to_predicate(self.tcx); + let predicate = self.resolve_vars_if_possible(predicate); + self.report_overflow_error( + &predicate, + obligation.cause.span, + suggest_increasing_limit, + |err| { + self.note_obligation_cause_code( + err, + &predicate, + obligation.param_env, + obligation.cause.code(), + &mut vec![], + &mut Default::default(), + ); + }, + ); + } + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { let suggested_limit = match self.tcx.recursion_limit() { Limit(0) => Limit(2), @@ -521,11 +560,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_error` except + /// compilation. This is equivalent to `report_overflow_obligation` except /// that we can give a more helpful error message (and, in particular, /// we do not suggest increasing the overflow limit, which is not /// going to help). - fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); @@ -533,7 +572,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // The 'deepest' obligation is most likely to have a useful // cause 'backtrace' - self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false); + self.report_overflow_obligation( + cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), + false, + ); } fn report_selection_error( @@ -1554,7 +1596,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { diag.emit(); } FulfillmentErrorCode::CodeCycle(ref cycle) => { - self.report_overflow_error_cycle(cycle); + self.report_overflow_obligation_cycle(cycle); } } } @@ -1607,7 +1649,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - let expected_ty = data.term.ty().unwrap(); + let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error()); // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1740128727a..6ea54b625bb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -298,7 +298,7 @@ pub trait TypeErrCtxtExt<'tcx> { obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where - T: fmt::Display + ToPredicate<'tcx, T>; + T: fmt::Display + ToPredicate<'tcx>; /// Suggest to await before try: future? => future.await? fn suggest_await_before_try( @@ -2353,7 +2353,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where - T: fmt::Display, + T: fmt::Display + ToPredicate<'tcx>, { let tcx = self.tcx; match *cause_code { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c6818a4e57d..d3cfd61e195 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -150,7 +150,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + TypeVisitable<'tcx>, + pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>, span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 71f6eae45aa..5789754e4fc 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -504,14 +504,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { - let obligation = Obligation::with_depth( - self.tcx(), - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, + self.selcx.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + true, + |_| {}, ); - self.selcx.infcx.err_ctxt().report_overflow_error(&obligation, true); } let substs = substs.fold_with(self); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index f899321fc01..7ad532d8a34 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::TypeErrCtxtExt; use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; -use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; @@ -214,14 +214,12 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let substs = substs.try_fold_with(self)?; let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { - let obligation = Obligation::with_depth( - self.tcx(), - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, + self.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + true, + |_| {}, ); - self.infcx.err_ctxt().report_overflow_error(&obligation, true); } let generic_ty = self.tcx().bound_type_of(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8835f2cc1b9..035deb61639 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -43,7 +43,6 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; @@ -1313,10 +1312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { error_obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> where - T: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + T: ToPredicate<'tcx> + Clone, { if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { match self.query_mode { @@ -1324,7 +1320,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(e) = self.infcx.tainted_by_errors() { return Err(OverflowError::Error(e)); } - self.infcx.err_ctxt().report_overflow_error(error_obligation, true); + self.infcx.err_ctxt().report_overflow_obligation(error_obligation, true); } TraitQueryMode::Canonical => { return Err(OverflowError::Canonical); @@ -1345,10 +1341,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { error_obligation: &Obligation<'tcx, V>, ) -> Result<(), OverflowError> where - V: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <V as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + V: ToPredicate<'tcx> + Clone, { self.check_recursion_depth(obligation.recursion_depth, error_obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0855d6d1973..e47ba64245f 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> { ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())), )); } - // FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger ty::ConstKind::Expr(_) => { - bug!("checking wfness of `ConstKind::Expr` is unsupported") + // FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the + // trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary + // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` + // which means that the `DefId` would have been typeck'd elsewhere. However in + // the future we may allow directly lowering to `ConstKind::Expr` in which case + // we would not be proving bounds we should. + + let predicate = + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + predicate, + )); } ty::ConstKind::Error(_) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 581993ba7d8..e3f7a1bd033 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -19,9 +19,11 @@ use std::mem::discriminant; pub mod codec; pub mod sty; +pub mod ty_info; pub use codec::*; pub use sty::*; +pub use ty_info::*; /// Needed so we can use #[derive(HashStable_Generic)] pub trait HashStableContext {} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 02cbb2e858f..3ed616d709b 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -301,61 +301,44 @@ impl<I: Interner> Clone for TyKind<I> { impl<I: Interner> PartialEq for TyKind<I> { #[inline] fn eq(&self, other: &TyKind<I>) -> bool { - let __self_vi = tykind_discriminant(self); - let __arg_1_vi = tykind_discriminant(other); - if __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Int(ref __self_0), &Int(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Float(ref __self_0), &Float(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 + tykind_discriminant(self) == tykind_discriminant(other) + && match (self, other) { + (Int(a_i), Int(b_i)) => a_i == b_i, + (Uint(a_u), Uint(b_u)) => a_u == b_u, + (Float(a_f), Float(b_f)) => a_f == b_f, + (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, + (Foreign(a_d), Foreign(b_d)) => a_d == b_d, + (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, + (Slice(a_t), Slice(b_t)) => a_t == b_t, + (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t, + (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, + (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s, + (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s, + (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => { + a_p == b_p && a_r == b_r && a_repr == b_repr } - (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 + (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, + (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { + a_d == b_d && a_s == b_s && a_m == b_m } - (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => __self_0 == __arg_1_0, - ( - &Ref(ref __self_0, ref __self_1, ref __self_2), - &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2), - ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2, - (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 + (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, + (Tuple(a_t), Tuple(b_t)) => a_t == b_t, + (Projection(a_p), Projection(b_p)) => a_p == b_p, + (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d == b_d && a_s == b_s, + (Param(a_p), Param(b_p)) => a_p == b_p, + (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b, + (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p, + (Infer(a_t), Infer(b_t)) => a_t == b_t, + (Error(a_e), Error(b_e)) => a_e == b_e, + (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true, + _ => { + debug_assert!( + false, + "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" + ); + true } - (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0, - ( - &Dynamic(ref __self_0, ref __self_1, ref self_repr), - &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), - ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && self_repr == arg_repr, - (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } - ( - &Generator(ref __self_0, ref __self_1, ref __self_2), - &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2), - ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2, - (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => { - __self_0 == __arg_1_0 - } - (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } - (&Param(ref __self_0), &Param(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } - (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Error(ref __self_0), &Error(ref __arg_1_0)) => __self_0 == __arg_1_0, - _ => true, } - } else { - false - } } } @@ -366,7 +349,7 @@ impl<I: Interner> Eq for TyKind<I> {} impl<I: Interner> PartialOrd for TyKind<I> { #[inline] fn partial_cmp(&self, other: &TyKind<I>) -> Option<Ordering> { - Some(Ord::cmp(self, other)) + Some(self.cmp(other)) } } @@ -374,213 +357,106 @@ impl<I: Interner> PartialOrd for TyKind<I> { impl<I: Interner> Ord for TyKind<I> { #[inline] fn cmp(&self, other: &TyKind<I>) -> Ordering { - let __self_vi = tykind_discriminant(self); - let __arg_1_vi = tykind_discriminant(other); - if __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Int(ref __self_0), &Int(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Float(ref __self_0), &Float(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } - } - (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } - } - (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - ( - &Ref(ref __self_0, ref __self_1, ref __self_2), - &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2), - ) => match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { - Ordering::Equal => Ord::cmp(__self_2, __arg_1_2), - cmp => cmp, - }, - cmp => cmp, - }, - (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } + tykind_discriminant(self).cmp(&tykind_discriminant(other)).then_with(|| { + match (self, other) { + (Int(a_i), Int(b_i)) => a_i.cmp(b_i), + (Uint(a_u), Uint(b_u)) => a_u.cmp(b_u), + (Float(a_f), Float(b_f)) => a_f.cmp(b_f), + (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)), + (Foreign(a_d), Foreign(b_d)) => a_d.cmp(b_d), + (Array(a_t, a_c), Array(b_t, b_c)) => a_t.cmp(b_t).then_with(|| a_c.cmp(b_c)), + (Slice(a_t), Slice(b_t)) => a_t.cmp(b_t), + (RawPtr(a_t), RawPtr(b_t)) => a_t.cmp(b_t), + (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => { + a_r.cmp(b_r).then_with(|| a_t.cmp(b_t).then_with(|| a_m.cmp(b_m))) } - (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - ( - &Dynamic(ref __self_0, ref __self_1, ref self_repr), - &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), - ) => match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { - Ordering::Equal => Ord::cmp(self_repr, arg_repr), - cmp => cmp, - }, - cmp => cmp, - }, - (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } + (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)), + (FnPtr(a_s), FnPtr(b_s)) => a_s.cmp(b_s), + (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => { + a_p.cmp(b_p).then_with(|| a_r.cmp(b_r).then_with(|| a_repr.cmp(b_repr))) } - ( - &Generator(ref __self_0, ref __self_1, ref __self_2), - &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2), - ) => match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { - Ordering::Equal => Ord::cmp(__self_2, __arg_1_2), - cmp => cmp, - }, - cmp => cmp, - }, - (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => { - Ord::cmp(__self_0, __arg_1_0) + (Closure(a_p, a_s), Closure(b_p, b_s)) => a_p.cmp(b_p).then_with(|| a_s.cmp(b_s)), + (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { + a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m))) } - (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => { - Ord::cmp(__self_0, __arg_1_0) + (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g), + (Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t), + (Projection(a_p), Projection(b_p)) => a_p.cmp(b_p), + (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)), + (Param(a_p), Param(b_p)) => a_p.cmp(b_p), + (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d.cmp(b_d).then_with(|| a_b.cmp(b_b)), + (Placeholder(a_p), Placeholder(b_p)) => a_p.cmp(b_p), + (Infer(a_t), Infer(b_t)) => a_t.cmp(b_t), + (Error(a_e), Error(b_e)) => a_e.cmp(b_e), + (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal, + _ => { + debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"); + Ordering::Equal } - (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } - } - (&Param(ref __self_0), &Param(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - } - } - (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => { - Ord::cmp(__self_0, __arg_1_0) - } - (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Error(ref __self_0), &Error(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - _ => Ordering::Equal, } - } else { - Ord::cmp(&__self_vi, &__arg_1_vi) - } + }) } } // This is manually implemented because a derive would require `I: Hash` impl<I: Interner> hash::Hash for TyKind<I> { fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () { - match (&*self,) { - (&Int(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Uint(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Float(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Adt(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&Foreign(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Array(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&Slice(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&RawPtr(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Ref(ref __self_0, ref __self_1, ref __self_2),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state); - hash::Hash::hash(__self_2, state) - } - (&FnDef(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&FnPtr(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Dynamic(ref __self_0, ref __self_1, ref repr),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state); - hash::Hash::hash(repr, state) - } - (&Closure(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&Generator(ref __self_0, ref __self_1, ref __self_2),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state); - hash::Hash::hash(__self_2, state) - } - (&GeneratorWitness(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Tuple(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Projection(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Opaque(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&Param(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Bound(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&Placeholder(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&Infer(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) + tykind_discriminant(self).hash(state); + match self { + Int(i) => i.hash(state), + Uint(u) => u.hash(state), + Float(f) => f.hash(state), + Adt(d, s) => { + d.hash(state); + s.hash(state) + } + Foreign(d) => d.hash(state), + Array(t, c) => { + t.hash(state); + c.hash(state) } - (&Error(ref __self_0),) => { - hash::Hash::hash(&tykind_discriminant(self), state); - hash::Hash::hash(__self_0, state) + Slice(t) => t.hash(state), + RawPtr(t) => t.hash(state), + Ref(r, t, m) => { + r.hash(state); + t.hash(state); + m.hash(state) + } + FnDef(d, s) => { + d.hash(state); + s.hash(state) + } + FnPtr(s) => s.hash(state), + Dynamic(p, r, repr) => { + p.hash(state); + r.hash(state); + repr.hash(state) + } + Closure(d, s) => { + d.hash(state); + s.hash(state) + } + Generator(d, s, m) => { + d.hash(state); + s.hash(state); + m.hash(state) + } + GeneratorWitness(g) => g.hash(state), + Tuple(t) => t.hash(state), + Projection(p) => p.hash(state), + Opaque(d, s) => { + d.hash(state); + s.hash(state) + } + Param(p) => p.hash(state), + Bound(d, b) => { + d.hash(state); + b.hash(state) } - _ => hash::Hash::hash(&tykind_discriminant(self), state), + Placeholder(p) => p.hash(state), + Infer(t) => t.hash(state), + Error(e) => e.hash(state), + Bool | Char | Str | Never => (), } } } @@ -588,37 +464,34 @@ impl<I: Interner> hash::Hash for TyKind<I> { // This is manually implemented because a derive would require `I: Debug` impl<I: Interner> fmt::Debug for TyKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::fmt::*; match self { - Bool => Formatter::write_str(f, "Bool"), - Char => Formatter::write_str(f, "Char"), - Int(f0) => Formatter::debug_tuple_field1_finish(f, "Int", f0), - Uint(f0) => Formatter::debug_tuple_field1_finish(f, "Uint", f0), - Float(f0) => Formatter::debug_tuple_field1_finish(f, "Float", f0), - Adt(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Adt", f0, f1), - Foreign(f0) => Formatter::debug_tuple_field1_finish(f, "Foreign", f0), - Str => Formatter::write_str(f, "Str"), - Array(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Array", f0, f1), - Slice(f0) => Formatter::debug_tuple_field1_finish(f, "Slice", f0), - RawPtr(f0) => Formatter::debug_tuple_field1_finish(f, "RawPtr", f0), - Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2), - FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1), - FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0), - Dynamic(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Dynamic", f0, f1, f2), - Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1), - Generator(f0, f1, f2) => { - Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2) - } - GeneratorWitness(f0) => Formatter::debug_tuple_field1_finish(f, "GeneratorWitness", f0), - Never => Formatter::write_str(f, "Never"), - Tuple(f0) => Formatter::debug_tuple_field1_finish(f, "Tuple", f0), - Projection(f0) => Formatter::debug_tuple_field1_finish(f, "Projection", f0), - Opaque(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Opaque", f0, f1), - Param(f0) => Formatter::debug_tuple_field1_finish(f, "Param", f0), - Bound(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Bound", f0, f1), - Placeholder(f0) => Formatter::debug_tuple_field1_finish(f, "Placeholder", f0), - Infer(f0) => Formatter::debug_tuple_field1_finish(f, "Infer", f0), - TyKind::Error(f0) => Formatter::debug_tuple_field1_finish(f, "Error", f0), + Bool => f.write_str("Bool"), + Char => f.write_str("Char"), + Int(i) => f.debug_tuple_field1_finish("Int", i), + Uint(u) => f.debug_tuple_field1_finish("Uint", u), + Float(float) => f.debug_tuple_field1_finish("Float", float), + Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s), + Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), + Str => f.write_str("Str"), + Array(t, c) => f.debug_tuple_field2_finish("Array", t, c), + Slice(t) => f.debug_tuple_field1_finish("Slice", t), + RawPtr(t) => f.debug_tuple_field1_finish("RawPtr", t), + Ref(r, t, m) => f.debug_tuple_field3_finish("Ref", r, t, m), + FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s), + FnPtr(s) => f.debug_tuple_field1_finish("FnPtr", s), + Dynamic(p, r, repr) => f.debug_tuple_field3_finish("Dynamic", p, r, repr), + Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), + Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), + GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), + Never => f.write_str("Never"), + Tuple(t) => f.debug_tuple_field1_finish("Tuple", t), + Projection(p) => f.debug_tuple_field1_finish("Projection", p), + Opaque(d, s) => f.debug_tuple_field2_finish("Opaque", d, s), + Param(p) => f.debug_tuple_field1_finish("Param", p), + Bound(d, b) => f.debug_tuple_field2_finish("Bound", d, b), + Placeholder(p) => f.debug_tuple_field1_finish("Placeholder", p), + Infer(t) => f.debug_tuple_field1_finish("Infer", t), + TyKind::Error(e) => f.debug_tuple_field1_finish("Error", e), } } } @@ -1091,12 +964,12 @@ where impl<I: Interner> Clone for RegionKind<I> { fn clone(&self) -> Self { match self { - ReEarlyBound(a) => ReEarlyBound(a.clone()), - ReLateBound(a, b) => ReLateBound(a.clone(), b.clone()), - ReFree(a) => ReFree(a.clone()), + ReEarlyBound(r) => ReEarlyBound(r.clone()), + ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()), + ReFree(r) => ReFree(r.clone()), ReStatic => ReStatic, - ReVar(a) => ReVar(a.clone()), - RePlaceholder(a) => RePlaceholder(a.clone()), + ReVar(r) => ReVar(r.clone()), + RePlaceholder(r) => RePlaceholder(r.clone()), ReErased => ReErased, } } @@ -1106,29 +979,23 @@ impl<I: Interner> Clone for RegionKind<I> { impl<I: Interner> PartialEq for RegionKind<I> { #[inline] fn eq(&self, other: &RegionKind<I>) -> bool { - let __self_vi = regionkind_discriminant(self); - let __arg_1_vi = regionkind_discriminant(other); - if __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => { - __self_0 == __arg_1_0 + regionkind_discriminant(self) == regionkind_discriminant(other) + && match (self, other) { + (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r, + (ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => a_d == b_d && a_r == b_r, + (ReFree(a_r), ReFree(b_r)) => a_r == b_r, + (ReStatic, ReStatic) => true, + (ReVar(a_r), ReVar(b_r)) => a_r == b_r, + (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r, + (ReErased, ReErased) => true, + _ => { + debug_assert!( + false, + "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" + ); + true } - ( - &ReLateBound(ref __self_0, ref __self_1), - &ReLateBound(ref __arg_1_0, ref __arg_1_1), - ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1, - (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&ReStatic, &ReStatic) => true, - (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { - __self_0 == __arg_1_0 - } - (&ReErased, &ReErased) => true, - _ => true, } - } else { - false - } } } @@ -1139,7 +1006,7 @@ impl<I: Interner> Eq for RegionKind<I> {} impl<I: Interner> PartialOrd for RegionKind<I> { #[inline] fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> { - Some(Ord::cmp(self, other)) + Some(self.cmp(other)) } } @@ -1147,66 +1014,41 @@ impl<I: Interner> PartialOrd for RegionKind<I> { impl<I: Interner> Ord for RegionKind<I> { #[inline] fn cmp(&self, other: &RegionKind<I>) -> Ordering { - let __self_vi = regionkind_discriminant(self); - let __arg_1_vi = regionkind_discriminant(other); - if __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => { - Ord::cmp(__self_0, __arg_1_0) + regionkind_discriminant(self).cmp(®ionkind_discriminant(other)).then_with(|| { + match (self, other) { + (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r.cmp(b_r), + (ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => { + a_d.cmp(b_d).then_with(|| a_r.cmp(b_r)) } - ( - &ReLateBound(ref __self_0, ref __self_1), - &ReLateBound(ref __arg_1_0, ref __arg_1_1), - ) => match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), - cmp => cmp, - }, - (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&ReStatic, &ReStatic) => Ordering::Equal, - (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { - Ord::cmp(__self_0, __arg_1_0) + (ReFree(a_r), ReFree(b_r)) => a_r.cmp(b_r), + (ReStatic, ReStatic) => Ordering::Equal, + (ReVar(a_r), ReVar(b_r)) => a_r.cmp(b_r), + (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r.cmp(b_r), + (ReErased, ReErased) => Ordering::Equal, + _ => { + debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"); + Ordering::Equal } - (&ReErased, &ReErased) => Ordering::Equal, - _ => Ordering::Equal, } - } else { - Ord::cmp(&__self_vi, &__arg_1_vi) - } + }) } } // This is manually implemented because a derive would require `I: Hash` impl<I: Interner> hash::Hash for RegionKind<I> { - fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () { - match (&*self,) { - (&ReEarlyBound(ref __self_0),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&ReLateBound(ref __self_0, ref __self_1),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) - } - (&ReFree(ref __self_0),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&ReStatic,) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - } - (&ReVar(ref __self_0),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&RePlaceholder(ref __self_0),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } - (&ReErased,) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - } + fn hash<H: hash::Hasher>(&self, state: &mut H) -> () { + regionkind_discriminant(self).hash(state); + match self { + ReEarlyBound(r) => r.hash(state), + ReLateBound(d, r) => { + d.hash(state); + r.hash(state) + } + ReFree(r) => r.hash(state), + ReStatic => (), + ReVar(r) => r.hash(state), + RePlaceholder(r) => r.hash(state), + ReErased => (), } } } @@ -1215,21 +1057,21 @@ impl<I: Interner> hash::Hash for RegionKind<I> { impl<I: Interner> fmt::Debug for RegionKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ReEarlyBound(ref data) => write!(f, "ReEarlyBound({:?})", data), + ReEarlyBound(data) => write!(f, "ReEarlyBound({:?})", data), - ReLateBound(binder_id, ref bound_region) => { + ReLateBound(binder_id, bound_region) => { write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region) } - ReFree(ref fr) => fr.fmt(f), + ReFree(fr) => fr.fmt(f), - ReStatic => write!(f, "ReStatic"), + ReStatic => f.write_str("ReStatic"), - ReVar(ref vid) => vid.fmt(f), + ReVar(vid) => vid.fmt(f), RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder), - ReErased => write!(f, "ReErased"), + ReErased => f.write_str("ReErased"), } } } @@ -1317,18 +1159,18 @@ where ReErased | ReStatic => { // No variant fields to hash for these ... } - ReLateBound(db, br) => { - db.hash_stable(hcx, hasher); - br.hash_stable(hcx, hasher); + ReLateBound(d, r) => { + d.hash_stable(hcx, hasher); + r.hash_stable(hcx, hasher); } - ReEarlyBound(eb) => { - eb.hash_stable(hcx, hasher); + ReEarlyBound(r) => { + r.hash_stable(hcx, hasher); } - ReFree(ref free_region) => { - free_region.hash_stable(hcx, hasher); + ReFree(r) => { + r.hash_stable(hcx, hasher); } - RePlaceholder(p) => { - p.hash_stable(hcx, hasher); + RePlaceholder(r) => { + r.hash_stable(hcx, hasher); } ReVar(_) => { panic!("region variables should not be hashed: {self:?}") diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs new file mode 100644 index 00000000000..4e5d424886a --- /dev/null +++ b/compiler/rustc_type_ir/src/ty_info.rs @@ -0,0 +1,122 @@ +use std::{ + cmp::Ordering, + hash::{Hash, Hasher}, + ops::Deref, +}; + +use rustc_data_structures::{ + fingerprint::Fingerprint, + stable_hasher::{HashStable, StableHasher}, +}; + +use crate::{DebruijnIndex, TypeFlags}; + +/// A helper type that you can wrap round your own type in order to automatically +/// cache the stable hash, type flags and debruijn index on creation and +/// not recompute it whenever the information is needed. +/// This is only done in incremental mode. You can also opt out of caching by using +/// StableHash::ZERO for the hash, in which case the hash gets computed each time. +/// This is useful if you have values that you intern but never (can?) use for stable +/// hashing. +#[derive(Copy, Clone)] +pub struct WithCachedTypeInfo<T> { + pub internee: T, + pub stable_hash: Fingerprint, + + /// This field provides fast access to information that is also contained + /// in `kind`. + /// + /// This field shouldn't be used directly and may be removed in the future. + /// Use `Ty::flags()` instead. + pub flags: TypeFlags, + + /// This field provides fast access to information that is also contained + /// in `kind`. + /// + /// This is a kind of confusing thing: it stores the smallest + /// binder such that + /// + /// (a) the binder itself captures nothing but + /// (b) all the late-bound things within the type are captured + /// by some sub-binder. + /// + /// So, for a type without any late-bound things, like `u32`, this + /// will be *innermost*, because that is the innermost binder that + /// captures nothing. But for a type `&'D u32`, where `'D` is a + /// late-bound region with De Bruijn index `D`, this would be `D + 1` + /// -- the binder itself does not capture `D`, but `D` is captured + /// by an inner binder. + /// + /// We call this concept an "exclusive" binder `D` because all + /// De Bruijn indices within the type are contained within `0..D` + /// (exclusive). + pub outer_exclusive_binder: DebruijnIndex, +} + +impl<T: PartialEq> PartialEq for WithCachedTypeInfo<T> { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.internee.eq(&other.internee) + } +} + +impl<T: Eq> Eq for WithCachedTypeInfo<T> {} + +impl<T: Ord> PartialOrd for WithCachedTypeInfo<T> { + fn partial_cmp(&self, other: &WithCachedTypeInfo<T>) -> Option<Ordering> { + Some(self.internee.cmp(&other.internee)) + } +} + +impl<T: Ord> Ord for WithCachedTypeInfo<T> { + fn cmp(&self, other: &WithCachedTypeInfo<T>) -> Ordering { + self.internee.cmp(&other.internee) + } +} + +impl<T> Deref for WithCachedTypeInfo<T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.internee + } +} + +impl<T: Hash> Hash for WithCachedTypeInfo<T> { + #[inline] + fn hash<H: Hasher>(&self, s: &mut H) { + if self.stable_hash != Fingerprint::ZERO { + self.stable_hash.hash(s) + } else { + self.internee.hash(s) + } + } +} + +impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) { + // No cached hash available. This can only mean that incremental is disabled. + // We don't cache stable hashes in non-incremental mode, because they are used + // so rarely that the performance actually suffers. + + // We need to build the hash as if we cached it and then hash that hash, as + // otherwise the hashes will differ between cached and non-cached mode. + let stable_hash: Fingerprint = { + let mut hasher = StableHasher::new(); + self.internee.hash_stable(hcx, &mut hasher); + hasher.finish() + }; + if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO { + assert_eq!( + stable_hash, self.stable_hash, + "cached stable hash does not match freshly computed stable hash" + ); + } + stable_hash.hash_stable(hcx, hasher); + } else { + self.stable_hash.hash_stable(hcx, hasher); + } + } +} diff --git a/config.toml.example b/config.toml.example index c94a27b12a3..ca54cbd2d68 100644 --- a/config.toml.example +++ b/config.toml.example @@ -255,6 +255,16 @@ changelog-seen = 2 # Defaults to the Python interpreter used to execute x.py #python = "python" +# The path to the REUSE executable to use. Note that REUSE is not required in +# most cases, as our tooling relies on a cached (and shrinked) copy of the +# REUSE output present in the git repository and in our source tarballs. +# +# REUSE is only needed if your changes caused the overral licensing of the +# repository to change, and the cached copy has to be regenerated. +# +# Defaults to the "reuse" command in the system path. +#reuse = "reuse" + # Force Cargo to check that Cargo.lock describes the precise dependency # set that all the Cargo.toml files create, instead of updating it. #locked-deps = false diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index f2b961d62e0..2a8e12fd4cf 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -44,7 +44,7 @@ pub use poll_fn::{poll_fn, PollFn}; /// non-Send/Sync as well, and we don't want that. /// /// It also simplifies the HIR lowering of `.await`. -#[cfg_attr(not(bootstrap), lang = "ResumeTy")] +// FIXME(swatinem): This type can be removed when bumping the bootstrap compiler #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[derive(Debug, Copy, Clone)] @@ -61,6 +61,7 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` +// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler #[cfg_attr(bootstrap, lang = "from_generator")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] @@ -102,7 +103,8 @@ where GenFuture(gen) } -#[lang = "get_context"] +// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler +#[cfg_attr(bootstrap, lang = "get_context")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[must_use] @@ -113,6 +115,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { unsafe { &mut *cx.0.as_ptr().cast() } } +// FIXME(swatinem): This fn is currently needed to work around shortcomings +// in type and lifetime inference. +// See the comment at the bottom of `LoweringContext::make_async_expr` and +// <https://github.com/rust-lang/rust/issues/104826>. #[cfg_attr(not(bootstrap), lang = "identity_future")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 0cff972df3a..9ab9b0ba1c7 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -174,6 +174,7 @@ impl RawWakerVTable { /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) /// which can be used to wake the current task. #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg_attr(not(bootstrap), lang = "Context")] pub struct Context<'a> { waker: &'a Waker, // Ensure we future-proof against variance changes by forcing diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 27fba761ada..adb488d4378 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -629,9 +629,7 @@ impl<T> Clone for Sender<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Drop for Sender<T> { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -751,9 +749,7 @@ impl<T> Clone for SyncSender<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Drop for SyncSender<T> { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -1094,9 +1090,7 @@ impl<T> IntoIterator for Receiver<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Drop for Receiver<T> { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cff5fd8c5b0..8ee6d49da8f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -754,6 +754,8 @@ impl<'a> Builder<'a> { run::BumpStage0, run::ReplaceVersionPlaceholder, run::Miri, + run::CollectLicenseMetadata, + run::GenerateCopyright, ), // These commands either don't use paths, or they're special-cased in Build::build() Kind::Clean | Kind::Format | Kind::Setup => vec![], diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index babf09d2b93..d8c15c76e2d 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -213,6 +213,7 @@ pub struct Config { pub npm: Option<PathBuf>, pub gdb: Option<PathBuf>, pub python: Option<PathBuf>, + pub reuse: Option<PathBuf>, pub cargo_native_static: bool, pub configure_args: Vec<String>, @@ -611,6 +612,7 @@ define_config! { nodejs: Option<String> = "nodejs", npm: Option<String> = "npm", python: Option<String> = "python", + reuse: Option<String> = "reuse", locked_deps: Option<bool> = "locked-deps", vendor: Option<bool> = "vendor", full_bootstrap: Option<bool> = "full-bootstrap", @@ -1004,6 +1006,7 @@ impl Config { config.npm = build.npm.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); config.python = build.python.map(PathBuf::from); + config.reuse = build.reuse.map(PathBuf::from); config.submodules = build.submodules; set(&mut config.low_priority, build.low_priority); set(&mut config.compiler_docs, build.compiler_docs); diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index d49b41c5132..05de51f8cc5 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,3 +1,4 @@ +use std::path::PathBuf; use std::process::Command; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; @@ -189,3 +190,65 @@ impl Step for Miri { builder.run(&mut miri); } } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct CollectLicenseMetadata; + +impl Step for CollectLicenseMetadata { + type Output = PathBuf; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/collect-license-metadata") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CollectLicenseMetadata); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let Some(reuse) = &builder.config.reuse else { + panic!("REUSE is required to collect the license metadata"); + }; + + // Temporary location, it will be moved to src/etc once it's accurate. + let dest = builder.out.join("license-metadata.json"); + + let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata); + cmd.env("REUSE_EXE", reuse); + cmd.env("DEST", &dest); + builder.run(&mut cmd); + + dest + } +} + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct GenerateCopyright; + +impl Step for GenerateCopyright { + type Output = PathBuf; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/generate-copyright") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(GenerateCopyright); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let license_metadata = builder.ensure(CollectLicenseMetadata); + + // Temporary location, it will be moved to the proper one once it's accurate. + let dest = builder.out.join("COPYRIGHT.md"); + + let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); + cmd.env("LICENSE_METADATA", &license_metadata); + cmd.env("DEST", &dest); + builder.run(&mut cmd); + + dest + } +} diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 631d42acb93..8a40b0f64f4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -140,6 +140,13 @@ than building it. .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("gdb")); + build.config.reuse = build + .config + .reuse + .take() + .map(|p| cmd_finder.must_have(p)) + .or_else(|| cmd_finder.maybe_have("reuse")); + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in &build.targets { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index ba329ea6c75..e0be4c432f1 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -380,6 +380,8 @@ bootstrap_tool!( HtmlChecker, "src/tools/html-checker", "html-checker"; BumpStage0, "src/tools/bump-stage0", "bump-stage0"; ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; + CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; + GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 528e99d2ce0..0cd15768ac6 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -195,8 +195,7 @@ h1, h2, h3, h4, h5, h6, span.since, a.srclink, #help-button > a, -details.rustdoc-toggle.top-doc > summary, -details.rustdoc-toggle.non-exhaustive > summary, +summary.hideme, .scraped-example-list, /* This selector is for the items listed in the "all items" page. */ ul.all-items { @@ -1484,6 +1483,7 @@ details.rustdoc-toggle { "Expand description" or "Show methods". */ details.rustdoc-toggle > summary.hideme { cursor: pointer; + font-size: 1rem; } details.rustdoc-toggle > summary { @@ -1546,13 +1546,6 @@ details.rustdoc-toggle > summary:focus-visible::before { outline-offset: 1px; } -details.rustdoc-toggle.top-doc > summary, -details.rustdoc-toggle.top-doc > summary::before, -details.rustdoc-toggle.non-exhaustive > summary, -details.rustdoc-toggle.non-exhaustive > summary::before { - font-size: 1rem; -} - details.non-exhaustive { margin-bottom: 8px; } diff --git a/src/test/rustdoc-gui/enum-variants.goml b/src/test/rustdoc-gui/enum-variants.goml index 230abb236bd..8dfc49285f2 100644 --- a/src/test/rustdoc-gui/enum-variants.goml +++ b/src/test/rustdoc-gui/enum-variants.goml @@ -3,3 +3,8 @@ goto: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" assert-css: (".variants > .variant", {"margin": "0px 0px 12px"}) assert-css: (".variants > .docblock", {"margin": "0px 0px 32px 24px"}) + +assert-css: ( + "details.non-exhaustive > summary", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index dea154c9319..1340511d472 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -76,6 +76,7 @@ impl AsRef<str> for Foo { /// /// # title! #[doc(alias = "ThisIsAnAlias")] +#[non_exhaustive] pub enum WhoLetTheDogOut { /// Woof! Woof, diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml index b7d10723767..45bb8daf1f2 100644 --- a/src/test/rustdoc-gui/toggle-docs.goml +++ b/src/test/rustdoc-gui/toggle-docs.goml @@ -7,6 +7,10 @@ wait-for: 50 // This is now collapsed so there shouldn't be the "open" attribute on details. assert-attribute-false: ("#main-content > details.top-doc", {"open": ""}) assert-text: ("#toggle-all-docs", "[+]") +assert-css: ( + "#main-content > details.top-doc > summary", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) click: "#toggle-all-docs" // Not collapsed anymore so the "open" attribute should be back. wait-for-attribute: ("#main-content > details.top-doc", {"open": ""}) diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 55154803098..94cf7b94241 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -77,6 +77,7 @@ -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) -Z ls=val -- list the symbols defined by a library crate (default: no) -Z macro-backtrace=val -- show macro backtraces (default: no) + -Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no) -Z merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name -Z meta-stats=val -- gather metadata statistics (default: no) -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) diff --git a/src/test/ui/async-await/async-await-let-else.drop-tracking.stderr b/src/test/ui/async-await/async-await-let-else.drop-tracking.stderr index 3be7f370da3..616623ee077 100644 --- a/src/test/ui/async-await/async-await-let-else.drop-tracking.stderr +++ b/src/test/ui/async-await/async-await-let-else.drop-tracking.stderr @@ -40,7 +40,7 @@ LL | async fn bar2<T>(_: T) -> ! { LL | | panic!() LL | | } | |_^ - = note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()` + = note: required because it captures the following types: `&mut Context<'_>`, `Option<bool>`, `impl Future<Output = !>`, `()` note: required because it's used within this `async fn` body --> $DIR/async-await-let-else.rs:21:32 | diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.rs b/src/test/ui/async-await/in-trait/return-type-suggestion.rs new file mode 100644 index 00000000000..3446761d119 --- /dev/null +++ b/src/test/ui/async-await/in-trait/return-type-suggestion.rs @@ -0,0 +1,14 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait A { + async fn e() { + Ok(()) + //~^ ERROR mismatched types + //~| HELP consider using a semicolon here + } +} + +fn main() {} diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.stderr b/src/test/ui/async-await/in-trait/return-type-suggestion.stderr new file mode 100644 index 00000000000..5a9b15e54a0 --- /dev/null +++ b/src/test/ui/async-await/in-trait/return-type-suggestion.stderr @@ -0,0 +1,23 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/return-type-suggestion.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/return-type-suggestion.rs:8:9 + | +LL | Ok(()) + | ^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found enum `Result` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/issue-68112.drop_tracking.stderr b/src/test/ui/async-await/issue-68112.drop_tracking.stderr index f2802698fd5..1c90bedae79 100644 --- a/src/test/ui/async-await/issue-68112.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-68112.drop_tracking.stderr @@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC | LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>` + = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>` note: required because it's used within this `async` block --> $DIR/issue-68112.rs:60:20 | diff --git a/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr b/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr index 38eb85b302f..e09ae7fedd8 100644 --- a/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr +++ b/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr @@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC | LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>` + = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>` note: required because it's used within this `async` block --> $DIR/issue-68112.rs:60:20 | diff --git a/src/test/ui/async-await/issue-69446-fnmut-capture.stderr b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr index 3d2b0402bc5..e6ad2f0d444 100644 --- a/src/test/ui/async-await/issue-69446-fnmut-capture.stderr +++ b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr @@ -14,6 +14,9 @@ LL | | }); | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape + = note: requirement occurs because of a mutable reference to `Context<'_>` + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 721234aa4a7..a8fd97cde8f 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -18,7 +18,7 @@ LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { | ___________________________________________________________________^ LL | | } | |_^ - = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()` + = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = ()>`, `()` note: required because it's used within this `async` block --> $DIR/issue-70935-complex-spans.rs:16:5 | diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr index 17b4ef7bdc6..25876d50840 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr @@ -11,7 +11,7 @@ LL | async fn foo() { | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` - = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `()`, `impl Future<Output = ()>` + = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `()`, `impl Future<Output = ()>` note: required because it's used within this `async fn` body --> $DIR/partial-drop-partial-reinit.rs:31:16 | diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr index 34d8a159f10..dba2a620779 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr @@ -11,7 +11,7 @@ LL | async fn foo() { | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` - = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()` + = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `impl Future<Output = ()>`, `()` note: required because it's used within this `async fn` body --> $DIR/partial-drop-partial-reinit.rs:31:16 | diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.rs b/src/test/ui/auto-traits/bad-generics-on-dyn.rs new file mode 100644 index 00000000000..3f8ac14c72d --- /dev/null +++ b/src/test/ui/auto-traits/bad-generics-on-dyn.rs @@ -0,0 +1,11 @@ +#![feature(auto_traits)] + +auto trait Trait1<'a> {} +//~^ ERROR auto traits cannot have generic parameters + +fn f<'a>(x: &dyn Trait1<'a>) +{} + +fn main() { + f(&1); +} diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.stderr b/src/test/ui/auto-traits/bad-generics-on-dyn.stderr new file mode 100644 index 00000000000..ade69ced606 --- /dev/null +++ b/src/test/ui/auto-traits/bad-generics-on-dyn.stderr @@ -0,0 +1,11 @@ +error[E0567]: auto traits cannot have generic parameters + --> $DIR/bad-generics-on-dyn.rs:3:18 + | +LL | auto trait Trait1<'a> {} + | ------^^^^ help: remove the parameters + | | + | auto trait cannot have generic parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0567`. diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs new file mode 100644 index 00000000000..6093fc70b16 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs @@ -0,0 +1,22 @@ +#![feature(generic_const_exprs, generic_arg_infer)] +#![allow(incomplete_features)] + +// minimized repro for #105205 +// +// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a +// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter +// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed` +// obligation into `WellFormed(Expr(L - 1))` + +fn foo<const N: usize, const M: usize>(_: [(); N + 1 + M]) {} + +fn ice<const L: usize>() +where + [(); (L - 1) + 1 + L]:, +{ + foo::<_, L>([(); L + 1 + L]); + //~^ ERROR: mismatched types + //~^^ ERROR: unconstrained generic constant +} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr new file mode 100644 index 00000000000..da5194696e6 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/wf_obligation.rs:17:17 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L` + | + = note: expected constant `N + 1 + M` + found constant `L + 1 + L` + +error: unconstrained generic constant + --> $DIR/wf_obligation.rs:17:22 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/nested-return-type4.rs b/src/test/ui/impl-trait/nested-return-type4.rs new file mode 100644 index 00000000000..cec70bb1a0d --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type4.rs @@ -0,0 +1,8 @@ +// edition: 2021 + +fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { + async move { let _s = s; } + //~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/src/test/ui/impl-trait/nested-return-type4.stderr b/src/test/ui/impl-trait/nested-return-type4.stderr new file mode 100644 index 00000000000..e761a60e79c --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type4.stderr @@ -0,0 +1,20 @@ +error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds + --> $DIR/nested-return-type4.rs:4:5 + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { + | -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here +LL | async move { let _s = s; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's { + | ++++ +help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/issues/issue-105330.rs b/src/test/ui/issues/issue-105330.rs new file mode 100644 index 00000000000..86e45f10b0e --- /dev/null +++ b/src/test/ui/issues/issue-105330.rs @@ -0,0 +1,21 @@ +pub trait TraitWAssocConst { + const A: usize; +} +pub struct Demo {} + +impl TraitWAssocConst for impl Demo { //~ ERROR E0404 + //~^ ERROR E0562 + pubconst A: str = 32; //~ ERROR expected one of +} + +fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658 + foo::<Demo>()(); //~ ERROR E0271 + //~^ ERROR E0618 + //~| ERROR E0277 +} + +fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131 + //~^ ERROR E0658 + foo::<Demo>(); //~ ERROR E0277 + //~^ ERROR E0271 +} diff --git a/src/test/ui/issues/issue-105330.stderr b/src/test/ui/issues/issue-105330.stderr new file mode 100644 index 00000000000..92f2ccb6544 --- /dev/null +++ b/src/test/ui/issues/issue-105330.stderr @@ -0,0 +1,109 @@ +error: expected one of `!` or `::`, found `A` + --> $DIR/issue-105330.rs:8:14 + | +LL | impl TraitWAssocConst for impl Demo { + | - while parsing this item list starting here +LL | +LL | pubconst A: str = 32; + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here + +error[E0404]: expected trait, found struct `Demo` + --> $DIR/issue-105330.rs:6:32 + | +LL | impl TraitWAssocConst for impl Demo { + | ^^^^ not a trait + +error[E0658]: associated const equality is incomplete + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ^^^^ + | + = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0658]: associated const equality is incomplete + --> $DIR/issue-105330.rs:17:29 + | +LL | fn main<A: TraitWAssocConst<A=32>>() { + | ^^^^ + | + = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-105330.rs:6:27 + | +LL | impl TraitWAssocConst for impl Demo { + | ^^^^^^^^^ + +error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied + --> $DIR/issue-105330.rs:12:11 + | +LL | foo::<Demo>()(); + | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:11 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32` + --> $DIR/issue-105330.rs:12:11 + | +LL | foo::<Demo>()(); + | ^^^^ types differ + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ^^^^ required by this bound in `foo` + +error[E0618]: expected function, found `()` + --> $DIR/issue-105330.rs:12:5 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ----------------------------------- `foo::<Demo>` defined here returns `()` +LL | foo::<Demo>()(); + | ^^^^^^^^^^^^^-- + | | + | call expression requires function + +error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied + --> $DIR/issue-105330.rs:19:11 + | +LL | foo::<Demo>(); + | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:11 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32` + --> $DIR/issue-105330.rs:19:11 + | +LL | foo::<Demo>(); + | ^^^^ types differ + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo<A: TraitWAssocConst<A=32>>() { + | ^^^^ required by this bound in `foo` + +error[E0131]: `main` function is not allowed to have generic parameters + --> $DIR/issue-105330.rs:17:8 + | +LL | fn main<A: TraitWAssocConst<A=32>>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658. +For more information about an error, try `rustc --explain E0131`. diff --git a/src/test/ui/lint/issue-104897.rs b/src/test/ui/lint/issue-104897.rs new file mode 100644 index 00000000000..5fbc658f155 --- /dev/null +++ b/src/test/ui/lint/issue-104897.rs @@ -0,0 +1,6 @@ +// error-pattern: this file contains an unclosed delimiter +// error-pattern: this file contains an unclosed delimiter +// error-pattern: this file contains an unclosed delimiter +// error-pattern: format argument must be a string literal + +fn f(){(print!(á diff --git a/src/test/ui/lint/issue-104897.stderr b/src/test/ui/lint/issue-104897.stderr new file mode 100644 index 00000000000..817a93c2f3b --- /dev/null +++ b/src/test/ui/lint/issue-104897.stderr @@ -0,0 +1,43 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-104897.rs:6:18 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-104897.rs:6:18 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-104897.rs:6:18 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: format argument must be a string literal + --> $DIR/issue-104897.rs:6:16 + | +LL | fn f(){(print!(á + | ^ + | +help: you might be missing a string literal to format with + | +LL | fn f(){(print!("{}", á + | +++++ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/macros/syntax-error-recovery.stderr b/src/test/ui/macros/syntax-error-recovery.stderr index c153b3b910b..c42ee9b295e 100644 --- a/src/test/ui/macros/syntax-error-recovery.stderr +++ b/src/test/ui/macros/syntax-error-recovery.stderr @@ -7,6 +7,7 @@ LL | $token $($inner)? = $value, LL | values!(STRING(1) as (String) => cfg(test),); | -------------------------------------------- in this macro invocation | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) error: macro expansion ignores token `(String)` and any following diff --git a/src/test/ui/maximal_mir_to_hir_coverage.rs b/src/test/ui/maximal_mir_to_hir_coverage.rs new file mode 100644 index 00000000000..5ca54633f21 --- /dev/null +++ b/src/test/ui/maximal_mir_to_hir_coverage.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmaximal-hir-to-mir-coverage +// run-pass + +// Just making sure this flag is accepted and doesn't crash the compiler + +fn main() { + let x = 1; + let y = x + 1; + println!("{y}"); +} diff --git a/src/test/ui/parser/issue-101477-enum.stderr b/src/test/ui/parser/issue-101477-enum.stderr index bffc881bdc8..1edca391e8f 100644 --- a/src/test/ui/parser/issue-101477-enum.stderr +++ b/src/test/ui/parser/issue-101477-enum.stderr @@ -3,6 +3,8 @@ error: unexpected `==` | LL | B == 2 | ^^ help: try using `=` instead + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: expected item, found `==` --> $DIR/issue-101477-enum.rs:6:7 diff --git a/src/test/ui/parser/issue-103869.rs b/src/test/ui/parser/issue-103869.rs new file mode 100644 index 00000000000..28c442bdd63 --- /dev/null +++ b/src/test/ui/parser/issue-103869.rs @@ -0,0 +1,9 @@ +enum VecOrMap{ + vec: Vec<usize>, + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:` + //~| HELP: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + //~| ERROR expected item, found `:` + map: HashMap<String,usize> +} + +fn main() {} diff --git a/src/test/ui/parser/issue-103869.stderr b/src/test/ui/parser/issue-103869.stderr new file mode 100644 index 00000000000..0b8cd919a9d --- /dev/null +++ b/src/test/ui/parser/issue-103869.stderr @@ -0,0 +1,16 @@ +error: expected one of `(`, `,`, `=`, `{`, or `}`, found `:` + --> $DIR/issue-103869.rs:2:8 + | +LL | vec: Vec<usize>, + | ^ expected one of `(`, `,`, `=`, `{`, or `}` + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: expected item, found `:` + --> $DIR/issue-103869.rs:2:8 + | +LL | vec: Vec<usize>, + | ^ expected item + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/macro/issue-37113.stderr b/src/test/ui/parser/macro/issue-37113.stderr index b1f8674fbdf..da9e743a0b4 100644 --- a/src/test/ui/parser/macro/issue-37113.stderr +++ b/src/test/ui/parser/macro/issue-37113.stderr @@ -9,6 +9,7 @@ LL | $( $t, )* LL | test_macro!(String,); | -------------------- in this macro invocation | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.rs b/src/test/ui/regions/closure-in-projection-issue-97405.rs index e567d5c2723..88b1c139651 100644 --- a/src/test/ui/regions/closure-in-projection-issue-97405.rs +++ b/src/test/ui/regions/closure-in-projection-issue-97405.rs @@ -22,11 +22,11 @@ fn good_generic_fn<T>() { // This should fail because `T` ends up in the upvars of the closure. fn bad_generic_fn<T: Copy>(t: T) { assert_static(opaque(async move { t; }).next()); - //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + //~^ ERROR the parameter type `T` may not live long enough assert_static(opaque(move || { t; }).next()); //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough assert_static(opaque(opaque(async move { t; }).next()).next()); - //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + //~^ ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.stderr b/src/test/ui/regions/closure-in-projection-issue-97405.stderr index c08f1059ebf..907964aaf37 100644 --- a/src/test/ui/regions/closure-in-projection-issue-97405.stderr +++ b/src/test/ui/regions/closure-in-projection-issue-97405.stderr @@ -1,11 +1,13 @@ -error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough +error[E0310]: the parameter type `T` may not live long enough --> $DIR/closure-in-projection-issue-97405.rs:24:5 | LL | assert_static(opaque(async move { t; }).next()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | - = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... - = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds +help: consider adding an explicit lifetime bound... + | +LL | fn bad_generic_fn<T: Copy + 'static>(t: T) { + | +++++++++ error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough --> $DIR/closure-in-projection-issue-97405.rs:26:5 @@ -16,14 +18,16 @@ LL | assert_static(opaque(move || { t; }).next()); = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds -error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough +error[E0310]: the parameter type `T` may not live long enough --> $DIR/closure-in-projection-issue-97405.rs:28:5 | LL | assert_static(opaque(opaque(async move { t; }).next()).next()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | - = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... - = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds +help: consider adding an explicit lifetime bound... + | +LL | fn bad_generic_fn<T: Copy + 'static>(t: T) { + | +++++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/structs/struct-fn-in-definition.rs b/src/test/ui/structs/struct-fn-in-definition.rs index 5ae1b727dc7..7f48f55fec9 100644 --- a/src/test/ui/structs/struct-fn-in-definition.rs +++ b/src/test/ui/structs/struct-fn-in-definition.rs @@ -28,6 +28,7 @@ enum E { //~^ ERROR functions are not allowed in enum definitions //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + //~| HELP enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` } fn main() {} diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr index 472365c6ed7..439c86ec22b 100644 --- a/src/test/ui/structs/struct-fn-in-definition.stderr +++ b/src/test/ui/structs/struct-fn-in-definition.stderr @@ -33,6 +33,7 @@ LL | fn foo() {} | = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/assoc-const-as-fn.stderr b/src/test/ui/suggestions/assoc-const-as-fn.stderr index fa740687858..3b6e947c59f 100644 --- a/src/test/ui/suggestions/assoc-const-as-fn.stderr +++ b/src/test/ui/suggestions/assoc-const-as-fn.stderr @@ -1,8 +1,10 @@ error[E0277]: the trait bound `T: GlUniformScalar` is not satisfied - --> $DIR/assoc-const-as-fn.rs:14:5 + --> $DIR/assoc-const-as-fn.rs:14:40 | LL | <T as GlUniformScalar>::FACTORY(1, value); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `GlUniformScalar` is not implemented for `T` + | ------------------------------- ^^^^^ the trait `GlUniformScalar` is not implemented for `T` + | | + | required by a bound introduced by this call | help: consider further restricting this bound | diff --git a/src/test/ui/suggestions/try-removing-the-field.rs b/src/test/ui/suggestions/try-removing-the-field.rs index 9d0573ca255..1b7289b229b 100644 --- a/src/test/ui/suggestions/try-removing-the-field.rs +++ b/src/test/ui/suggestions/try-removing-the-field.rs @@ -14,4 +14,19 @@ fn use_foo(x: Foo) -> i32 { return foo; } +// issue #105028, suggest removing the field only for shorthand +fn use_match(x: Foo) { + match x { + Foo { foo: unused, .. } => { //~ WARNING unused variable + //~| help: if this is intentional, prefix it with an underscore + } + } + + match x { + Foo { foo, .. } => { //~ WARNING unused variable + //~| help: try removing the field + } + } +} + fn main() {} diff --git a/src/test/ui/suggestions/try-removing-the-field.stderr b/src/test/ui/suggestions/try-removing-the-field.stderr index 448a2c3d2ec..7a6013d4a6e 100644 --- a/src/test/ui/suggestions/try-removing-the-field.stderr +++ b/src/test/ui/suggestions/try-removing-the-field.stderr @@ -8,5 +8,19 @@ LL | let Foo { foo, bar, .. } = x; | = note: `#[warn(unused_variables)]` on by default -warning: 1 warning emitted +warning: unused variable: `unused` + --> $DIR/try-removing-the-field.rs:20:20 + | +LL | Foo { foo: unused, .. } => { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` + +warning: unused variable: `foo` + --> $DIR/try-removing-the-field.rs:26:15 + | +LL | Foo { foo, .. } => { + | ^^^- + | | + | help: try removing the field + +warning: 3 warnings emitted diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs new file mode 100644 index 00000000000..dcdbd022873 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs @@ -0,0 +1,38 @@ +trait Trait<T> { + fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a; +} + +impl Trait<()> for () { + fn foo<'a, K>(self, _: (), _: K) where { //~ ERROR E0195 + todo!(); + } +} + +struct State; + +trait Foo<T> { + fn foo<'a>(&self, state: &'a State) -> &'a T + where + T: 'a; +} + +impl<F, T> Foo<T> for F +where + F: Fn(&State) -> &T, +{ + fn foo<'a>(&self, state: &'a State) -> &'a T { //~ ERROR E0195 + self(state) + } +} + +trait Bar { + fn foo<'a>(&'a self) {} +} + +impl Bar for () { + fn foo<'a: 'a>(&'a self) {} //~ ERROR E0195 +} + +fn main() { + ().foo((), ()); +} diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr new file mode 100644 index 00000000000..e26cb22163f --- /dev/null +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr @@ -0,0 +1,36 @@ +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:6:11 + | +LL | fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a; + | ------- -- -- this bound might be missing in the impl + | | | + | | this bound might be missing in the impl + | lifetimes in impl do not match this method in trait +... +LL | fn foo<'a, K>(self, _: (), _: K) where { + | ^^^^^^^ lifetimes do not match method in trait + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11 + | +LL | fn foo<'a>(&self, state: &'a State) -> &'a T + | ---- lifetimes in impl do not match this method in trait +LL | where +LL | T: 'a; + | -- this bound might be missing in the impl +... +LL | fn foo<'a>(&self, state: &'a State) -> &'a T { + | ^^^^ lifetimes do not match method in trait + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11 + | +LL | fn foo<'a>(&'a self) {} + | ---- lifetimes in impl do not match this method in trait +... +LL | fn foo<'a: 'a>(&'a self) {} + | ^^^^^^^^ lifetimes do not match method in trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0195`. diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs new file mode 100644 index 00000000000..fb56b394493 --- /dev/null +++ b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs @@ -0,0 +1,4 @@ +fn main() { + let page_size = page_size::get(); + //~^ ERROR failed to resolve: use of undeclared crate or module `page_size` +} diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr new file mode 100644 index 00000000000..b01e30be54d --- /dev/null +++ b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `page_size` + --> $DIR/path-to-method-sugg-unresolved-expr.rs:2:21 + | +LL | let page_size = page_size::get(); + | ^^^^^^^^^ use of undeclared crate or module `page_size` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml new file mode 100644 index 00000000000..d0820cfc2a0 --- /dev/null +++ b/src/tools/collect-license-metadata/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "collect-license-metadata" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.65" +serde = { version = "1.0.147", features = ["derive"] } +serde_json = "1.0.85" +spdx-rs = "0.5.1" diff --git a/src/tools/collect-license-metadata/src/licenses.rs b/src/tools/collect-license-metadata/src/licenses.rs new file mode 100644 index 00000000000..1c95b1bc8e9 --- /dev/null +++ b/src/tools/collect-license-metadata/src/licenses.rs @@ -0,0 +1,65 @@ +use std::collections::HashMap; + +const COPYRIGHT_PREFIXES: &[&str] = &["SPDX-FileCopyrightText:", "Copyright", "(c)", "(C)", "©"]; + +pub(crate) struct LicensesInterner { + by_id: Vec<License>, + by_struct: HashMap<License, usize>, +} + +impl LicensesInterner { + pub(crate) fn new() -> Self { + LicensesInterner { by_id: Vec::new(), by_struct: HashMap::new() } + } + + pub(crate) fn intern(&mut self, mut license: License) -> LicenseId { + license.simplify(); + if let Some(id) = self.by_struct.get(&license) { + LicenseId(*id) + } else { + let id = self.by_id.len(); + self.by_id.push(license.clone()); + self.by_struct.insert(license, id); + LicenseId(id) + } + } + + pub(crate) fn resolve(&self, id: LicenseId) -> &License { + &self.by_id[id.0] + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)] +#[serde(transparent)] +pub(crate) struct LicenseId(usize); + +#[derive(Clone, Hash, PartialEq, Eq, serde::Serialize)] +pub(crate) struct License { + pub(crate) spdx: String, + pub(crate) copyright: Vec<String>, +} + +impl License { + fn simplify(&mut self) { + self.remove_copyright_prefixes(); + self.copyright.sort(); + self.copyright.dedup(); + } + + fn remove_copyright_prefixes(&mut self) { + for copyright in &mut self.copyright { + let mut stripped = copyright.trim(); + let mut previous_stripped; + loop { + previous_stripped = stripped; + for pattern in COPYRIGHT_PREFIXES { + stripped = stripped.trim_start_matches(pattern).trim_start(); + } + if stripped == previous_stripped { + break; + } + } + *copyright = stripped.into(); + } + } +} diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs new file mode 100644 index 00000000000..ca2a6f4b8c8 --- /dev/null +++ b/src/tools/collect-license-metadata/src/main.rs @@ -0,0 +1,30 @@ +mod licenses; +mod path_tree; +mod reuse; + +use crate::licenses::LicensesInterner; +use anyhow::Error; +use std::path::PathBuf; + +fn main() -> Result<(), Error> { + let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into(); + let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into(); + + let mut interner = LicensesInterner::new(); + let paths = crate::reuse::collect(&reuse_exe, &mut interner)?; + + let mut tree = crate::path_tree::build(paths); + tree.simplify(); + + if let Some(parent) = dest.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write( + &dest, + &serde_json::to_vec_pretty(&serde_json::json!({ + "files": crate::path_tree::expand_interned_licenses(tree, &interner), + }))?, + )?; + + Ok(()) +} diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs new file mode 100644 index 00000000000..133ff683737 --- /dev/null +++ b/src/tools/collect-license-metadata/src/path_tree.rs @@ -0,0 +1,294 @@ +//! Tools like REUSE output per-file licensing information, but we need to condense it in the +//! minimum amount of data that still represents the same licensing metadata. This module is +//! responsible for that, by turning the list of paths into a tree and executing simplification +//! passes over the tree to remove redundant information. + +use crate::licenses::{License, LicenseId, LicensesInterner}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +#[derive(serde::Serialize)] +#[serde(rename_all = "kebab-case", tag = "type")] +pub(crate) enum Node<L> { + Root { childs: Vec<Node<L>> }, + Directory { name: PathBuf, childs: Vec<Node<L>>, license: Option<L> }, + File { name: PathBuf, license: L }, + FileGroup { names: Vec<PathBuf>, license: L }, + Empty, +} + +impl Node<LicenseId> { + pub(crate) fn simplify(&mut self) { + self.merge_directories(); + self.collapse_in_licensed_directories(); + self.merge_directory_licenses(); + self.merge_file_groups(); + self.remove_empty(); + } + + /// Initially, the build() function constructs a list of separate paths from the file + /// system root down to each file, like so: + /// + /// ```text + /// ┌─► ./ ──► compiler/ ──► rustc/ ──► src/ ──► main.rs + /// │ + /// <root> ─┼─► ./ ──► compiler/ ──► rustc/ ──► Cargo.toml + /// │ + /// └─► ./ ──► library/ ───► std/ ──► Cargo.toml + /// ``` + /// + /// This pass is responsible for turning that into a proper directory tree: + /// + /// ```text + /// ┌─► compiler/ ──► rustc/ ──┬─► src/ ──► main.rs + /// │ │ + /// <root> ──► ./ ──┤ └─► Cargo.toml + /// │ + /// └─► library/ ───► std/ ──► Cargo.toml + /// ``` + fn merge_directories(&mut self) { + match self { + Node::Root { childs } | Node::Directory { childs, license: None, .. } => { + let mut directories = BTreeMap::new(); + let mut files = Vec::new(); + + for child in childs.drain(..) { + match child { + Node::Directory { name, mut childs, license: None } => { + directories.entry(name).or_insert_with(Vec::new).append(&mut childs); + } + file @ Node::File { .. } => { + files.push(file); + } + Node::Empty => {} + Node::Root { .. } => { + panic!("can't have a root inside another element"); + } + Node::FileGroup { .. } => { + panic!("FileGroup should not be present at this stage"); + } + Node::Directory { license: Some(_), .. } => { + panic!("license should not be set at this stage"); + } + } + } + + childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory { + name, + childs, + license: None, + })); + childs.append(&mut files); + + for child in &mut *childs { + child.merge_directories(); + } + } + Node::Empty => {} + Node::File { .. } => {} + Node::FileGroup { .. } => { + panic!("FileGroup should not be present at this stage"); + } + Node::Directory { license: Some(_), .. } => { + panic!("license should not be set at this stage"); + } + } + } + + /// In our codebase, most files in a directory have the same license as the other files in that + /// same directory, so it's redundant to store licensing metadata for all the files. Instead, + /// we can add a license for a whole directory, and only record the exceptions to a directory + /// licensing metadata. + /// + /// We cannot instead record only the difference to Rust's standard licensing, as the majority + /// of the files in our repository are *not* licensed under Rust's standard licensing due to + /// our inclusion of LLVM. + fn collapse_in_licensed_directories(&mut self) { + match self { + Node::Directory { childs, license, .. } => { + for child in &mut *childs { + child.collapse_in_licensed_directories(); + } + + let mut licenses_count = BTreeMap::new(); + for child in &*childs { + let Some(license) = child.license() else { continue }; + *licenses_count.entry(license).or_insert(0) += 1; + } + + let most_popular_license = licenses_count + .into_iter() + .max_by_key(|(_, count)| *count) + .map(|(license, _)| license); + + if let Some(most_popular_license) = most_popular_license { + childs.retain(|child| child.license() != Some(most_popular_license)); + *license = Some(most_popular_license); + } + } + Node::Root { childs } => { + for child in &mut *childs { + child.collapse_in_licensed_directories(); + } + } + Node::File { .. } => {} + Node::FileGroup { .. } => {} + Node::Empty => {} + } + } + + /// Reduce the depth of the tree by merging subdirectories with the same license as their + /// parent directory into their parent, and adjusting the paths of the childs accordingly. + fn merge_directory_licenses(&mut self) { + match self { + Node::Root { childs } => { + for child in &mut *childs { + child.merge_directory_licenses(); + } + } + Node::Directory { childs, license, .. } => { + let mut to_add = Vec::new(); + for child in &mut *childs { + child.merge_directory_licenses(); + + let Node::Directory { + name: child_name, + childs: child_childs, + license: child_license, + } = child else { continue }; + + if child_license != license { + continue; + } + for mut child_child in child_childs.drain(..) { + match &mut child_child { + Node::Root { .. } => { + panic!("can't have a root inside another element"); + } + Node::FileGroup { .. } => { + panic!("FileGroup should not be present at this stage"); + } + Node::Directory { name: child_child_name, .. } => { + *child_child_name = child_name.join(&child_child_name); + } + Node::File { name: child_child_name, .. } => { + *child_child_name = child_name.join(&child_child_name); + } + Node::Empty => {} + } + to_add.push(child_child); + } + + *child = Node::Empty; + } + childs.append(&mut to_add); + } + Node::Empty => {} + Node::File { .. } => {} + Node::FileGroup { .. } => {} + } + } + + /// This pass groups multiple files in a directory with the same license into a single + /// "FileGroup", so that the license of all those files can be reported as a group. + /// + /// Crucially this pass runs after collapse_in_licensed_directories, so the most common license + /// will already be marked as the directory's license and won't be turned into a group. + fn merge_file_groups(&mut self) { + match self { + Node::Root { childs } | Node::Directory { childs, .. } => { + let mut grouped = BTreeMap::new(); + + for child in &mut *childs { + child.merge_file_groups(); + if let Node::File { name, license } = child { + grouped.entry(*license).or_insert_with(Vec::new).push(name.clone()); + *child = Node::Empty; + } + } + + for (license, mut names) in grouped.into_iter() { + if names.len() == 1 { + childs.push(Node::File { license, name: names.pop().unwrap() }); + } else { + childs.push(Node::FileGroup { license, names }); + } + } + } + Node::File { .. } => {} + Node::FileGroup { .. } => panic!("FileGroup should not be present at this stage"), + Node::Empty => {} + } + } + + /// Some nodes were replaced with Node::Empty to mark them for deletion. As the last step, make + /// sure to remove them from the tree. + fn remove_empty(&mut self) { + match self { + Node::Root { childs } | Node::Directory { childs, .. } => { + for child in &mut *childs { + child.remove_empty(); + } + childs.retain(|child| !matches!(child, Node::Empty)); + } + Node::FileGroup { .. } => {} + Node::File { .. } => {} + Node::Empty => {} + } + } + + fn license(&self) -> Option<LicenseId> { + match self { + Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => { + Some(*license) + } + Node::File { license, .. } => Some(*license), + _ => None, + } + } +} + +pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> { + let mut childs = Vec::new(); + + // Ensure reproducibility of all future steps. + input.sort(); + + for (path, license) in input { + let mut node = Node::File { name: path.file_name().unwrap().into(), license }; + for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() { + node = Node::Directory { + name: component.as_os_str().into(), + childs: vec![node], + license: None, + }; + } + + childs.push(node); + } + + Node::Root { childs } +} + +/// Convert a `Node<LicenseId>` into a `Node<&License>`, expanding all interned license IDs with a +/// reference to the actual license metadata. +pub(crate) fn expand_interned_licenses( + node: Node<LicenseId>, + interner: &LicensesInterner, +) -> Node<&License> { + match node { + Node::Root { childs } => Node::Root { + childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(), + }, + Node::Directory { name, childs, license } => Node::Directory { + childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(), + license: license.map(|license| interner.resolve(license)), + name, + }, + Node::File { name, license } => Node::File { name, license: interner.resolve(license) }, + Node::FileGroup { names, license } => { + Node::FileGroup { names, license: interner.resolve(license) } + } + Node::Empty => Node::Empty, + } +} diff --git a/src/tools/collect-license-metadata/src/reuse.rs b/src/tools/collect-license-metadata/src/reuse.rs new file mode 100644 index 00000000000..d6b3772ba51 --- /dev/null +++ b/src/tools/collect-license-metadata/src/reuse.rs @@ -0,0 +1,49 @@ +use crate::licenses::{License, LicenseId, LicensesInterner}; +use anyhow::Error; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::time::Instant; + +pub(crate) fn collect( + reuse_exe: &Path, + interner: &mut LicensesInterner, +) -> Result<Vec<(PathBuf, LicenseId)>, Error> { + eprintln!("gathering license information from REUSE"); + let start = Instant::now(); + let raw = &obtain_spdx_document(reuse_exe)?; + eprintln!("finished gathering the license information from REUSE in {:.2?}", start.elapsed()); + + let document = spdx_rs::parsers::spdx_from_tag_value(&raw)?; + + let mut result = Vec::new(); + for file in document.file_information { + let license = interner.intern(License { + spdx: file.concluded_license.to_string(), + copyright: file.copyright_text.split('\n').map(|s| s.into()).collect(), + }); + + result.push((file.file_name.into(), license)); + } + + Ok(result) +} + +fn obtain_spdx_document(reuse_exe: &Path) -> Result<String, Error> { + let output = Command::new(reuse_exe) + .args(&["spdx", "--add-license-concluded", "--creator-person=bors"]) + .stdout(Stdio::piped()) + .spawn()? + .wait_with_output()?; + + if !output.status.success() { + eprintln!(); + eprintln!("Note that Rust requires some REUSE features that might not be present in the"); + eprintln!("release you're using. Make sure your REUSE release includes these PRs:"); + eprintln!(); + eprintln!(" - https://github.com/fsfe/reuse-tool/pull/623"); + eprintln!(); + anyhow::bail!("collecting licensing information with REUSE failed"); + } + + Ok(String::from_utf8(output.stdout)?) +} diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml new file mode 100644 index 00000000000..899ef0f8a6c --- /dev/null +++ b/src/tools/generate-copyright/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "generate-copyright" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.65" +serde = { version = "1.0.147", features = ["derive"] } +serde_json = "1.0.85" diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs new file mode 100644 index 00000000000..d172c9e157b --- /dev/null +++ b/src/tools/generate-copyright/src/main.rs @@ -0,0 +1,94 @@ +use anyhow::Error; +use std::io::Write; +use std::path::PathBuf; + +fn main() -> Result<(), Error> { + let dest = env_path("DEST")?; + let license_metadata = env_path("LICENSE_METADATA")?; + + let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?; + + let mut buffer = Vec::new(); + render_recursive(&metadata.files, &mut buffer, 0)?; + + std::fs::write(&dest, &buffer)?; + + Ok(()) +} + +fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> { + let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>(); + + match node { + Node::Root { childs } => { + for child in childs { + render_recursive(child, buffer, depth)?; + } + } + Node::Directory { name, childs, license } => { + render_license(&prefix, std::iter::once(name), license, buffer)?; + if !childs.is_empty() { + writeln!(buffer, "{prefix}")?; + writeln!(buffer, "{prefix}*Exceptions:*")?; + for child in childs { + writeln!(buffer, "{prefix}")?; + render_recursive(child, buffer, depth + 1)?; + } + } + } + Node::FileGroup { names, license } => { + render_license(&prefix, names.iter(), license, buffer)?; + } + Node::File { name, license } => { + render_license(&prefix, std::iter::once(name), license, buffer)?; + } + } + + Ok(()) +} + +fn render_license<'a>( + prefix: &str, + names: impl Iterator<Item = &'a String>, + license: &License, + buffer: &mut Vec<u8>, +) -> Result<(), Error> { + for name in names { + writeln!(buffer, "{prefix}**`{name}`** ")?; + } + writeln!(buffer, "{prefix}License: `{}` ", license.spdx)?; + for (i, copyright) in license.copyright.iter().enumerate() { + let suffix = if i == license.copyright.len() - 1 { "" } else { " " }; + writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?; + } + + Ok(()) +} + +#[derive(serde::Deserialize)] +struct Metadata { + files: Node, +} + +#[derive(serde::Deserialize)] +#[serde(rename_all = "kebab-case", tag = "type")] +pub(crate) enum Node { + Root { childs: Vec<Node> }, + Directory { name: String, childs: Vec<Node>, license: License }, + File { name: String, license: License }, + FileGroup { names: Vec<String>, license: License }, +} + +#[derive(serde::Deserialize)] +struct License { + spdx: String, + copyright: Vec<String>, +} + +fn env_path(var: &str) -> Result<PathBuf, Error> { + if let Some(var) = std::env::var_os(var) { + Ok(var.into()) + } else { + anyhow::bail!("missing environment variable {var}") + } +} |