From: Matthias Krüger Date: Tue, 6 Dec 2022 12:27:43 +0000 (+0100) Subject: Rollup merge of #105310 - compiler-errors:issue-105288, r=eholk X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=61189b6ae3c5ccc8a38be18aad7ef75c253d7c28;hp=f4c76b193d54eeb88b2c966612679d733536efaf;p=rust.git Rollup merge of #105310 - compiler-errors:issue-105288, r=eholk Be more careful about unresolved exprs in suggestion Fixes #105288 --- diff --git a/Cargo.lock b/Cargo.lock index dae79e5bc26..150a70341f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,6 +581,7 @@ dependencies = [ "libc", "num-integer", "num-traits", + "serde", "time", "winapi", ] @@ -730,6 +731,16 @@ dependencies = [ "rustc-semver", ] +[[package]] +name = "collect-license-metadata" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "spdx-rs", +] + [[package]] name = "color-eyre" version = "0.6.2" @@ -1552,6 +1563,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "generate-copyright" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -2085,9 +2105,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" dependencies = [ "rustc-std-workspace-core", ] @@ -4864,6 +4884,35 @@ dependencies = [ "winapi", ] +[[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" @@ -4967,6 +5016,25 @@ version = "0.10.0" 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" @@ -5596,6 +5664,15 @@ version = "0.1.1" 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" 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::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 4260805f1dd..695ccec0b1c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -147,6 +147,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ), ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr( *capture_clause, + None, *closure_node_id, None, e.span, @@ -584,6 +585,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { pub(super) fn make_async_expr( &mut self, capture_clause: CaptureBy, + outer_hir_id: Option, closure_node_id: NodeId, ret_ty: Option>, span: Span, @@ -651,18 +653,20 @@ pub(super) fn make_async_expr( hir::ExprKind::Closure(c) }; - let parent_has_track_caller = self - .attrs - .values() - .find(|attrs| attrs.into_iter().find(|attr| attr.has_name(sym::track_caller)).is_some()) - .is_some(); - let unstable_span = - self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let hir_id = if parent_has_track_caller { - let generator_hir_id = self.lower_node_id(closure_node_id); + let track_caller = outer_hir_id + .and_then(|id| self.attrs.get(&id.local_id)) + .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); + if track_caller { + let unstable_span = self.mark_span_with_reason( + DesugaringKind::Async, + span, + self.allow_gen_future.clone(), + ); self.lower_attrs( - generator_hir_id, + hir_id, &[Attribute { kind: AttrKind::Normal(ptr::P(NormalAttr { item: AttrItem { @@ -677,10 +681,7 @@ pub(super) fn make_async_expr( span: unstable_span, }], ); - generator_hir_id - } else { - self.lower_node_id(closure_node_id) - }; + } let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; @@ -1019,6 +1020,9 @@ fn lower_expr_async_closure( let async_body = this.make_async_expr( capture_clause, + // FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]` + // can be applied on async closures as well. + None, inner_closure_id, async_ret_ty, body.span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f6275433fc5..9eda48e9329 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -253,8 +253,13 @@ fn lower_item_kind( // only cares about the input argument patterns in the function // declaration (decl), not the return types. let asyncness = header.asyncness; - let body_id = - this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); + let body_id = this.lower_maybe_async_body( + span, + hir_id, + &decl, + asyncness, + body.as_deref(), + ); let mut itctx = ImplTraitContext::Universal; let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { @@ -701,6 +706,7 @@ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<' fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); + self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -724,7 +730,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { let asyncness = sig.header.asyncness; let body_id = - self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body)); + self.lower_maybe_async_body(i.span, hir_id, &sig.decl, asyncness, Some(&body)); let (generics, sig) = self.lower_method_sig( generics, sig, @@ -759,7 +765,6 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"), }; - self.lower_attrs(hir_id, &i.attrs); let item = hir::TraitItem { owner_id: trait_item_def_id, ident: self.lower_ident(i.ident), @@ -798,6 +803,8 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); + let hir_id = self.lower_node_id(i.id); + self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { @@ -810,8 +817,13 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; - let body_id = - self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref()); + let body_id = self.lower_maybe_async_body( + i.span, + hir_id, + &sig.decl, + asyncness, + body.as_deref(), + ); let (generics, sig) = self.lower_method_sig( generics, sig, @@ -844,8 +856,6 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"), }; - let hir_id = self.lower_node_id(i.id); - self.lower_attrs(hir_id, &i.attrs); let item = hir::ImplItem { owner_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), @@ -978,6 +988,7 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi fn lower_maybe_async_body( &mut self, span: Span, + fn_id: hir::HirId, decl: &FnDecl, asyncness: Async, body: Option<&Block>, @@ -1128,6 +1139,7 @@ fn lower_maybe_async_body( let async_expr = this.make_async_expr( CaptureBy::Value, + Some(fn_id), closure_id, None, body.span, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 04e68b96455..3dfded2d930 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -240,7 +240,7 @@ fn align_offset( let align = ImmTy::from_uint(target_align, args[1].layout).into(); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - // We replace the entire entire function call with a "tail call". + // We replace the entire function call with a "tail call". // Note that this happens before the frame of the original function // is pushed on the stack. self.eval_fn_call( diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 79450fccfc4..e17d3e516a6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -676,6 +676,10 @@ pub fn push_stack_frame( return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); + // Clobber previous return place contents, nobody is supposed to be able to see them any more + // This also checks dereferenceable, but not align. We rely on all constructed places being + // sufficiently aligned (in particular we rely on `deref_operand` checking alignment). + self.write_uninit(return_place)?; // first push a stack frame so we have access to the local substs let pre_frame = Frame { body, 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 @@ fn finish(hasher: stable_hasher::StableHasher) -> Self { } } -impl_stable_hash_via_hash!(Fingerprint); +impl_stable_traits_for_trivial_type!(Fingerprint); impl Encodable for Fingerprint { #[inline] 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 @@ fn from_iter>(iter: T) -> Self { } } -impl, V: HashStable, CTX> HashStable for SortedMap { +impl + StableOrd, V: HashStable, CTX> HashStable for SortedMap { #[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 @@ fn hash(&self, hasher: &mut H) { self.items.hash(hasher) } } + impl HashStable for SortedIndexMultiMap where K: HashStable, V: HashStable, { 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 { 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 { /// 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 $crate::stable_hasher::HashStable for $t { #[inline] @@ -235,26 +263,28 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut $crate::stable_hasher::StableHas ::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 HashStable for ! { fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { @@ -444,6 +474,10 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { } } +// Safety: String comparison only depends on their contents and the +// contents are not changed by (de-)serialization. +unsafe impl StableOrd for String {} + impl ToStableHashKey for String { type KeyType = String; #[inline] @@ -459,6 +493,9 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { } } +// Safety: sort order of bools is not changed by (de-)serialization. +unsafe impl StableOrd for bool {} + impl HashStable for Option where T: HashStable, @@ -474,6 +511,9 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { } } +// Safety: the Option wrapper does not add instability to comparison. +unsafe impl StableOrd for Option {} + impl HashStable for Result where T1: HashStable, @@ -550,8 +590,8 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { } } -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 HashStable for ::std::collections::HashMap where @@ -584,27 +624,26 @@ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { impl HashStable for ::std::collections::BTreeMap where - K: ToStableHashKey, + K: HashStable + StableOrd, V: HashStable, { 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 HashStable for ::std::collections::BTreeSet where - K: ToStableHashKey, + K: HashStable + 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_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index f204d59d005..66906b331da 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1930,6 +1930,7 @@ pub fn associated_path_to_ty( adt_substs, ); let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs); + let ty = self.normalize_ty(span, ty); return Ok((ty, DefKind::AssocTy, assoc_ty_did)); } } 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, + #[label(where_label)] + pub where_span: Option, + #[label(bounds_label)] + pub bounds_span: Vec, 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_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, } - 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 { if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { @@ -87,6 +107,19 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { } r.super_visit_with(self) } + + #[instrument(level = "trace", skip(self), ret)] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + 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 visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { } } - 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/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1daca464b47..4f92477b5d8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -32,11 +32,13 @@ pub(crate) fn body_fn_sig(&self) -> Option> { } pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { + // This suggestion is incorrect for + // fn foo() -> bool { match () { () => true } || match () { () => true } } err.span_suggestion_short( span.shrink_to_hi(), "consider using a semicolon here", ";", - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6b5b5df9e2a..f75c8669fa1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -12,6 +12,7 @@ use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; @@ -801,6 +802,12 @@ pub fn create_global_ctxt<'tcx>( TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) }); + let ty::ResolverOutputs { + definitions, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = resolver_outputs; + let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(move || { TyCtxt::create_global_ctxt( @@ -808,7 +815,8 @@ pub fn create_global_ctxt<'tcx>( lint_store, arena, hir_arena, - resolver_outputs, + definitions, + untracked_resolutions, krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), @@ -820,7 +828,12 @@ pub fn create_global_ctxt<'tcx>( }) }); - QueryContext { gcx } + let mut qcx = QueryContext { gcx }; + qcx.enter(|tcx| { + tcx.feed_unit_query() + .resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering))) + }); + qcx } /// Runs the resolution, type-checking, region checking and other @@ -965,12 +978,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { pub fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, - outputs: &OutputFilenames, ) -> Box { info!("Pre-codegen\n{:?}", tcx.debug_stats()); - let (metadata, need_metadata_module) = - rustc_metadata::fs::encode_and_write_metadata(tcx, outputs); + let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx); let codegen = tcx.sess.time("codegen_crate", move || { codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) @@ -986,7 +997,7 @@ pub fn start_codegen<'tcx>( info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { + if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) { tcx.sess.emit_err(CantEmitMIR { error }); tcx.sess.abort_if_errors(); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index fc0b11183f7..f5ddd647b24 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -20,6 +20,7 @@ use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::rc::Rc; +use std::sync::Arc; /// Represent the result of a query. /// @@ -214,7 +215,7 @@ pub fn prepare_outputs(&self) -> Result<&Query> { pub fn global_ctxt(&'tcx self) -> Result<&Query>> { self.global_ctxt.compute(|| { let crate_name = self.crate_name()?.peek().clone(); - let outputs = self.prepare_outputs()?.peek().clone(); + let outputs = self.prepare_outputs()?.take(); let dep_graph = self.dep_graph()?.peek().clone(); let (krate, resolver, lint_store) = self.expansion()?.take(); Ok(passes::create_global_ctxt( @@ -235,7 +236,6 @@ pub fn global_ctxt(&'tcx self) -> Result<&Query>> { pub fn ongoing_codegen(&'tcx self) -> Result<&Query>> { self.ongoing_codegen.compute(|| { - let outputs = self.prepare_outputs()?; self.global_ctxt()?.peek_mut().enter(|tcx| { tcx.analysis(()).ok(); @@ -249,7 +249,7 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query>> { // Hook for UI tests. Self::check_for_rustc_errors_attr(tcx); - Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek())) + Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) }) }) } @@ -293,8 +293,10 @@ pub fn linker(&'tcx self) -> Result { let codegen_backend = self.codegen_backend().clone(); let dep_graph = self.dep_graph()?.peek().clone(); - let prepare_outputs = self.prepare_outputs()?.take(); - let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE)); + let (crate_hash, prepare_outputs) = self + .global_ctxt()? + .peek_mut() + .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone())); let ongoing_codegen = self.ongoing_codegen()?.take(); Ok(Linker { @@ -316,7 +318,7 @@ pub struct Linker { // compilation outputs dep_graph: DepGraph, - prepare_outputs: OutputFilenames, + prepare_outputs: Arc, crate_hash: Svh, ongoing_codegen: Box, } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 4047969724a..789d83a0dd0 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -364,10 +364,6 @@ macro_rules! passthrough { modifiers.eval_always.is_none(), "Query {name} cannot be both `feedable` and `eval_always`." ); - assert!( - modifiers.no_hash.is_none(), - "Query {name} cannot be both `feedable` and `no_hash`." - ); feedable_queries.extend(quote! { #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index c41ae8d55cd..4fa440c7ca6 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -6,7 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{CrateType, OutputFilenames, OutputType}; +use rustc_session::config::{CrateType, OutputType}; use rustc_session::output::filename_for_metadata; use rustc_session::Session; use tempfile::Builder as TempFileBuilder; @@ -38,10 +38,7 @@ pub fn emit_wrapper_file( out_filename } -pub fn encode_and_write_metadata( - tcx: TyCtxt<'_>, - outputs: &OutputFilenames, -) -> (EncodedMetadata, bool) { +pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -64,7 +61,8 @@ enum MetadataKind { .unwrap_or(MetadataKind::None); let crate_name = tcx.crate_name(LOCAL_CRATE); - let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs); + let out_filename = + filename_for_metadata(tcx.sess, crate_name.as_str(), tcx.output_filenames(())); // To avoid races with another rustc process scanning the output directory, // we need to write the file somewhere else and atomically move it to its // final destination, with an `fs::rename` call. In order for the rename to diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index e83106b1ee5..9aed75931bf 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -28,6 +28,7 @@ macro_rules! arena_types { [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, + [] resolver: rustc_data_structures::steal::Steal, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d6dea0e9f30..f2f2b22f52a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -33,7 +33,7 @@ } query resolver_for_lowering(_: ()) -> &'tcx Steal { - eval_always + feedable no_hash desc { "getting the resolver for lowering" } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c5683a9db94..c39d04d3819 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -81,7 +81,7 @@ use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::{ImplPolarity, ResolverOutputs, RvalueScopes}; +use super::{ImplPolarity, RvalueScopes}; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -1034,16 +1034,29 @@ pub struct FreeRegionInfo { /// This struct should only be created by `create_def`. #[derive(Copy, Clone)] -pub struct TyCtxtFeed<'tcx> { +pub struct TyCtxtFeed<'tcx, KEY: Copy> { pub tcx: TyCtxt<'tcx>, // Do not allow direct access, as downstream code must not mutate this field. - def_id: LocalDefId, + key: KEY, } -impl<'tcx> TyCtxtFeed<'tcx> { +impl<'tcx> TyCtxt<'tcx> { + pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> { + TyCtxtFeed { tcx: self, key: () } + } +} + +impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> { + #[inline(always)] + pub fn key(&self) -> KEY { + self.key + } +} + +impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { #[inline(always)] pub fn def_id(&self) -> LocalDefId { - self.def_id + self.key } } @@ -1099,7 +1112,6 @@ pub struct GlobalCtxt<'tcx> { /// Output of the resolver. pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt, - untracked_resolver_for_lowering: Steal, /// The entire crate as AST. This field serves as the input for the hir_crate query, /// which lowers it from AST to HIR. It must not be read or used by anything else. pub untracked_crate: Steal>, @@ -1262,7 +1274,8 @@ pub fn create_global_ctxt( lint_store: Lrc, arena: &'tcx WorkerLocal>, hir_arena: &'tcx WorkerLocal>, - resolver_outputs: ResolverOutputs, + definitions: Definitions, + untracked_resolutions: ty::ResolverGlobalCtxt, krate: Lrc, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, @@ -1271,11 +1284,6 @@ pub fn create_global_ctxt( crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { - let ResolverOutputs { - definitions, - global_ctxt: untracked_resolutions, - ast_lowering: untracked_resolver_for_lowering, - } = resolver_outputs; let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.emit_fatal(err); }); @@ -1304,7 +1312,6 @@ pub fn create_global_ctxt( lifetimes: common_lifetimes, consts: common_consts, untracked_resolutions, - untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering), untracked_crate: Steal::new(krate), on_disk_cache, queries, @@ -1515,7 +1522,7 @@ pub fn create_def( self, parent: LocalDefId, data: hir::definitions::DefPathData, - ) -> TyCtxtFeed<'tcx> { + ) -> TyCtxtFeed<'tcx, LocalDefId> { // This function modifies `self.definitions` using a side-effect. // We need to ensure that these side effects are re-run by the incr. comp. engine. // Depending on the forever-red node will tell the graph that the calling query @@ -1536,9 +1543,9 @@ pub fn create_def( // This is fine because: // - those queries are `eval_always` so we won't miss their result changing; // - this write will have happened before these queries are called. - let def_id = self.definitions.write().create_def(parent, data); + let key = self.definitions.write().create_def(parent, data); - let feed = TyCtxtFeed { tcx: self.tcx, def_id }; + let feed = TyCtxtFeed { tcx: self.tcx, key }; feed.def_span(self.span); feed } @@ -3107,7 +3114,6 @@ fn ptr_eq(t: *const T, u: *const U) -> bool { pub fn provide(providers: &mut ty::query::Providers) { providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; - providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering; providers.module_reexports = |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { 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 @@ pub fn default_value<'tcx>( _ => 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 dd4ab3e8d30..9e73236f8d5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -82,8 +82,8 @@ pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData, - GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, - UserTypeAnnotationIndex, + GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults, + UserType, UserTypeAnnotationIndex, }; pub use self::instance::{Instance, InstanceDef, ShortInstance}; pub use self::list::List; diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index a7fd1754960..642900d3ab4 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -328,13 +328,25 @@ fn $name( }; } +macro_rules! hash_result { + ([]) => {{ + Some(dep_graph::hash_result) + }}; + ([(no_hash) $($rest:tt)*]) => {{ + None + }}; + ([$other:tt $($modifiers:tt)*]) => { + hash_result!([$($modifiers)*]) + }; +} + macro_rules! define_feedable { ($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - impl<'tcx> TyCtxtFeed<'tcx> { - $($(#[$attr])* + $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> { + $(#[$attr])* #[inline(always)] pub fn $name(self, value: $V) -> query_stored::$name<'tcx> { - let key = self.def_id().into_query_param(); + let key = self.key().into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); let tcx = self.tcx; @@ -358,11 +370,11 @@ pub fn $name(self, value: $V) -> query_stored::$name<'tcx> { tcx, key, &value, - dep_graph::hash_result, + hash_result!([$($modifiers)*]), ); cache.complete(key, value, dep_node_index) - })* - } + } + })* } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5984686044b..1eec119616e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -722,8 +722,17 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicat 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) } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 141c8354c18..23507d28045 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -352,6 +352,22 @@ pub fn fill_single( } } + // 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> + 'tcx { self.iter() diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index cc69a1bb02d..7df01142264 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -406,7 +406,7 @@ fn clone_from(&mut self, source: &Self) { /// The dataflow state for an instance of [`ValueAnalysis`]. /// /// Every instance specifies a lattice that represents the possible values of a single tracked -/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an +/// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an /// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is /// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not /// the bottom element (because joining an unreachable and any other reachable state yields a diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 778ae63c5a4..594cbd8977e 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::write_mir_pretty; use rustc_middle::mir::Body; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_session::config::OutputType; pub struct Marker(pub &'static str); @@ -19,8 +19,8 @@ fn name(&self) -> &str { fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} } -pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> { - let path = outputs.path(OutputType::Mir); +pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> { + let path = tcx.output_filenames(()).path(OutputType::Mir); let mut f = io::BufWriter::new(File::create(&path)?); write_mir_pretty(tcx, None, &mut f)?; Ok(()) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index bf670c5c26a..220cf7df9c6 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -8,7 +8,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; -use rustc_span::def_id::DefId; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -87,13 +86,8 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let param_env = tcx.param_env_reveal_all_normalized(def_id); - let mut this = Inliner { - tcx, - param_env, - codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), - history: Vec::new(), - changed: false, - }; + let mut this = + Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false }; let blocks = BasicBlock::new(0)..body.basic_blocks.next_index(); this.process_blocks(body, blocks); this.changed @@ -104,12 +98,6 @@ struct Inliner<'tcx> { param_env: ParamEnv<'tcx>, /// Caller codegen attributes. codegen_fn_attrs: &'tcx CodegenFnAttrs, - /// Stack of inlined instances. - /// We only check the `DefId` and not the substs because we want to - /// avoid inlining cases of polymorphic recursion. - /// The number of `DefId`s is finite, so checking history is enough - /// to ensure that we do not loop endlessly while inlining. - history: Vec, /// Indicates that the caller body has been modified. changed: bool, } @@ -134,12 +122,12 @@ fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range { + Ok(_) => { debug!("inlined {}", callsite.callee); self.changed = true; - self.history.push(callsite.callee.def_id()); - self.process_blocks(caller_body, new_blocks); - self.history.pop(); + // We could process the blocks returned by `try_inlining` here. However, that + // leads to exponential compile times due to the top-down nature of this kind + // of inlining. } } } @@ -313,10 +301,6 @@ fn resolve_callsite( return None; } - if self.history.contains(&callee.def_id()) { - return None; - } - let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs); return Some(CallSite { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fe3cfde2e63..f6a6ed379a2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -390,20 +390,11 @@ fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool { // want to keep their span info to improve diagnostics in these cases in a later stage. (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` - (true, Some(AssocOp::Add)) // `{ 42 } + 42 - // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: - // `if x { a } else { b } && if y { c } else { d }` - if !self.look_ahead(1, |t| t.is_used_keyword()) => { - // These cases are ambiguous and can't be identified in the parser alone. - let sp = self.sess.source_map().start_point(self.token.span); - self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); - false - } - (true, Some(AssocOp::LAnd)) | - (true, Some(AssocOp::LOr)) | - (true, Some(AssocOp::BitOr)) => { - // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the - // above due to #74233. + (true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus) + (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` + (true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure) + (true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42` + => { // These cases are ambiguous and can't be identified in the parser alone. // // Bitwise AND is left out because guessing intent is hard. We can make 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 @@ fn parse_enum_variant(&mut self) -> PResult<'a, Option> { Ok((Some(vr), TrailingToken::MaybeComma)) }, - ) + ).map_err(|mut err|{ + err.help("enum variants can be `Variant`, `Variant = `, `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 @@ fn parse_seq_to_before_tokens( 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_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 30d28ff3455..38c7c6cce67 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -510,7 +510,7 @@ pub fn with_feed_task, A: Debug, R: Debug>( cx: Ctxt, key: A, result: &R, - hash_result: fn(&mut StableHashingContext<'_>, &R) -> Fingerprint, + hash_result: Option, &R) -> Fingerprint>, ) -> DepNodeIndex { if let Some(data) = self.data.as_ref() { // The caller query has more dependencies than the node we are creating. We may @@ -521,10 +521,12 @@ pub fn with_feed_task, A: Debug, R: Debug>( // For sanity, we still check that the loaded stable hash and the new one match. if let Some(dep_node_index) = self.dep_node_index_of_opt(&node) { let _current_fingerprint = - crate::query::incremental_verify_ich(cx, result, &node, Some(hash_result)); + crate::query::incremental_verify_ich(cx, result, &node, hash_result); #[cfg(debug_assertions)] - data.current.record_edge(dep_node_index, node, _current_fingerprint); + if hash_result.is_some() { + data.current.record_edge(dep_node_index, node, _current_fingerprint); + } return dep_node_index; } @@ -539,8 +541,9 @@ pub fn with_feed_task, A: Debug, R: Debug>( }); let hashing_timer = cx.profiler().incr_result_hashing(); - let current_fingerprint = - cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result)); + let current_fingerprint = hash_result.map(|hash_result| { + cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result)) + }); let print_status = cfg!(debug_assertions) && cx.sess().opts.unstable_opts.dep_tasks; @@ -550,7 +553,7 @@ pub fn with_feed_task, A: Debug, R: Debug>( &data.previous, node, edges, - Some(current_fingerprint), + current_fingerprint, print_status, ); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 51a53f7b37c..cf3e5946053 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1927,7 +1927,7 @@ enum Elision { // We have a single lifetime => success. elision_lifetime = Elision::Param(res) } else { - // We have have multiple lifetimes => error. + // We have multiple lifetimes => error. elision_lifetime = Elision::Err; } } @@ -2360,8 +2360,8 @@ fn with_generic_param_rib<'c, F>( if let GenericParamKind::Lifetime = param.kind { // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); - continue; } + continue; } Entry::Vacant(entry) => { entry.insert(param.ident.span); 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 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 ToStableHashKey for OutputType { type KeyType = Self; 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 3379279dd15..12cc72d30c8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1810,7 +1810,8 @@ fn find_similar_impl_candidates( &self, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Vec> { - self.tcx + let mut candidates: Vec<_> = self + .tcx .all_impls(trait_pred.def_id()) .filter_map(|def_id| { if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative @@ -1826,7 +1827,14 @@ fn find_similar_impl_candidates( self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false) .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) }) - .collect() + .collect(); + if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) { + // If any of the candidates is a perfect match, we don't want to show all of them. + // This is particularly relevant for the case of numeric types (as they all have the + // same cathegory). + candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })); + } + candidates } fn report_similar_impl_candidates( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 051660be9c4..71f6eae45aa 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2321,11 +2321,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( nested: &mut Vec>, ) { let tcx = selcx.tcx(); - for predicate in tcx + let own = tcx .predicates_of(obligation.predicate.item_def_id) - .instantiate_own(tcx, obligation.predicate.substs) - .predicates - { + .instantiate_own(tcx, obligation.predicate.substs); + for (predicate, span) in std::iter::zip(own.predicates, own.spans) { let normalized = normalize_with_depth_to( selcx, obligation.param_env, @@ -2334,9 +2333,30 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( predicate, nested, ); + + let nested_cause = if matches!( + obligation.cause.code(), + super::CompareImplItemObligation { .. } + | super::CheckAssociatedTypeBounds { .. } + | super::AscribeUserTypeProvePredicate(..) + ) { + obligation.cause.clone() + } else if span.is_dummy() { + ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + super::ItemObligation(obligation.predicate.item_def_id), + ) + } else { + ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + super::BindingObligation(obligation.predicate.item_def_id, span), + ) + }; nested.push(Obligation::with_depth( tcx, - obligation.cause.clone(), + nested_cause, obligation.recursion_depth + 1, obligation.param_env, normalized, 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/cmp.rs b/library/core/src/cmp.rs index 5db5cbfc3df..949896e5748 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,8 +29,7 @@ use self::Ordering::*; -/// Trait for equality comparisons which are [partial equivalence -/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation). +/// Trait for equality comparisons. /// /// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`. /// We use the easier-to-read infix notation in the remainder of this documentation. @@ -38,6 +37,8 @@ /// This trait allows for partial equality, for types that do not have a full /// equivalence relation. For example, in floating point numbers `NaN != NaN`, /// so floating point types implement `PartialEq` but not [`trait@Eq`]. +/// Formally speaking, when `Rhs == Self`, this trait corresponds to a [partial equivalence +/// relation](https://en.wikipedia.org/wiki/Partial_equivalence_relation). /// /// Implementations must ensure that `eq` and `ne` are consistent with each other: /// diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index dc69bf4df59..fd8d25ce1a5 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -20,7 +20,7 @@ /// #![feature(iter_repeat_n)] /// use std::iter; /// -/// // four of the the number four: +/// // four of the number four: /// let mut four_fours = iter::repeat_n(4, 4); /// /// assert_eq!(Some(4), four_fours.next()); diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index d76d6f8b2a2..19da6d2fbec 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -1894,7 +1894,7 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool { // Thus, derefencing both `px` and `py` in the loop below is safe. // // Moreover, we set `pxend` and `pyend` to be 4 bytes before the actual - // end of of `px` and `py`. Thus, the final dereference outside of the + // end of `px` and `py`. Thus, the final dereference outside of the // loop is guaranteed to be valid. (The final comparison will overlap with // the last comparison done in the loop for lengths that aren't multiples // of four.) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c10bfde4ddf..a7aefc26b97 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.82" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 4db7b4990b9..f71edc6c525 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -225,7 +225,7 @@ fn start_recv(&self, token: &mut Token) -> bool { let slot = unsafe { self.buffer.get_unchecked(index) }; let stamp = slot.stamp.load(Ordering::Acquire); - // If the the stamp is ahead of the head by 1, we may attempt to pop. + // If the stamp is ahead of the head by 1, we may attempt to pop. if head + 1 == stamp { let new = if index + 1 < self.cap { // Same lap, incremented index. 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 @@ fn clone(&self) -> Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Sender { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -751,9 +749,7 @@ fn clone(&self) -> SyncSender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for SyncSender { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -1094,9 +1090,7 @@ fn into_iter(self) -> IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Receiver { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index e6dbf35bd02..ada69aa8269 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -46,7 +46,7 @@ pub(super) fn increment_num_running_threads(&self) { // We check for 'overflow' with usize::MAX / 2, to make sure there's no // chance it overflows to 0, which would result in unsoundness. if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 { - // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles. + // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles. self.decrement_num_running_threads(false); panic!("too many running threads in thread scope"); } 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 @@ macro_rules! describe { 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, pub gdb: Option, pub python: Option, + pub reuse: Option, pub cargo_native_static: bool, pub configure_args: Vec, @@ -611,6 +612,7 @@ struct Build { nodejs: Option = "nodejs", npm: Option = "npm", python: Option = "python", + reuse: Option = "reuse", locked_deps: Option = "locked-deps", vendor: Option = "vendor", full_bootstrap: Option = "full-bootstrap", @@ -1004,6 +1006,7 @@ pub fn parse(args: &[String]) -> 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/flags.rs b/src/bootstrap/flags.rs index 2001e29bd2e..37a8eb884ef 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -143,7 +143,7 @@ pub enum Subcommand { args: Vec, }, Setup { - profile: Profile, + profile: Option, }, } @@ -628,14 +628,15 @@ pub fn parse(args: &[String]) -> Flags { |path| format!("{} is not a valid UTF8 string", path.to_string_lossy()) )); - profile_string.parse().unwrap_or_else(|err| { + let profile = profile_string.parse().unwrap_or_else(|err| { eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); eprint!("{}", Profile::all_for_help("- ")); crate::detail_exit(1); - }) + }); + Some(profile) } else { - t!(crate::setup::interactive_path()) + None }; Subcommand::Setup { profile } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d69bced0b28..3ed53452309 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -542,16 +542,6 @@ pub fn new(mut config: Config) -> Build { metrics: metrics::BuildMetrics::init(), }; - build.verbose("finding compilers"); - cc_detect::find(&mut build); - // When running `setup`, the profile is about to change, so any requirements we have now may - // be different on the next invocation. Don't check for them until the next time x.py is - // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. - if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.verbose("running sanity check"); - sanity::check(&mut build); - } - // If local-rust is the same major.minor as the current version, then force a // local-rebuild let local_version_verbose = @@ -567,16 +557,34 @@ pub fn new(mut config: Config) -> Build { build.local_rebuild = true; } - // Make sure we update these before gathering metadata so we don't get an error about missing - // Cargo.toml files. - let rust_submodules = - ["src/tools/rust-installer", "src/tools/cargo", "library/backtrace", "library/stdarch"]; - for s in rust_submodules { - build.update_submodule(Path::new(s)); - } + build.verbose("finding compilers"); + cc_detect::find(&mut build); + // When running `setup`, the profile is about to change, so any requirements we have now may + // be different on the next invocation. Don't check for them until the next time x.py is + // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. + // + // Similarly, for `setup` we don't actually need submodules or cargo metadata. + if !matches!(build.config.cmd, Subcommand::Setup { .. }) { + build.verbose("running sanity check"); + sanity::check(&mut build); + + // Make sure we update these before gathering metadata so we don't get an error about missing + // Cargo.toml files. + let rust_submodules = [ + "src/tools/rust-installer", + "src/tools/cargo", + "library/backtrace", + "library/stdarch", + ]; + for s in rust_submodules { + build.update_submodule(Path::new(s)); + } + // Now, update all existing submodules. + build.update_existing_submodules(); - build.verbose("learning about cargo"); - metadata::build(&mut build); + build.verbose("learning about cargo"); + metadata::build(&mut build); + } build } @@ -668,7 +676,7 @@ fn dir_is_empty(dir: &Path) -> bool { /// If any submodule has been initialized already, sync it unconditionally. /// This avoids contributors checking in a submodule change by accident. - pub fn maybe_update_submodules(&self) { + pub fn update_existing_submodules(&self) { // Avoid running git when there isn't a git checkout. if !self.config.submodules(&self.rust_info()) { return; @@ -697,8 +705,6 @@ pub fn build(&mut self) { job::setup(self); } - self.maybe_update_submodules(); - if let Subcommand::Format { check, paths } = &self.config.cmd { return format::format(&builder::Builder::new(&self), *check, &paths); } 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 @@ fn run(self, builder: &Builder<'_>) { 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 @@ pub fn check(build: &mut Build) { .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/setup.rs b/src/bootstrap/setup.rs index 04480277fe0..c7f98a7d0d1 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,15 +1,13 @@ +use crate::Config; use crate::{t, VERSION}; -use crate::{Config, TargetSelection}; use std::env::consts::EXE_SUFFIX; use std::fmt::Write as _; use std::fs::File; +use std::io::Write; use std::path::{Path, PathBuf, MAIN_SEPARATOR}; use std::process::Command; use std::str::FromStr; -use std::{ - env, fmt, fs, - io::{self, Write}, -}; +use std::{fmt, fs, io}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Profile { @@ -81,38 +79,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -pub fn setup(config: &Config, profile: Profile) { - let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml")); - - if path.exists() { - eprintln!( - "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", - path.display() - ); - eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display()); - eprintln!( - "note: this will use the configuration in {}", - profile.include_path(&config.src).display() - ); - crate::detail_exit(1); - } - - let settings = format!( - "# Includes one of the default files in src/bootstrap/defaults\n\ - profile = \"{}\"\n\ - changelog-seen = {}\n", - profile, VERSION - ); - t!(fs::write(path, settings)); - - let include_path = profile.include_path(&config.src); - println!("`x.py` will now use the configuration at {}", include_path.display()); - - let build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); +pub fn setup(config: &Config, profile: Option) { + let profile = profile.unwrap_or_else(|| t!(interactive_path())); let stage_path = - ["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string()); - - println!(); + ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string()); if !rustup_installed() && profile != Profile::User { eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); @@ -134,8 +104,6 @@ pub fn setup(config: &Config, profile: Profile) { Profile::User => &["dist", "build"], }; - println!(); - t!(install_git_hook_maybe(&config)); println!(); @@ -150,6 +118,36 @@ pub fn setup(config: &Config, profile: Profile) { "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); } + + let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml")); + setup_config_toml(path, profile, config); +} + +fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { + if path.exists() { + eprintln!(); + eprintln!( + "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", + path.display() + ); + eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display()); + eprintln!( + "note: this will use the configuration in {}", + profile.include_path(&config.src).display() + ); + crate::detail_exit(1); + } + + let settings = format!( + "# Includes one of the default files in src/bootstrap/defaults\n\ + profile = \"{}\"\n\ + changelog-seen = {}\n", + profile, VERSION + ); + t!(fs::write(path, settings)); + + let include_path = profile.include_path(&config.src); + println!("`x.py` will now use the configuration at {}", include_path.display()); } fn rustup_installed() -> bool { @@ -303,7 +301,18 @@ fn parse_with_abbrev(input: &str) -> Result { // install a git hook to automatically run tidy --bless, if they want fn install_git_hook_maybe(config: &Config) -> io::Result<()> { + let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { + assert!(output.status.success(), "failed to run `git`"); + PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) + })); + let dst = git.join("hooks").join("pre-push"); + if dst.exists() { + // The git hook has already been set up, or the user already has a custom hook. + return Ok(()); + } + let mut input = String::new(); + println!(); println!( "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality. If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before @@ -329,12 +338,6 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> { if should_install { let src = config.src.join("src").join("etc").join("pre-push.sh"); - let git = - t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })); - let dst = git.join("hooks").join("pre-push"); match fs::hard_link(src, &dst) { Err(e) => eprintln!( "error: could not create hook {}: do you already have the git hook installed?\n{}", 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 @@ fn run(self, builder: &Builder<'_>) -> PathBuf { 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/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index e54d0eafb40..699938c3718 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -14,7 +14,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins gdb \ libssl-dev \ pkg-config \ - xz-utils + xz-utils \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index cd86d9fb584..ea4a2a2427d 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -32,7 +32,8 @@ RUN yum upgrade -y && \ wget \ xz \ zlib-devel.i686 \ - zlib-devel.x86_64 + zlib-devel.x86_64 \ + && yum clean all RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index f9b1fa8951a..377d4a9ce5e 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ wget \ libssl-dev \ - pkg-config + pkg-config \ + && rm -rf /var/lib/apt/lists/* COPY scripts/freebsd-toolchain.sh /tmp/ RUN /tmp/freebsd-toolchain.sh x86_64 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile index c2e44ead51e..4e46bdee5ac 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile @@ -11,7 +11,8 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ libgmp-dev \ libmpfr-dev \ - libmpc-dev + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* COPY scripts/illumos-toolchain.sh /tmp/ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 423aba06cca..6bdc88e18f5 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -32,7 +32,8 @@ RUN yum upgrade -y && \ wget \ xz \ zlib-devel.i686 \ - zlib-devel.x86_64 + zlib-devel.x86_64 \ + && yum clean all RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index 51645a81853..13eaf7fce8c 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -16,7 +16,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins gdb \ patch \ libssl-dev \ - pkg-config + pkg-config \ + && rm -rf /var/lib/apt/lists/* WORKDIR /build/ diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index dd74726f856..e2b66c2cff1 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ zlib1g-dev \ lib32z1-dev \ - xz-utils + xz-utils \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index 0c36cfd66bd..cb6559707d9 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ zlib1g-dev \ lib32z1-dev \ - xz-utils + xz-utils \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 52a7776153d..40caa7c5013 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -20,20 +20,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ libssl-dev \ pkg-config \ - mingw-w64 + mingw-w64 \ + && rm -rf /var/lib/apt/lists/* RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}" # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. -RUN npm install es-check@6.1.1 -g -RUN npm install eslint@8.6.0 -g +RUN npm install es-check@6.1.1 eslint@8.6.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/ -RUN pip3 install --no-deps --require-hashes -r /tmp/reuse-requirements.txt +RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 7c09e3a582f..cf4451f8b33 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -21,7 +21,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins ovmf \ qemu-efi-aarch64 \ qemu-system-arm \ - qemu-system-x86 + qemu-system-x86 \ + && rm -rf /var/lib/apt/lists/* RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \ tar -xJ diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile index 9e37c2822e8..ef1fde1c3b9 100644 --- a/src/ci/docker/host-x86_64/wasm32/Dockerfile +++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile @@ -13,7 +13,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins sudo \ gdb \ xz-utils \ - bzip2 + bzip2 \ + && rm -rf /var/lib/apt/lists/* COPY scripts/emscripten.sh /scripts/ RUN bash /scripts/emscripten.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index d55d5b56ad3..e08c4e1e8b7 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -19,7 +19,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ llvm-dev \ libfreetype6-dev \ libexpat1-dev \ - tidy + tidy \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 739045248fe..c2b002055a8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -23,7 +23,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ xz-utils \ lld \ - clang + clang \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 80a004501a8..7e640c49f01 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ libssl-dev \ - pkg-config + pkg-config \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile index 23f2215c2d9..16976a9428e 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile @@ -21,7 +21,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ zlib1g-dev \ xz-utils \ - nodejs + nodejs \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile index 8f6831bc54e..c3b47c3510d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile @@ -24,15 +24,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ zlib1g-dev \ xz-utils \ - nodejs + nodejs \ # Install powershell so we can test x.ps1 on Linux -RUN apt-get update && \ - apt-get install -y apt-transport-https software-properties-common && \ + apt-transport-https software-properties-common && \ curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \ dpkg -i packages-microsoft-prod.deb && \ apt-get update && \ - apt-get install -y powershell + apt-get install -y powershell \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 77510d7ac62..9fdc78406fb 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins gdb \ libssl-dev \ pkg-config \ - xz-utils + xz-utils \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 4350ca20586..501d2781646 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -14,10 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ sudo \ xz-utils \ - tidy + tidy \ # Install dependencies for chromium browser -RUN apt-get install -y \ gconf-service \ libasound2 \ libatk1.0-0 \ @@ -56,7 +55,8 @@ RUN apt-get install -y \ libnss3 \ lsb-release \ xdg-utils \ - wget + wget \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 88c182a4d43..5b9581f72a6 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ libssl-dev \ pkg-config \ - xz-utils + xz-utils \ + && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 4a4cac1b723..17cd456b995 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -53,7 +53,7 @@ files_to_extract=( for lib in c cxxrt gcc_s m thr util; do files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*") done -for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm; do +for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm memstat; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done diff --git a/src/doc/book b/src/doc/book index 3f64052c048..a60f4316ec9 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 3f64052c048c6def93b94a2b514ee88bba918744 +Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index c533348edd6..19f798d4488 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit c533348edd69f11a8f4225d633a05d7093fddbf3 +Subproject commit 19f798d448835a4888e3b3eae7fe69f1d61d8681 diff --git a/src/doc/nomicon b/src/doc/nomicon index 05532356e7a..ae406aa5287 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 05532356e7a4dbea2330aabb77611f5179493bb8 +Subproject commit ae406aa5287a9e025abb72343aaceec98458c117 diff --git a/src/doc/reference b/src/doc/reference index 9f0cc13ffcd..3ae62681ff2 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19 +Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 2b15c0abf2b..a9869b4a3c4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 2b15c0abf2bada6e00553814336bc3e2d8399097 +Subproject commit a9869b4a3c4cac3bc6099b41f088679e268400b8 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d0dc6c97a64..e269950a57f 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d0dc6c97a6486f68bac782fff135086eae6d77ec +Subproject commit e269950a57fa6fcda356426545fb5aa3691a7ced diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f44797fe55f..528e99d2ce0 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1660,8 +1660,6 @@ in storage.js /* Hide the sidebar offscreen while not in use. Doing this instead of display: none means the sidebar stays visible for screen readers, which is useful for navigation. */ left: -1000px; - margin: 0; - padding: 0; z-index: 11; /* Reduce height slightly to account for mobile topbar. */ height: calc(100vh - 45px); @@ -1978,7 +1976,9 @@ in storage.js } .scraped-example .code-wrapper .example-wrap { - flex: 1; + display: grid; + grid-template-columns: max-content auto; + width: 100%; overflow-x: auto; overflow-y: hidden; margin-bottom: 0; diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index d0fd115fd15..e328e656edd 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -57,7 +57,7 @@ }); }); - example.querySelector("next") + example.querySelector(".next") .addEventListener("click", () => { onChangeLoc(() => { locIndex = (locIndex + 1) % locs.length; diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 1f87f95563a..b48b82307eb 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -130,4 +130,4 @@ pub(crate) fn for_each(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<() nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt", } -pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js"); +pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md"); diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff index 5f3ee467c88..afe157ccd7f 100644 --- a/src/test/mir-opt/inline/cycle.g.Inline.diff +++ b/src/test/mir-opt/inline/cycle.g.Inline.diff @@ -10,8 +10,6 @@ + let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 + let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ scope 2 (inlined >::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 -+ } + } bb0: { @@ -29,7 +27,10 @@ + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _3 = >::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ // mir::Constant ++ // + span: $DIR/cycle.rs:6:5: 6:6 ++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> >::Output {>::call}, val: Value() } } bb1: { @@ -39,19 +40,19 @@ return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 + } + -+ bb2 (cleanup): { -+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ bb2: { ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + + bb3 (cleanup): { -+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 ++ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + -+ bb4: { -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 -+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ bb4 (cleanup): { ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 } } diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff index 8b4099b9d9f..bd89e09ecd1 100644 --- a/src/test/mir-opt/inline/cycle.main.Inline.diff +++ b/src/test/mir-opt/inline/cycle.main.Inline.diff @@ -10,18 +10,6 @@ + let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 + let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ scope 2 (inlined >::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 -+ scope 3 (inlined g) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12 -+ scope 4 (inlined f::) { // at $DIR/cycle.rs:12:5: 12:12 -+ debug g => _6; // in scope 4 at $DIR/cycle.rs:5:6: 5:7 -+ let _7: (); // in scope 4 at $DIR/cycle.rs:6:5: 6:8 -+ let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6 -+ scope 5 (inlined >::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 -+ } -+ } -+ } -+ } + } bb0: { @@ -39,11 +27,10 @@ + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ StorageLive(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 -+ StorageLive(_7); // scope 4 at $DIR/cycle.rs:6:5: 6:8 -+ StorageLive(_8); // scope 4 at $DIR/cycle.rs:6:5: 6:6 -+ _8 = &_6; // scope 4 at $DIR/cycle.rs:6:5: 6:6 -+ _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _3 = >::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ // mir::Constant ++ // + span: $DIR/cycle.rs:6:5: 6:6 ++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> >::Output {>::call}, val: Value() } } bb1: { @@ -53,22 +40,19 @@ return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 + } + -+ bb2 (cleanup): { -+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ bb2: { ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + + bb3 (cleanup): { -+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 ++ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2 + } + -+ bb4: { -+ StorageDead(_8); // scope 4 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_7); // scope 4 at $DIR/cycle.rs:6:8: 6:9 -+ StorageDead(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 -+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ bb4 (cleanup): { ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 } } diff --git a/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff b/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff new file mode 100644 index 00000000000..d9fd7b324c7 --- /dev/null +++ b/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff @@ -0,0 +1,50 @@ +- // MIR for `main` before Inline ++ // MIR for `main` after Inline + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/exponential_runtime.rs:+0:11: +0:11 + let _1: (); // in scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ scope 1 (inlined <() as G>::call) { // at $DIR/exponential_runtime.rs:86:5: 86:22 ++ let _2: (); // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ let _3: (); // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 ++ let _4: (); // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 +- _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ _2 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 + // mir::Constant +- // + span: $DIR/exponential_runtime.rs:86:5: 86:20 +- // + literal: Const { ty: fn() {<() as G>::call}, val: Value() } ++ // + span: $DIR/exponential_runtime.rs:73:9: 73:23 ++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value() } + } + + bb1: { ++ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26 ++ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 ++ _3 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 ++ // mir::Constant ++ // + span: $DIR/exponential_runtime.rs:74:9: 74:23 ++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value() } ++ } ++ ++ bb2: { ++ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26 ++ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 ++ _4 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 ++ // mir::Constant ++ // + span: $DIR/exponential_runtime.rs:75:9: 75:23 ++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value() } ++ } ++ ++ bb3: { ++ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26 + StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23 + _0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2 + return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2 + } + } + diff --git a/src/test/mir-opt/inline/exponential_runtime.rs b/src/test/mir-opt/inline/exponential_runtime.rs new file mode 100644 index 00000000000..d9219d76a98 --- /dev/null +++ b/src/test/mir-opt/inline/exponential_runtime.rs @@ -0,0 +1,87 @@ +// Checks that code with exponential runtime does not have exponential behavior in inlining. + +trait A { + fn call(); +} + +trait B { + fn call(); +} +impl B for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +trait C { + fn call(); +} +impl C for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +trait D { + fn call(); +} +impl D for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +trait E { + fn call(); +} +impl E for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +trait F { + fn call(); +} +impl F for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +trait G { + fn call(); +} +impl G for T { + #[inline] + fn call() { + ::call(); + ::call(); + ::call(); + } +} + +impl A for () { + #[inline(never)] + fn call() {} +} + +// EMIT_MIR exponential_runtime.main.Inline.diff +fn main() { + <() as G>::call(); +} diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff index 5510cd7bc8c..f54a1a747d4 100644 --- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff @@ -5,20 +5,17 @@ let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10 let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24 + scope 1 (inlined ::call) { // at $DIR/inline_cycle.rs:14:5: 14:24 -+ scope 2 (inlined as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23 -+ scope 3 (inlined as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31 -+ } -+ } + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24 - _1 = ::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24 -+ _1 = ::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28 ++ _1 = as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23 // mir::Constant - // + span: $DIR/inline_cycle.rs:14:5: 14:22 -+ // + span: $DIR/inline_cycle.rs:36:9: 36:26 - // + literal: Const { ty: fn() {::call}, val: Value() } +- // + literal: Const { ty: fn() {::call}, val: Value() } ++ // + span: $DIR/inline_cycle.rs:43:9: 43:21 ++ // + literal: Const { ty: fn() { as Call>::call}, val: Value() } } bb1: { diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff index ab1ea0e3b2c..a940848c269 100644 --- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff @@ -9,11 +9,6 @@ + debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23 + let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 -+ scope 2 (inlined >::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8 -+ scope 3 (inlined f) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ let _5: (); // in scope 3 at $DIR/inline_cycle.rs:59:5: 59:12 -+ } -+ } + } bb0: { @@ -23,23 +18,19 @@ + _2 = f; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 // mir::Constant - // + span: $DIR/inline_cycle.rs:49:5: 49:9 -+ // + span: $DIR/inline_cycle.rs:49:10: 49:11 -+ // + literal: Const { ty: fn() {f}, val: Value() } +- // + literal: Const { ty: fn(fn() {f}) {call::}, val: Value() } +- // mir::Constant + // + span: $DIR/inline_cycle.rs:49:10: 49:11 + // + literal: Const { ty: fn() {f}, val: Value() } + StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 -+ StorageLive(_5); // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12 -+ _5 = call::(f) -> bb1; // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12 ++ _3 = >::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + // mir::Constant -+ // + span: $DIR/inline_cycle.rs:59:5: 59:9 - // + literal: Const { ty: fn(fn() {f}) {call::}, val: Value() } - // mir::Constant -- // + span: $DIR/inline_cycle.rs:49:10: 49:11 -+ // + span: $DIR/inline_cycle.rs:59:10: 59:11 - // + literal: Const { ty: fn() {f}, val: Value() } ++ // + span: $DIR/inline_cycle.rs:54:5: 54:6 ++ // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> >::Output {>::call_once}, val: Value() } } bb1: { -+ StorageDead(_5); // scope 3 at $DIR/inline_cycle.rs:59:12: 59:13 + StorageDead(_4); // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8 + StorageDead(_3); // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9 + StorageDead(_2); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff index 52debab4dd1..04de3e61e5f 100644 --- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff @@ -6,21 +6,18 @@ let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24 + scope 1 (inlined ::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24 + scope 2 (inlined as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31 -+ scope 3 (inlined ::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28 -+ scope 4 (inlined as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31 -+ } -+ } + } + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24 - _1 = ::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24 -+ _1 = ::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28 ++ _1 = ::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28 // mir::Constant - // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22 +- // + literal: Const { ty: fn() {::call}, val: Value() } + // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26 - // + literal: Const { ty: fn() {::call}, val: Value() } ++ // + literal: Const { ty: fn() {::call}, val: Value() } } bb1: { diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 75a6ab37008..a01bcf1645b 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -19,14 +19,6 @@ + scope 3 { + debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 + } -+ scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:28:13: 28:16 -+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ } -+ } -+ } -+ scope 4 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16 -+ scope 5 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL -+ } + } + } @@ -46,11 +38,51 @@ + StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12 ++ _3 = ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 ++ // mir::Constant ++ // + span: $DIR/inline_diverging.rs:27:13: 27:14 ++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> ! {sleep} as FnOnce<()>>::Output { ! {sleep} as Fn<()>>::call}, val: Value() } + } + + bb1: { -+ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12 ++ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 ++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 ++ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 ++ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 ++ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 ++ _9 = ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 ++ // mir::Constant ++ // + span: $DIR/inline_diverging.rs:28:13: 28:14 ++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> ! {sleep} as FnOnce<()>>::Output { ! {sleep} as Fn<()>>::call}, val: Value() } ++ } ++ ++ bb2: { ++ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 ++ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 ++ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _8 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ Deinit(_1); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ (_1.0: !) = move _8; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ (_1.1: !) = move _9; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 ++ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ drop(_2) -> bb3; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ } ++ ++ bb3: { ++ unreachable; // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2 ++ } ++ ++ bb4 (cleanup): { ++ drop(_3) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ } ++ ++ bb5 (cleanup): { ++ drop(_2) -> bb6; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2 } } diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index f25b3ce724b..b28c6f687f7 100644 --- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -22,9 +22,6 @@ let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL scope 9 { debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - } } } } @@ -95,18 +92,11 @@ StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL _18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 +- _17 = >::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL ++ _17 = >::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/result.rs:LL:COL + // + literal: Const { ty: fn(i32) -> i32 {>::from}, val: Value() } } - bb5: { @@ -152,5 +142,20 @@ + _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 } + +- bb8: { ++ bb7: { + StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 + StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 + StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 + StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 + return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 + } } diff --git a/src/test/rustdoc-gui/method-margins.goml b/src/test/rustdoc-gui/method-margins.goml index 397bcd40b36..ed36bcdec17 100644 --- a/src/test/rustdoc-gui/method-margins.goml +++ b/src/test/rustdoc-gui/method-margins.goml @@ -1,3 +1,4 @@ +// This test ensures that the margins on methods are coherent inside an impl block. goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait" assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1) diff --git a/src/test/rustdoc-gui/scrape-examples-button-focus.goml b/src/test/rustdoc-gui/scrape-examples-button-focus.goml index 2a263a87a47..a222139f1dc 100644 --- a/src/test/rustdoc-gui/scrape-examples-button-focus.goml +++ b/src/test/rustdoc-gui/scrape-examples-button-focus.goml @@ -1,4 +1,17 @@ goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" + +store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre", "scrollTop") +focus: ".scraped-example-list > .scraped-example .next" +press-key: "Enter" +assert-property-false: (".scraped-example-list > .scraped-example pre", { + "scrollTop": |initialScrollTop| +}) +focus: ".scraped-example-list > .scraped-example .prev" +press-key: "Enter" +assert-property: (".scraped-example-list > .scraped-example pre", { + "scrollTop": |initialScrollTop| +}) + store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight") assert-property-false: (".scraped-example-list > .scraped-example pre", { "scrollHeight": |smallOffsetHeight| diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check.rs index 3e69c6086ae..b3f682fe497 100644 --- a/src/test/rustdoc-gui/src/scrape_examples/examples/check.rs +++ b/src/test/rustdoc-gui/src/scrape_examples/examples/check.rs @@ -22,4 +22,5 @@ fn main() { println!("hello world!"); println!("hello world!"); } + scrape_examples::test(); } diff --git a/src/test/ui/associated-inherent-types/normalize-projection-0.rs b/src/test/ui/associated-inherent-types/normalize-projection-0.rs new file mode 100644 index 00000000000..50763ecddf9 --- /dev/null +++ b/src/test/ui/associated-inherent-types/normalize-projection-0.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct S(T); + +impl S { + type P = ::P; +} + +trait O { + type P; +} + +impl O for i32 { + type P = String; +} + +fn main() { + let _: S::P = String::new(); +} diff --git a/src/test/ui/associated-inherent-types/normalize-projection-1.rs b/src/test/ui/associated-inherent-types/normalize-projection-1.rs new file mode 100644 index 00000000000..2f7b2551a03 --- /dev/null +++ b/src/test/ui/associated-inherent-types/normalize-projection-1.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct S; + +impl S { + type P = ::P; +} + +trait O { + type P; +} + +impl O for i32 { + type P = String; +} + +fn main() { + let _: S::P = String::new(); +} diff --git a/src/test/ui/async-await/track-caller/issue-105134.rs b/src/test/ui/async-await/track-caller/issue-105134.rs new file mode 100644 index 00000000000..4e52b8e250b --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-105134.rs @@ -0,0 +1,11 @@ +// check-pass +// edition:2021 + +#[track_caller] +fn f() { + let _ = async {}; +} + +fn main() { + f(); +} diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs index b113c56412f..5ebfeb3f36a 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.rs +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -54,6 +54,19 @@ async fn foo_track_caller() { bar_track_caller().await } +struct Foo; + +impl Foo { + #[track_caller] + async fn bar_assoc() { + panic!(); + } +} + +async fn foo_assoc() { + Foo::bar_assoc().await +} + fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { let loc = Arc::new(Mutex::new(None)); @@ -73,4 +86,5 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { fn main() { assert_eq!(panicked_at(|| block_on(foo())), 41); assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 67); } 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/binop/binop-mul-i32-f32.stderr b/src/test/ui/binop/binop-mul-i32-f32.stderr index 21c490965b1..c986bc3fd1e 100644 --- a/src/test/ui/binop/binop-mul-i32-f32.stderr +++ b/src/test/ui/binop/binop-mul-i32-f32.stderr @@ -6,15 +6,10 @@ LL | x * y | = help: the trait `Mul` is not implemented for `i32` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&i32 as Mul<&i32>> + > + error: aborting due to previous error diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr index f2e7777ce68..a46bd53520b 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -18,9 +18,7 @@ LL | LL | 1_u32 | ----- return type was inferred to be `u32` here | - = help: the following other types implement trait `Traitor`: - > - > + = help: the trait `Traitor` is implemented for `u32` error[E0277]: the trait bound `u64: Traitor` is not satisfied --> $DIR/rp_impl_trait_fail.rs:21:13 @@ -31,9 +29,7 @@ LL | LL | 1_u64 | ----- return type was inferred to be `u64` here | - = help: the following other types implement trait `Traitor`: - > - > + = help: the trait `Traitor<1, 2>` is implemented for `u64` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/defaults/self-referential.rs b/src/test/ui/const-generics/defaults/self-referential.rs new file mode 100644 index 00000000000..14a870dc39b --- /dev/null +++ b/src/test/ui/const-generics/defaults/self-referential.rs @@ -0,0 +1,4 @@ +trait Foo {} +//~^ ERROR the name `M` is already used for a generic parameter in this item's generic parameters +impl Foo<2> for () {} +fn main() {} diff --git a/src/test/ui/const-generics/defaults/self-referential.stderr b/src/test/ui/const-generics/defaults/self-referential.stderr new file mode 100644 index 00000000000..170c1f7f7b2 --- /dev/null +++ b/src/test/ui/const-generics/defaults/self-referential.stderr @@ -0,0 +1,11 @@ +error[E0403]: the name `M` is already used for a generic parameter in this item's generic parameters + --> $DIR/self-referential.rs:1:30 + | +LL | trait Foo {} + | - ^ already used + | | + | first use of `M` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0403`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index c685922c456..f199170018f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,15 +12,10 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `~const Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&i8 as Add<&i8>> + > + error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index b396079240a..1f8e402317a 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,15 +12,10 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `~const Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&i8 as Add<&i8>> + > + error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index d27b05fe7f7..7229b9ac986 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -12,10 +12,6 @@ LL | Foo::::bar(&1i8); > > > - > - > - > - > error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -26,11 +22,6 @@ LL | Foo::::bar(&1u8); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > > > > diff --git a/src/test/ui/duplicate/duplicate-type-parameter.stderr b/src/test/ui/duplicate/duplicate-type-parameter.stderr index 6754574f0b9..628f898d5c8 100644 --- a/src/test/ui/duplicate/duplicate-type-parameter.stderr +++ b/src/test/ui/duplicate/duplicate-type-parameter.stderr @@ -55,10 +55,10 @@ LL | impl Qux for Option {} | first use of `T` error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/duplicate-type-parameter.rs:24:6 + --> $DIR/duplicate-type-parameter.rs:24:8 | LL | impl Qux for Option {} - | ^ unconstrained type parameter + | ^ unconstrained type parameter error: aborting due to 8 previous errors diff --git a/src/test/ui/generic-associated-types/own-bound-span.rs b/src/test/ui/generic-associated-types/own-bound-span.rs new file mode 100644 index 00000000000..3699f7296f5 --- /dev/null +++ b/src/test/ui/generic-associated-types/own-bound-span.rs @@ -0,0 +1,17 @@ +struct S; + +trait D { + type P; + //~^ NOTE required by this bound in `D::P` + //~| NOTE required by a bound in `D::P` +} + +impl D for S { + type P = (); +} + +fn main() { + let _: ::P; + //~^ ERROR the trait bound `String: Copy` is not satisfied + //~| NOTE the trait `Copy` is not implemented for `String` +} diff --git a/src/test/ui/generic-associated-types/own-bound-span.stderr b/src/test/ui/generic-associated-types/own-bound-span.stderr new file mode 100644 index 00000000000..8ab8ea623b2 --- /dev/null +++ b/src/test/ui/generic-associated-types/own-bound-span.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/own-bound-span.rs:14:12 + | +LL | let _: ::P; + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `D::P` + --> $DIR/own-bound-span.rs:4:15 + | +LL | type P; + | ^^^^ required by this bound in `D::P` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 1841b8e5dcd..69f4cbbbf42 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -30,15 +30,10 @@ LL | n + sum_to(n - 1) | = help: the trait `Add` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&'a u32 as Add> + <&u32 as Add<&u32>> + > + error: aborting due to 2 previous errors; 1 warning emitted 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 { + async move { let _s = s; } + //~^ ERROR hidden type for `impl Future` 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` 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 { + | -- 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` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future + '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 { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/issues/issue-24352.stderr index 118f37f6971..1f51b6e2905 100644 --- a/src/test/ui/issues/issue-24352.stderr +++ b/src/test/ui/issues/issue-24352.stderr @@ -6,15 +6,10 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&f64 as Sub<&f64>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | 1.0f64 - 1.0 diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 025a5008d0f..9af89159a8c 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -4,16 +4,7 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | - = help: the following other types implement trait `Copy`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `Copy` is implemented for `isize` note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | @@ -26,16 +17,7 @@ error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | - = help: the following other types implement trait `Copy`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `Copy` is implemented for `isize` note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | diff --git a/src/test/ui/lexer/lex-bad-char-literals-6.stderr b/src/test/ui/lexer/lex-bad-char-literals-6.stderr index afef0cb6034..ce41942467c 100644 --- a/src/test/ui/lexer/lex-bad-char-literals-6.stderr +++ b/src/test/ui/lexer/lex-bad-char-literals-6.stderr @@ -42,12 +42,11 @@ LL | if x == y {} <&'a str as PartialEq> <&'a str as PartialEq> <&'b str as PartialEq>> - > - >> - > - >> - and 4 others + > + > + > + error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -68,12 +67,11 @@ LL | if x == z {} <&'a str as PartialEq> <&'a str as PartialEq> <&'b str as PartialEq>> - > - >> - > - >> - and 4 others + > + > + > + error: aborting due to 6 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 = `, `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/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 3de652d87ec..3585587ed4c 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -24,15 +24,10 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> - <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&'a usize as Sub> + <&usize as Sub<&usize>> + > + error[E0277]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr index fed780e6895..2d22da0b420 100644 --- a/src/test/ui/never_type/issue-13352.stderr +++ b/src/test/ui/never_type/issue-13352.stderr @@ -6,15 +6,10 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&'a usize as Add> + <&usize as Add<&usize>> + > + error: aborting due to previous error diff --git a/src/test/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/src/test/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 6aa1ad8dd89..8f0eef237cf 100644 --- a/src/test/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/src/test/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,15 +6,10 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&'a u8 as Add> + <&u8 as Add<&u8>> + > + error[E0277]: cannot add `&str` to `f64` --> $DIR/not-suggest-float-literal.rs:6:7 @@ -24,15 +19,10 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f32 as Add> <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&f64 as Add<&f64>> + > + error[E0277]: cannot add `{integer}` to `f64` --> $DIR/not-suggest-float-literal.rs:11:7 @@ -42,15 +32,10 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f32 as Add> <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&f64 as Add<&f64>> + > + error[E0277]: cannot subtract `{float}` from `u8` --> $DIR/not-suggest-float-literal.rs:15:7 @@ -60,15 +45,10 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> - <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&'a u8 as Sub> + <&u8 as Sub<&u8>> + > + error[E0277]: cannot subtract `&str` from `f64` --> $DIR/not-suggest-float-literal.rs:19:7 @@ -78,15 +58,10 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&f64 as Sub<&f64>> + > + error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/not-suggest-float-literal.rs:24:7 @@ -96,15 +71,10 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&f64 as Sub<&f64>> + > + error[E0277]: cannot multiply `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:28:7 @@ -114,15 +84,10 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&'a u8 as Mul> + <&u8 as Mul<&u8>> + > + error[E0277]: cannot multiply `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:32:7 @@ -132,15 +97,10 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&f64 as Mul<&f64>> + > + error[E0277]: cannot multiply `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:37:7 @@ -150,15 +110,10 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&f64 as Mul<&f64>> + > + error[E0277]: cannot divide `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:41:7 @@ -168,15 +123,11 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: - <&'a f32 as Div> - <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> - and 54 others + <&'a u8 as Div> + <&u8 as Div<&u8>> + > + > + error[E0277]: cannot divide `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:45:7 @@ -186,15 +137,10 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f32 as Div> <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> - and 54 others + <&f64 as Div<&f64>> + > + error[E0277]: cannot divide `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:50:7 @@ -204,15 +150,10 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f32 as Div> <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> - and 54 others + <&f64 as Div<&f64>> + > + error: aborting due to 12 previous errors diff --git a/src/test/ui/numbers-arithmetic/suggest-float-literal.stderr b/src/test/ui/numbers-arithmetic/suggest-float-literal.stderr index 988379e582a..03779d35637 100644 --- a/src/test/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/src/test/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -7,14 +7,9 @@ LL | x + 100 = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add`: <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&f32 as Add<&f32>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -28,15 +23,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f32 as Add> <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&f64 as Add<&f64>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -51,14 +41,9 @@ LL | x - 100 = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub`: <&'a f32 as Sub> - <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&f32 as Sub<&f32>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -72,15 +57,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> - and 48 others + <&f64 as Sub<&f64>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -95,14 +75,9 @@ LL | x * 100 = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul`: <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&f32 as Mul<&f32>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -116,15 +91,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> - and 49 others + <&f64 as Mul<&f64>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -139,14 +109,9 @@ LL | x / 100 = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div`: <&'a f32 as Div> - <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> - and 54 others + <&f32 as Div<&f32>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 @@ -160,15 +125,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f32 as Div> <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> - and 54 others + <&f64 as Div<&f64>> + > + help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr index c1aaad31e81..f05b0cd6538 100644 --- a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr @@ -3,10 +3,10 @@ error[E0311]: the parameter type `Self` may not live long enough = help: consider adding an explicit lifetime bound `Self: 'a`... = note: ...so that the type `Self` will meet its required lifetime bounds... note: ...that is required by this bound - --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39 + --> $DIR/object-safety-supertrait-mentions-GAT.rs:6:15 | -LL | trait SuperTrait: for<'a> GatTrait = T> { - | ^^^^^^^^^^^ +LL | Self: 'a; + | ^^ error: associated item referring to unboxed trait object for its own trait --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20 diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed index 36709eea17c..b06f62794c4 100644 --- a/src/test/ui/parser/expr-as-stmt.fixed +++ b/src/test/ui/parser/expr-as-stmt.fixed @@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool { { foo(); } || { true } //~ ERROR E0308 } +// https://github.com/rust-lang/rust/issues/105179 +fn r#match() -> i32 { + (match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +// https://github.com/rust-lang/rust/issues/102171 +fn r#unsafe() -> i32 { + (unsafe { 1 }) + unsafe { 1 } //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs index 92bb972b240..b39d2b88647 100644 --- a/src/test/ui/parser/expr-as-stmt.rs +++ b/src/test/ui/parser/expr-as-stmt.rs @@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool { { foo() } || { true } //~ ERROR E0308 } +// https://github.com/rust-lang/rust/issues/105179 +fn r#match() -> i32 { + match () { () => 1 } + match () { () => 1 } //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +// https://github.com/rust-lang/rust/issues/102171 +fn r#unsafe() -> i32 { + unsafe { 1 } + unsafe { 1 } //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index 6da4ac34067..18c8b0b7c50 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -55,6 +55,28 @@ help: parentheses are required to parse this as an expression LL | ({ true }) | { true } | + + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:69:26 + | +LL | match () { () => 1 } + match () { () => 1 } + | ^ expected expression + | +help: parentheses are required to parse this as an expression + | +LL | (match () { () => 1 }) + match () { () => 1 } + | + + + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:75:18 + | +LL | unsafe { 1 } + unsafe { 1 } + | ^ expected expression + | +help: parentheses are required to parse this as an expression + | +LL | (unsafe { 1 }) + unsafe { 1 } + | + + + error[E0308]: mismatched types --> $DIR/expr-as-stmt.rs:64:7 | @@ -201,7 +223,26 @@ help: parentheses are required to parse this as an expression LL | ({ true }) || { true } | + + -error: aborting due to 18 previous errors +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:69:5 + | +LL | match () { () => 1 } + match () { () => 1 } + | ^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here + | | + | expected `()`, found integer + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:75:14 + | +LL | unsafe { 1 } + unsafe { 1 } + | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | unsafe { return 1; } + unsafe { 1 } + | ++++++ + + +error: aborting due to 22 previous errors Some errors have detailed explanations: E0308, E0600, E0614. For more information about an error, try `rustc --explain E0308`. 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 = `, `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, + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:` + //~| HELP: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + //~| ERROR expected item, found `:` + map: HashMap +} + +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, + | ^ expected one of `(`, `,`, `=`, `{`, or `}` + | + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: expected item, found `:` + --> $DIR/issue-103869.rs:2:8 + | +LL | vec: Vec, + | ^ 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 = `, `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/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs index 6b7d94603b5..a8deb8a7550 100644 --- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs +++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs @@ -5,7 +5,7 @@ struct Foo { impl PartialEq for Foo { fn eq(&self, _: &Foo) -> bool { - false // ha ha sucker! + false // ha ha! } } diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index c0d9a8634e4..b44df962a9b 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -6,15 +6,10 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&'a u32 as Add> + <&u32 as Add<&u32>> + > + error: aborting due to previous error 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 @@ fn foo() {} //~^ 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 = `, `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 = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: aborting due to 3 previous errors 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 { + 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 { + fn foo<'a>(&self, state: &'a State) -> &'a T + where + T: 'a; +} + +impl Foo 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/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr index cf2e4edf9f0..08f7bbbf0ea 100644 --- a/src/test/ui/traits/issue-79458.stderr +++ b/src/test/ui/traits/issue-79458.stderr @@ -7,10 +7,7 @@ LL | struct Foo<'a, T> { LL | bar: &'a mut T | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&mut T` | - = help: the following other types implement trait `Clone`: - &T - *const T - *mut T + = help: the trait `Clone` is implemented for `&T` = note: `Clone` is implemented for `&T`, but not for `&mut T` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 419a86bf33b..a49630adb95 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -8,15 +8,8 @@ LL | Ok(Err(123_i32)?) | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > - > - > - > - > - > - > - > - and 68 others + > + > = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` diff --git a/src/test/ui/type-alias-impl-trait/self-referential-2.stderr b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr index 2b505d30730..c2cf70687fd 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-2.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr @@ -7,16 +7,7 @@ LL | 42_i32 | ------ return type was inferred to be `i32` here | = help: the trait `PartialEq` is not implemented for `i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/self-referential-4.stderr b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr index 27880f792f4..98c762e3d38 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr @@ -7,16 +7,7 @@ LL | i | - return type was inferred to be `&i32` here | = help: the trait `PartialEq>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` --> $DIR/self-referential-4.rs:11:31 @@ -27,16 +18,7 @@ LL | i | - return type was inferred to be `&i32` here | = help: the trait `PartialEq>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` --> $DIR/self-referential-4.rs:17:31 @@ -47,16 +29,7 @@ LL | i | - return type was inferred to be `&i32` here | = help: the trait `PartialEq>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-impl-trait/self-referential.stderr b/src/test/ui/type-alias-impl-trait/self-referential.stderr index 97d510f6830..aff489d70e3 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential.stderr @@ -8,16 +8,7 @@ LL | i | - return type was inferred to be `&i32` here | = help: the trait `PartialEq>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error[E0277]: can't compare `&i32` with `(i32, &i32)` --> $DIR/self-referential.rs:12:31 @@ -29,16 +20,7 @@ LL | (42, i) | ------- return type was inferred to be `(i32, &i32)` here | = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` --> $DIR/self-referential.rs:19:31 @@ -50,16 +32,7 @@ LL | (42, i) | ------- return type was inferred to be `(i32, &i32)` here | = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32` - = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 - i16 - i32 - i64 - i8 - isize - and 6 others + = help: the trait `PartialEq` is implemented for `i32` error: aborting due to 3 previous errors diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index cf77c057d46..9ba63ffe9c9 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -66,15 +66,10 @@ LL | trait ProjectionPred> where T::Item : Add {} | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&i32 as Add<&i32>> + > + error: aborting due to 7 previous errors diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr index 9658288ac8b..6976be71135 100644 --- a/src/test/ui/typeck/issue-81293.stderr +++ b/src/test/ui/typeck/issue-81293.stderr @@ -21,15 +21,10 @@ LL | a = c + b * 5; | = help: the trait `Add` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&'a usize as Add> + <&usize as Add<&usize>> + > + error: aborting due to 3 previous errors diff --git a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr index eaab6ff3d9a..ed56e1cf957 100644 --- a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -8,15 +8,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&i32 as Add<&i32>> + > + error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 @@ -62,15 +57,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> - and 48 others + <&i32 as Add<&i32>> + > + error: aborting due to 4 previous errors 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, + by_struct: HashMap, +} + +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, +} + +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 { + Root { childs: Vec> }, + Directory { name: PathBuf, childs: Vec>, license: Option }, + File { name: PathBuf, license: L }, + FileGroup { names: Vec, license: L }, + Empty, +} + +impl Node { + 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 + /// │ + /// ─┼─► ./ ──► 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 + /// │ │ + /// ──► ./ ──┤ └─► 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 { + 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 { + 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` 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, + 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, 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 { + 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/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0d9a629e179..64d97e91442 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -260,9 +260,9 @@ pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self { props.load_from(testfile, cfg, config); match (props.pass_mode, props.fail_mode) { - (None, None) => props.fail_mode = Some(FailMode::Check), - (Some(_), None) | (None, Some(_)) => {} + (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check), (Some(_), Some(_)) => panic!("cannot use a *-fail and *-pass mode together"), + _ => {} } props @@ -522,8 +522,8 @@ fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config } pub fn pass_mode(&self, config: &Config) -> Option { - if !self.ignore_pass && self.fail_mode.is_none() && config.mode == Mode::Ui { - if let (mode @ Some(_), Some(_)) = (config.force_pass_mode, self.pass_mode) { + if !self.ignore_pass && self.fail_mode.is_none() { + if let mode @ Some(_) = config.force_pass_mode { return mode; } } 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, depth: usize) -> Result<(), Error> { + let prefix = std::iter::repeat("> ").take(depth + 1).collect::(); + + 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, + license: &License, + buffer: &mut Vec, +) -> 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 }, + Directory { name: String, childs: Vec, license: License }, + File { name: String, license: License }, + FileGroup { names: Vec, license: License }, +} + +#[derive(serde::Deserialize)] +struct License { + spdx: String, + copyright: Vec, +} + +fn env_path(var: &str) -> Result { + if let Some(var) = std::env::var_os(var) { + Ok(var.into()) + } else { + anyhow::bail!("missing environment variable {var}") + } +} diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0a6b9417cc2..8dd18ae98e6 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -cef44f53034eac46be3a0e3eec7b2b3d4ef5140b +203c8765ea33c65d888febe0e8219c4bb11b0d89 diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 50c2ad75ca7..bcac873251f 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -45,7 +45,9 @@ pub struct Stacks { /// new pointer. #[derive(Copy, Clone, Hash, PartialEq, Eq)] enum RefKind { - /// `&mut` and `Box`. + /// `Box`. + Box, + /// `&mut`. Unique { two_phase: bool }, /// `&` with or without interior mutability. Shared, @@ -56,6 +58,7 @@ enum RefKind { impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + RefKind::Box => write!(f, "Box"), RefKind::Unique { two_phase: false } => write!(f, "unique reference"), RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"), RefKind::Shared => write!(f, "shared reference"), @@ -654,15 +657,17 @@ fn sb_reborrow( let (perm, access) = match kind { RefKind::Unique { two_phase } => { // Permission is Unique only if the type is `Unpin` and this is not twophase - let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) { - Permission::Unique + if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) { + (Permission::Unique, Some(AccessKind::Write)) } else { - Permission::SharedReadWrite - }; - // We do an access for all full borrows, even if `!Unpin`. - let access = if !two_phase { Some(AccessKind::Write) } else { None }; - (perm, access) + // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we + // should do fake accesses here. But then we run into + // , so for now + // we don't do that. + (Permission::SharedReadWrite, None) + } } + RefKind::Box => (Permission::Unique, Some(AccessKind::Write)), RefKind::Raw { mutable: true } => { // Creating a raw ptr does not count as an access (Permission::SharedReadWrite, None) @@ -853,7 +858,7 @@ fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> // Boxes get a weak protectors, since they may be deallocated. self.retag_place( place, - RefKind::Unique { two_phase: false }, + RefKind::Box, self.retag_cause, /*protector*/ (self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector), diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs deleted file mode 100644 index d660921bfe6..00000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Reborrowing a `&mut !Unpin` must still act like a (fake) read. -use std::marker::PhantomPinned; - -struct NotUnpin(i32, PhantomPinned); - -fn main() { - unsafe { - let mut x = NotUnpin(0, PhantomPinned); - // Mutable borrow of `Unpin` field (with lifetime laundering) - let fieldref = &mut *(&mut x.0 as *mut i32); - // Mutable reborrow of the entire `x`, which is `!Unpin` but should - // still count as a read since we would add `dereferenceable`. - let _xref = &mut x; - // That read should have invalidated `fieldref`. - *fieldref = 0; //~ ERROR: /write access .* tag does not exist in the borrow stack/ - } -} diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr deleted file mode 100644 index 3ef8a8e0e9c..00000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | *fieldref = 0; - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental - = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a Unique retag at offsets [0x0..0x4] - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | let fieldref = &mut *(&mut x.0 as *mut i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag - --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - | -LL | let _xref = &mut x; - | ^^^^^^ - = note: BACKTRACE: - = note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs new file mode 100644 index 00000000000..3ba21552fd3 --- /dev/null +++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs @@ -0,0 +1,102 @@ +#![feature(pin_macro)] + +use std::future::*; +use std::marker::PhantomPinned; +use std::pin::*; +use std::ptr; +use std::task::*; + +struct Delay { + delay: usize, +} + +impl Delay { + fn new(delay: usize) -> Self { + Delay { delay } + } +} + +impl Future for Delay { + type Output = (); + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { + if self.delay > 0 { + self.delay -= 1; + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +async fn do_stuff() { + (&mut Delay::new(1)).await; +} + +// Same thing implemented by hand +struct DoStuff { + state: usize, + delay: Delay, + delay_ref: *mut Delay, + _marker: PhantomPinned, +} + +impl DoStuff { + fn new() -> Self { + DoStuff { + state: 0, + delay: Delay::new(1), + delay_ref: ptr::null_mut(), + _marker: PhantomPinned, + } + } +} + +impl Future for DoStuff { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + unsafe { + let this = self.get_unchecked_mut(); + match this.state { + 0 => { + // Set up self-ref. + this.delay_ref = &mut this.delay; + // Move to next state. + this.state = 1; + Poll::Pending + } + 1 => { + let delay = &mut *this.delay_ref; + Pin::new_unchecked(delay).poll(cx) + } + _ => unreachable!(), + } + } + } +} + +fn run_fut(fut: impl Future) -> T { + use std::sync::Arc; + + struct MyWaker; + impl Wake for MyWaker { + fn wake(self: Arc) { + unimplemented!() + } + } + + let waker = Waker::from(Arc::new(MyWaker)); + let mut context = Context::from_waker(&waker); + + let mut pinned = pin!(fut); + loop { + match pinned.as_mut().poll(&mut context) { + Poll::Pending => continue, + Poll::Ready(v) => return v, + } + } +} + +fn main() { + run_fut(do_stuff()); + run_fut(DoStuff::new()); +}