diff options
665 files changed, 7016 insertions, 3388 deletions
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml new file mode 100644 index 00000000000..d3f42c5a905 --- /dev/null +++ b/.github/workflows/post-merge.yml @@ -0,0 +1,36 @@ +# Workflow that runs after a merge to master, analyses changes in test executions +# and posts the result to the merged PR. + +name: Post merge analysis + +on: + push: + branches: + - master + +jobs: + analysis: + runs-on: ubuntu-24.04 + if: github.repository == 'rust-lang/rust' + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Perform analysis and send PR + run: | + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1` + + # Find PR for the current commit + HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + + echo "Parent: ${PARENT_COMMIT}" + echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" + + cd src/ci/citool + + echo "Post-merge analysis result" > output.log + cargo run --release post-merge-analysis ${PARENT_COMMIT} ${{ github.sha }} >> output.log + cat output.log + + gh pr comment ${HEAD_PR} -F output.log diff --git a/Cargo.lock b/Cargo.lock index 72f2d4f6cd3..ea93fbd01f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2527,6 +2527,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2871,11 +2881,11 @@ dependencies = [ [[package]] name = "rand_xoshiro" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.0", ] [[package]] @@ -3050,6 +3060,7 @@ dependencies = [ "gimli 0.31.1", "libc", "object 0.36.7", + "os_pipe", "regex", "serde_json", "similar", @@ -3144,7 +3155,7 @@ name = "rustc_abi" version = "0.0.0" dependencies = [ "bitflags", - "rand 0.8.5", + "rand 0.9.0", "rand_xoshiro", "rustc_data_structures", "rustc_hashes", @@ -3286,6 +3297,7 @@ dependencies = [ "rustc_hir", "rustc_lexer", "rustc_macros", + "rustc_middle", "rustc_serialize", "rustc_session", "rustc_span", @@ -3741,7 +3753,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_hir", "rustc_span", ] @@ -3777,7 +3789,7 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand 0.8.5", + "rand 0.9.0", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4009,7 +4021,8 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", + "rustc_ast_ir", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_messages", "rustc_errors", @@ -5163,8 +5176,8 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.0", + "rand_chacha 0.9.0", "rayon", ] @@ -5260,6 +5273,7 @@ dependencies = [ "serde", "similar", "termcolor", + "toml 0.7.8", "walkdir", ] diff --git a/Cargo.toml b/Cargo.toml index 20a43aaaeeb..e2d032e0806 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,20 @@ exclude = [ "src/tools/x", ] +# These lints are applied to many crates in the workspace. In practice, this is +# all crates under `compiler/`. +# +# NOTE: rustc-specific lints (e.g. `rustc::internal`) aren't supported by +# Cargo. (Support for them is possibly blocked by #44690 (attributes for +# tools).) Those lints are instead specified for `compiler/` crates in +# `src/bootstrap/src/core/builder/cargo.rs`. +[workspace.lints.rust] +# FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all of the +# individual lints are satisfied. +keyword_idents_2024 = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" + [profile.release.package.rustc-rayon-core] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index f4caa3ef769..7af0b34d2da 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -32,3 +32,6 @@ llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts'] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 86dc84e2016..9cb6619adc9 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -6,13 +6,13 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rand = { version = "0.8.4", default-features = false, optional = true } -rand_xoshiro = { version = "0.6.0", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rand = { version = "0.9.0", default-features = false, optional = true } +rand_xoshiro = { version = "0.7.0", optional = true } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" # tidy-alphabetical-end @@ -31,3 +31,6 @@ nightly = [ ] randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index d3ae6a29f10..7bffeaf4cc9 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -4,6 +4,7 @@ use std::{cmp, iter}; use rustc_hashes::Hash64; use rustc_index::Idx; +use rustc_index::bit_set::BitMatrix; use tracing::debug; use crate::{ @@ -12,6 +13,9 @@ use crate::{ Variants, WrappingRange, }; +mod coroutine; +mod simple; + #[cfg(feature = "nightly")] mod ty; @@ -60,17 +64,28 @@ pub enum LayoutCalculatorError<F> { /// The fields or variants have irreconcilable reprs ReprConflict, + + /// The length of an SIMD type is zero + ZeroLengthSimdType, + + /// The length of an SIMD type exceeds the maximum number of lanes + OversizedSimdType { max_lanes: u64 }, + + /// An element type of an SIMD type isn't a primitive + NonPrimitiveSimdType(F), } impl<F> LayoutCalculatorError<F> { pub fn without_payload(&self) -> LayoutCalculatorError<()> { - match self { - LayoutCalculatorError::UnexpectedUnsized(_) => { - LayoutCalculatorError::UnexpectedUnsized(()) - } - LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow, - LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion, - LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict, + use LayoutCalculatorError::*; + match *self { + UnexpectedUnsized(_) => UnexpectedUnsized(()), + SizeOverflow => SizeOverflow, + EmptyUnion => EmptyUnion, + ReprConflict => ReprConflict, + ZeroLengthSimdType => ZeroLengthSimdType, + OversizedSimdType { max_lanes } => OversizedSimdType { max_lanes }, + NonPrimitiveSimdType(_) => NonPrimitiveSimdType(()), } } @@ -78,13 +93,15 @@ impl<F> LayoutCalculatorError<F> { /// /// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra. pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use LayoutCalculatorError::*; f.write_str(match self { - LayoutCalculatorError::UnexpectedUnsized(_) => { - "an unsized type was found where a sized type was expected" + UnexpectedUnsized(_) => "an unsized type was found where a sized type was expected", + SizeOverflow => "size overflow", + EmptyUnion => "type is a union with no fields", + ReprConflict => "type has an invalid repr", + ZeroLengthSimdType | OversizedSimdType { .. } | NonPrimitiveSimdType(_) => { + "invalid simd type definition" } - LayoutCalculatorError::SizeOverflow => "size overflow", - LayoutCalculatorError::EmptyUnion => "type is a union with no fields", - LayoutCalculatorError::ReprConflict => "type has an invalid repr", }) } } @@ -102,41 +119,115 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Self { cx } } - pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>( + pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>( &self, - a: Scalar, - b: Scalar, - ) -> LayoutData<FieldIdx, VariantIdx> { - let dl = self.cx.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); + element: &LayoutData<FieldIdx, VariantIdx>, + count_if_sized: Option<u64>, // None for slices + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + let count = count_if_sized.unwrap_or(0); + let size = + element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?; - // HACK(nox): We iter on `b` and then `a` because `max_by_key` - // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b) - .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a)) - .max_by_key(|niche| niche.available(dl)); + Ok(LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Array { stride: element.size, count }, + backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() }, + largest_niche: element.largest_niche.filter(|_| count != 0), + uninhabited: element.uninhabited && count != 0, + align: element.align, + size, + max_repr_align: None, + unadjusted_abi_align: element.align.abi, + randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } - let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes()); + pub fn simd_type< + FieldIdx: Idx, + VariantIdx: Idx, + F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, + >( + &self, + element: F, + count: u64, + repr_packed: bool, + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + let elt = element.as_ref(); + if count == 0 { + return Err(LayoutCalculatorError::ZeroLengthSimdType); + } else if count > crate::MAX_SIMD_LANES { + return Err(LayoutCalculatorError::OversizedSimdType { + max_lanes: crate::MAX_SIMD_LANES, + }); + } - LayoutData { + let BackendRepr::Scalar(e_repr) = elt.backend_repr else { + return Err(LayoutCalculatorError::NonPrimitiveSimdType(element)); + }; + + // Compute the size and alignment of the vector + let dl = self.cx.data_layout(); + let size = + elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let (repr, align) = if repr_packed && !count.is_power_of_two() { + // Non-power-of-two vectors have padding up to the next power-of-two. + // If we're a packed repr, remove the padding while keeping the alignment as close + // to a vector as possible. + ( + BackendRepr::Memory { sized: true }, + AbiAndPrefAlign { + abi: Align::max_aligned_factor(size), + pref: dl.llvmlike_vector_align(size).pref, + }, + ) + } else { + (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) + }; + let size = size.align_to(align.abi); + + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO, b_offset].into(), - memory_index: [0, 1].into(), + offsets: [Size::ZERO].into(), + memory_index: [0].into(), }, - backend_repr: BackendRepr::ScalarPair(a, b), - largest_niche, + backend_repr: repr, + largest_niche: elt.largest_niche, uninhabited: false, - align, size, + align, max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::new(combined_seed), - } + unadjusted_abi_align: elt.align.abi, + randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } + + /// Compute the layout for a coroutine. + /// + /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine + /// fields may be shared between multiple variants (see the [`coroutine`] module for details). + pub fn coroutine< + 'a, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, + >( + &self, + local_layouts: &IndexSlice<LocalIdx, F>, + prefix_layouts: IndexVec<FieldIdx, F>, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, + tag_to_layout: impl Fn(Scalar) -> F, + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + coroutine::layout( + self, + local_layouts, + prefix_layouts, + variant_fields, + storage_conflicts, + tag_to_layout, + ) } pub fn univariant< @@ -214,25 +305,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { layout } - pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>( - &self, - ) -> LayoutData<FieldIdx, VariantIdx> { - let dl = self.cx.data_layout(); - // This is also used for uninhabited enums, so we use `Variants::Empty`. - LayoutData { - variants: Variants::Empty, - fields: FieldsShape::Primitive, - backend_repr: BackendRepr::Memory { sized: true }, - largest_niche: None, - uninhabited: true, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - randomization_seed: Hash64::ZERO, - } - } - pub fn layout_of_struct_or_enum< 'a, FieldIdx: Idx, @@ -260,7 +332,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if is_enum => { - return Ok(self.layout_of_never_type()); + return Ok(LayoutData::never_type(&self.cx)); } // If it's a struct, still compute a layout so that we can still compute the // field offsets. @@ -949,7 +1021,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Common prim might be uninit. Scalar::Union { value: prim } }; - let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar); + let pair = + LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); @@ -1341,7 +1414,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } else { ((j, b), (i, a)) }; - let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b); + let pair = + LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs new file mode 100644 index 00000000000..27e704d538c --- /dev/null +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -0,0 +1,320 @@ +//! Coroutine layout logic. +//! +//! When laying out coroutines, we divide our saved local fields into two +//! categories: overlap-eligible and overlap-ineligible. +//! +//! Those fields which are ineligible for overlap go in a "prefix" at the +//! beginning of the layout, and always have space reserved for them. +//! +//! Overlap-eligible fields are only assigned to one variant, so we lay +//! those fields out for each variant and put them right after the +//! prefix. +//! +//! Finally, in the layout details, we point to the fields from the +//! variants they are assigned to. It is possible for some fields to be +//! included in multiple variants. No field ever "moves around" in the +//! layout; its offset is always the same. +//! +//! Also included in the layout are the upvars and the discriminant. +//! These are included as fields on the "outer" layout; they are not part +//! of any variant. + +use std::iter; + +use rustc_index::bit_set::{BitMatrix, DenseBitSet}; +use rustc_index::{Idx, IndexSlice, IndexVec}; +use tracing::{debug, trace}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutData, Primitive, ReprOptions, Scalar, + StructKind, TagEncoding, Variants, WrappingRange, +}; + +/// Overlap eligibility and variant assignment for each CoroutineSavedLocal. +#[derive(Clone, Debug, PartialEq)] +enum SavedLocalEligibility<VariantIdx, FieldIdx> { + Unassigned, + Assigned(VariantIdx), + Ineligible(Option<FieldIdx>), +} + +/// Compute the eligibility and assignment of each local. +fn coroutine_saved_local_eligibility<VariantIdx: Idx, FieldIdx: Idx, LocalIdx: Idx>( + nb_locals: usize, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, +) -> (DenseBitSet<LocalIdx>, IndexVec<LocalIdx, SavedLocalEligibility<VariantIdx, FieldIdx>>) { + use SavedLocalEligibility::*; + + let mut assignments: IndexVec<LocalIdx, _> = IndexVec::from_elem_n(Unassigned, nb_locals); + + // The saved locals not eligible for overlap. These will get + // "promoted" to the prefix of our coroutine. + let mut ineligible_locals = DenseBitSet::new_empty(nb_locals); + + // Figure out which of our saved locals are fields in only + // one variant. The rest are deemed ineligible for overlap. + for (variant_index, fields) in variant_fields.iter_enumerated() { + for local in fields { + match assignments[*local] { + Unassigned => { + assignments[*local] = Assigned(variant_index); + } + Assigned(idx) => { + // We've already seen this local at another suspension + // point, so it is no longer a candidate. + trace!( + "removing local {:?} in >1 variant ({:?}, {:?})", + local, variant_index, idx + ); + ineligible_locals.insert(*local); + assignments[*local] = Ineligible(None); + } + Ineligible(_) => {} + } + } + } + + // Next, check every pair of eligible locals to see if they + // conflict. + for local_a in storage_conflicts.rows() { + let conflicts_a = storage_conflicts.count(local_a); + if ineligible_locals.contains(local_a) { + continue; + } + + for local_b in storage_conflicts.iter(local_a) { + // local_a and local_b are storage live at the same time, therefore they + // cannot overlap in the coroutine layout. The only way to guarantee + // this is if they are in the same variant, or one is ineligible + // (which means it is stored in every variant). + if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] { + continue; + } + + // If they conflict, we will choose one to make ineligible. + // This is not always optimal; it's just a greedy heuristic that + // seems to produce good results most of the time. + let conflicts_b = storage_conflicts.count(local_b); + let (remove, other) = + if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; + ineligible_locals.insert(remove); + assignments[remove] = Ineligible(None); + trace!("removing local {:?} due to conflict with {:?}", remove, other); + } + } + + // Count the number of variants in use. If only one of them, then it is + // impossible to overlap any locals in our layout. In this case it's + // always better to make the remaining locals ineligible, so we can + // lay them out with the other locals in the prefix and eliminate + // unnecessary padding bytes. + { + let mut used_variants = DenseBitSet::new_empty(variant_fields.len()); + for assignment in &assignments { + if let Assigned(idx) = assignment { + used_variants.insert(*idx); + } + } + if used_variants.count() < 2 { + for assignment in assignments.iter_mut() { + *assignment = Ineligible(None); + } + ineligible_locals.insert_all(); + } + } + + // Write down the order of our locals that will be promoted to the prefix. + { + for (idx, local) in ineligible_locals.iter().enumerate() { + assignments[local] = Ineligible(Some(FieldIdx::new(idx))); + } + } + debug!("coroutine saved local assignments: {:?}", assignments); + + (ineligible_locals, assignments) +} + +/// Compute the full coroutine layout. +pub(super) fn layout< + 'a, + F: core::ops::Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + core::fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, +>( + calc: &super::LayoutCalculator<impl HasDataLayout>, + local_layouts: &IndexSlice<LocalIdx, F>, + mut prefix_layouts: IndexVec<FieldIdx, F>, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, + tag_to_layout: impl Fn(Scalar) -> F, +) -> super::LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + use SavedLocalEligibility::*; + + let (ineligible_locals, assignments) = + coroutine_saved_local_eligibility(local_layouts.len(), variant_fields, storage_conflicts); + + // Build a prefix layout, including "promoting" all ineligible + // locals as part of the prefix. We compute the layout of all of + // these fields at once to get optimal packing. + let tag_index = prefix_layouts.len(); + + // `variant_fields` already accounts for the reserved variants, so no need to add them. + let max_discr = (variant_fields.len() - 1) as u128; + let discr_int = Integer::fit_unsigned(max_discr); + let tag = Scalar::Initialized { + value: Primitive::Int(discr_int, /* signed = */ false), + valid_range: WrappingRange { start: 0, end: max_discr }, + }; + + let promoted_layouts = ineligible_locals.iter().map(|local| local_layouts[local]); + prefix_layouts.push(tag_to_layout(tag)); + prefix_layouts.extend(promoted_layouts); + let prefix = + calc.univariant(&prefix_layouts, &ReprOptions::default(), StructKind::AlwaysSized)?; + + let (prefix_size, prefix_align) = (prefix.size, prefix.align); + + // Split the prefix layout into the "outer" fields (upvars and + // discriminant) and the "promoted" fields. Promoted fields will + // get included in each variant that requested them in + // CoroutineLayout. + debug!("prefix = {:#?}", prefix); + let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { + FieldsShape::Arbitrary { mut offsets, memory_index } => { + let mut inverse_memory_index = memory_index.invert_bijective_mapping(); + + // "a" (`0..b_start`) and "b" (`b_start..`) correspond to + // "outer" and "promoted" fields respectively. + let b_start = FieldIdx::new(tag_index + 1); + let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index())); + let offsets_a = offsets; + + // Disentangle the "a" and "b" components of `inverse_memory_index` + // by preserving the order but keeping only one disjoint "half" each. + // FIXME(eddyb) build a better abstraction for permutations, if possible. + let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index + .iter() + .filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new)) + .collect(); + inverse_memory_index.raw.retain(|&i| i.index() < b_start.index()); + let inverse_memory_index_a = inverse_memory_index; + + // Since `inverse_memory_index_{a,b}` each only refer to their + // respective fields, they can be safely inverted + let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); + let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); + + let outer_fields = + FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; + (outer_fields, offsets_b, memory_index_b) + } + _ => unreachable!(), + }; + + let mut size = prefix.size; + let mut align = prefix.align; + let variants = variant_fields + .iter_enumerated() + .map(|(index, variant_fields)| { + // Only include overlap-eligible fields when we compute our variant layout. + let variant_only_tys = variant_fields + .iter() + .filter(|local| match assignments[**local] { + Unassigned => unreachable!(), + Assigned(v) if v == index => true, + Assigned(_) => unreachable!("assignment does not match variant"), + Ineligible(_) => false, + }) + .map(|local| local_layouts[*local]); + + let mut variant = calc.univariant( + &variant_only_tys.collect::<IndexVec<_, _>>(), + &ReprOptions::default(), + StructKind::Prefixed(prefix_size, prefix_align.abi), + )?; + variant.variants = Variants::Single { index }; + + let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { + unreachable!(); + }; + + // Now, stitch the promoted and variant-only fields back together in + // the order they are mentioned by our CoroutineLayout. + // Because we only use some subset (that can differ between variants) + // of the promoted fields, we can't just pick those elements of the + // `promoted_memory_index` (as we'd end up with gaps). + // So instead, we build an "inverse memory_index", as if all of the + // promoted fields were being used, but leave the elements not in the + // subset as `invalid_field_idx`, which we can filter out later to + // obtain a valid (bijective) mapping. + let invalid_field_idx = promoted_memory_index.len() + memory_index.len(); + let mut combined_inverse_memory_index = + IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx); + + let mut offsets_and_memory_index = iter::zip(offsets, memory_index); + let combined_offsets = variant_fields + .iter_enumerated() + .map(|(i, local)| { + let (offset, memory_index) = match assignments[*local] { + Unassigned => unreachable!(), + Assigned(_) => { + let (offset, memory_index) = offsets_and_memory_index.next().unwrap(); + (offset, promoted_memory_index.len() as u32 + memory_index) + } + Ineligible(field_idx) => { + let field_idx = field_idx.unwrap(); + (promoted_offsets[field_idx], promoted_memory_index[field_idx]) + } + }; + combined_inverse_memory_index[memory_index] = i; + offset + }) + .collect(); + + // Remove the unused slots and invert the mapping to obtain the + // combined `memory_index` (also see previous comment). + combined_inverse_memory_index.raw.retain(|&i| i.index() != invalid_field_idx); + let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); + + variant.fields = FieldsShape::Arbitrary { + offsets: combined_offsets, + memory_index: combined_memory_index, + }; + + size = size.max(variant.size); + align = align.max(variant.align); + Ok(variant) + }) + .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; + + size = size.align_to(align.abi); + + let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); + let abi = BackendRepr::Memory { sized: true }; + + Ok(LayoutData { + variants: Variants::Multiple { + tag, + tag_encoding: TagEncoding::Direct, + tag_field: tag_index, + variants, + }, + fields: outer_fields, + backend_repr: abi, + // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to + // self-referentiality), getting the discriminant can cause aliasing violations. + // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that + // would do the same for us here. + // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>. + // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. + largest_niche: None, + uninhabited, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Default::default(), + }) +} diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs new file mode 100644 index 00000000000..0d0706defc2 --- /dev/null +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -0,0 +1,148 @@ +use std::num::NonZero; + +use rustc_hashes::Hash64; +use rustc_index::{Idx, IndexVec}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants, +}; + +/// "Simple" layout constructors that cannot fail. +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { + pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + backend_repr: BackendRepr::Memory { sized }, + largest_niche: None, + uninhabited: false, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::new(0), + } + } + + pub fn never_type<C: HasDataLayout>(cx: &C) -> Self { + let dl = cx.data_layout(); + // This is also used for uninhabited enums, so we use `Variants::Empty`. + LayoutData { + variants: Variants::Empty, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } + + pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { + let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); + let size = scalar.size(cx); + let align = scalar.align(cx); + + let range = scalar.valid_range(cx); + + // All primitive types for which we don't have subtype coercions should get a distinct seed, + // so that types wrapping them can use randomization to arrive at distinct layouts. + // + // Some type information is already lost at this point, so as an approximation we derive + // the seed from what remains. For example on 64-bit targets usize and u64 can no longer + // be distinguished. + let randomization_seed = size + .bytes() + .wrapping_add( + match scalar.primitive() { + Primitive::Int(_, true) => 1, + Primitive::Int(_, false) => 2, + Primitive::Float(_) => 3, + Primitive::Pointer(_) => 4, + } << 32, + ) + // distinguishes references from pointers + .wrapping_add((range.start as u64).rotate_right(16)) + // distinguishes char from u32 and bool from u8 + .wrapping_add((range.end as u64).rotate_right(16)); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Scalar(scalar), + largest_niche, + uninhabited: false, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(randomization_seed), + } + } + + pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self { + let dl = cx.data_layout(); + let b_align = b.align(dl); + let align = a.align(dl).max(b_align).max(dl.aggregate_align); + let b_offset = a.size(dl).align_to(b_align.abi); + let size = (b_offset + b.size(dl)).align_to(align.abi); + + // HACK(nox): We iter on `b` and then `a` because `max_by_key` + // returns the last maximum. + let largest_niche = Niche::from_scalar(dl, b_offset, b) + .into_iter() + .chain(Niche::from_scalar(dl, Size::ZERO, a)) + .max_by_key(|niche| niche.available(dl)); + + let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes()); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO, b_offset].into(), + memory_index: [0, 1].into(), + }, + backend_repr: BackendRepr::ScalarPair(a, b), + largest_niche, + uninhabited: false, + align, + size, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(combined_seed), + } + } + + /// Returns a dummy layout for an uninhabited variant. + /// + /// Uninhabited variants get pruned as part of the layout calculation, + /// so this can be used after the fact to reconstitute a layout. + pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index }, + fields: match NonZero::new(fields) { + Some(fields) => FieldsShape::Union(fields), + None => FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + }, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } +} diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 03f3f043c21..4f43c0e6f8e 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -150,6 +150,12 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { } } +impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> { + fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> { + &*self.layout.0.0 + } +} + /// Trait that needs to be implemented by the higher-level type representation /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality. pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index a59dc870aa3..078b676e40e 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -5,7 +5,6 @@ #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] -#![warn(unreachable_pub)] // tidy-alphabetical-end /*! ABI handling for rustc @@ -205,6 +204,13 @@ impl ReprOptions { } } +/// The maximum supported number of lanes in a SIMD vector. +/// +/// This value is selected based on backend support: +/// * LLVM does not appear to have a vector width limit. +/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. +pub const MAX_SIMD_LANES: u64 = 1 << 0xF; + /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. #[derive(Debug, PartialEq, Eq)] @@ -1744,48 +1750,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { pub fn is_uninhabited(&self) -> bool { self.uninhabited } - - pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { - let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); - let size = scalar.size(cx); - let align = scalar.align(cx); - - let range = scalar.valid_range(cx); - - // All primitive types for which we don't have subtype coercions should get a distinct seed, - // so that types wrapping them can use randomization to arrive at distinct layouts. - // - // Some type information is already lost at this point, so as an approximation we derive - // the seed from what remains. For example on 64-bit targets usize and u64 can no longer - // be distinguished. - let randomization_seed = size - .bytes() - .wrapping_add( - match scalar.primitive() { - Primitive::Int(_, true) => 1, - Primitive::Int(_, false) => 2, - Primitive::Float(_) => 3, - Primitive::Pointer(_) => 4, - } << 32, - ) - // distinguishes references from pointers - .wrapping_add((range.start as u64).rotate_right(16)) - // distinguishes char from u32 and bool from u8 - .wrapping_add((range.end as u64).rotate_right(16)); - - LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - backend_repr: BackendRepr::Scalar(scalar), - largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::new(randomization_seed), - } - } } impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx> diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index bbcd8ea6d38..1a600f0ee3f 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -7,3 +7,6 @@ edition = "2024" # tidy-alphabetical-start smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index b21ccba93bb..6aaac072e4b 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -23,7 +23,6 @@ #![feature(maybe_uninit_slice)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::alloc::Layout; @@ -93,7 +92,7 @@ impl<T> ArenaChunk<T> { #[inline] fn end(&mut self) -> *mut T { unsafe { - if mem::size_of::<T>() == 0 { + if size_of::<T>() == 0 { // A pointer as large as possible for zero-sized elements. ptr::without_provenance_mut(!0) } else { @@ -151,7 +150,7 @@ impl<T> TypedArena<T> { } unsafe { - if mem::size_of::<T>() == 0 { + if size_of::<T>() == 0 { self.ptr.set(self.ptr.get().wrapping_byte_add(1)); let ptr = ptr::NonNull::<T>::dangling().as_ptr(); // Don't drop the object. This `write` is equivalent to `forget`. @@ -173,13 +172,13 @@ impl<T> TypedArena<T> { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let available_bytes = self.end.get().addr() - self.ptr.get().addr(); - let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap(); + let additional_bytes = additional.checked_mul(size_of::<T>()).unwrap(); available_bytes >= additional_bytes } #[inline] fn alloc_raw_slice(&self, len: usize) -> *mut T { - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(len != 0); // Ensure the current chunk can fit `len` objects. @@ -213,7 +212,7 @@ impl<T> TypedArena<T> { // So we collect all the elements beforehand, which takes care of reentrancy and panic // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it // doesn't need to be hyper-optimized. - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); if vec.is_empty() { @@ -236,7 +235,7 @@ impl<T> TypedArena<T> { unsafe { // We need the element size to convert chunk sizes (ranging from // PAGE to HUGE_PAGE bytes) to element counts. - let elem_size = cmp::max(1, mem::size_of::<T>()); + let elem_size = cmp::max(1, size_of::<T>()); let mut chunks = self.chunks.borrow_mut(); let mut new_cap; if let Some(last_chunk) = chunks.last_mut() { @@ -246,7 +245,7 @@ impl<T> TypedArena<T> { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let used_bytes = self.ptr.get().addr() - last_chunk.start().addr(); - last_chunk.entries = used_bytes / mem::size_of::<T>(); + last_chunk.entries = used_bytes / size_of::<T>(); } // If the previous chunk's len is less than HUGE_PAGE @@ -276,7 +275,7 @@ impl<T> TypedArena<T> { let end = self.ptr.get().addr(); // We then calculate the number of elements to be dropped in the last chunk, // which is the filled area's length. - let diff = if mem::size_of::<T>() == 0 { + let diff = if size_of::<T>() == 0 { // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get // the number of zero-sized values in the last and only chunk, just out of caution. // Recall that `end` was incremented for each allocated value. @@ -284,7 +283,7 @@ impl<T> TypedArena<T> { } else { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). - (end - start) / mem::size_of::<T>() + (end - start) / size_of::<T>() }; // Pass that to the `destroy` method. unsafe { @@ -329,7 +328,7 @@ fn align_up(val: usize, align: usize) -> usize { // Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them // to optimize away alignment code. -const DROPLESS_ALIGNMENT: usize = mem::align_of::<usize>(); +const DROPLESS_ALIGNMENT: usize = align_of::<usize>(); /// An arena that can hold objects of multiple different types that impl `Copy` /// and/or satisfy `!mem::needs_drop`. @@ -447,7 +446,7 @@ impl DroplessArena { #[inline] pub fn alloc<T>(&self, object: T) -> &mut T { assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); let mem = self.alloc_raw(Layout::new::<T>()) as *mut T; @@ -471,7 +470,7 @@ impl DroplessArena { T: Copy, { assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(!slice.is_empty()); let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; @@ -546,7 +545,7 @@ impl DroplessArena { // Warning: this function is reentrant: `iter` could hold a reference to `&self` and // allocate additional elements while we're iterating. let iter = iter.into_iter(); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(!mem::needs_drop::<T>()); let size_hint = iter.size_hint(); diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 902287d0328..259b51689e4 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -18,3 +18,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 11fc409cf43..002435b2d03 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1399,6 +1399,7 @@ impl Expr { // Never need parens ExprKind::Array(_) | ExprKind::Await(..) + | ExprKind::Use(..) | ExprKind::Block(..) | ExprKind::Call(..) | ExprKind::ConstBlock(_) @@ -1588,6 +1589,8 @@ pub enum ExprKind { Gen(CaptureBy, P<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P<Expr>, Span), + /// A use expression (`x.use`). Span is of use keyword. + Use(P<Expr>, Span), /// A try block (`try { ... }`). TryBlock(P<Block>), @@ -1757,8 +1760,17 @@ pub enum CaptureBy { /// The span of the `move` keyword. move_kw: Span, }, - /// `move` keyword was not specified. + /// `move` or `use` keywords were not specified. Ref, + /// `use |x| y + x`. + /// + /// Note that if you have a regular closure like `|| x.use`, this will *not* result + /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type + /// of `x` and treat `x.use` as either a copy/clone/move as appropriate. + Use { + /// The span of the `use` keyword. + use_kw: Span, + }, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 6372c66050e..294c6c9ba7a 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -19,7 +19,6 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod util { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f14646b5a99..ee894db7b96 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1745,6 +1745,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_expr(expr); vis.visit_span(await_kw_span); } + ExprKind::Use(expr, use_kw_span) => { + vis.visit_expr(expr); + vis.visit_span(use_kw_span); + } ExprKind::Assign(el, er, span) => { vis.visit_expr(el); vis.visit_expr(er); @@ -1895,6 +1899,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) { CaptureBy::Value { move_kw } => { vis.visit_span(move_kw); } + CaptureBy::Use { use_kw } => { + vis.visit_span(use_kw); + } } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 64f2a98b8a6..e43d78f6e72 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { Assign(e, _, _) | AssignOp(_, e, _) | Await(e, _) + | Use(e, _) | Binary(_, e, _) | Call(e, _) | Cast(e, _) @@ -224,6 +225,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { | Lit(_) | Type(_, _) | Await(_, _) + | Use(_, _) | Field(_, _) | Index(_, _, _) | Underscore diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37139e664f3..43ffbe9b071 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1211,6 +1211,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), + ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)), ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); try_visit!(visitor.visit_expr(rhs)); diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index f54e9687d8c..668c45438d6 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -19,3 +19,6 @@ nightly = [ "dep:rustc_macros", "dep:rustc_span", ] + +[lints] +workspace = true diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 9884e191ea7..6d05cd18cec 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -9,7 +9,6 @@ #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(never_type))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[cfg(feature = "nightly")] diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 2ec4f4b0555..358963c7997 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -28,3 +28,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c70fcdc84a3..acf35b75e4d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,7 +13,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; @@ -207,6 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), + ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), ExprKind::Closure(box Closure { binder, capture_clause, @@ -483,7 +484,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); + self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { AstP(Expr { @@ -1067,6 +1068,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + hir::ExprKind::Use(self.lower_expr(expr), use_kw_span) + } + fn lower_expr_closure( &mut self, binder: &ClosureBinder, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f5832068028..4cecc56909e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -38,7 +38,6 @@ #![feature(if_let_guard)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::sync::Arc; @@ -494,7 +493,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -774,7 +773,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let _def_id = self.create_def( self.current_hir_id_owner.def_id, param, - kw::UnderscoreLifetime, + Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, ident.span, ); @@ -2089,8 +2088,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 728981dea5f..07cc64a1358 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, LangItem}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DesugaringKind, Ident, Span, kw}; +use rustc_span::{DesugaringKind, Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -523,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're generating a range end that didn't exist in the AST, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let unstable_span = self.mark_span_with_reason( diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index c738cb2aa2f..5966308a262 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -20,3 +20,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index de11fe770c5..31ff102c127 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -489,6 +489,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); + gate_all!(ergonomic_clones, "ergonomic clones are experimental"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index b4ed70d83e5..093199cf342 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -10,7 +10,6 @@ #![feature(iter_is_partitioned)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod ast_validation; diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 2634dd1fdf9..b120bdc2f05 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -12,3 +12,6 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 602ab69ee5b..84d9ce278a2 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -3,7 +3,6 @@ #![doc(rust_logo)] #![feature(box_patterns)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod helpers; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 496323a35b8..e3c41f117ab 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -574,6 +574,14 @@ impl<'a> State<'a> { ); self.word(".await"); } + ast::ExprKind::Use(expr, _) => { + self.print_expr_cond_paren( + expr, + expr.precedence() < ExprPrecedence::Unambiguous, + fixup, + ); + self.word(".use"); + } ast::ExprKind::Assign(lhs, rhs, _) => { self.print_expr_cond_paren( lhs, @@ -885,6 +893,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { match capture_clause { ast::CaptureBy::Value { .. } => self.word_space("move"), + ast::CaptureBy::Use { .. } => self.word_space("use"), ast::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml index b18923c337f..8fbc21f3ba2 100644 --- a/compiler/rustc_attr_data_structures/Cargo.toml +++ b/compiler/rustc_attr_data_structures/Cargo.toml @@ -14,3 +14,6 @@ rustc_serialize = {path = "../rustc_serialize"} rustc_span = {path = "../rustc_span"} thin-vec = "0.2.12" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index e4bb459e6df..be00d1c10e0 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -3,7 +3,6 @@ #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod attributes; @@ -149,3 +148,47 @@ print_tup!(A B C D E F G H); print_skip!(Span, ()); print_disp!(Symbol, u16, bool, NonZero<u32>); print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); + +/// Finds attributes in sequences of attributes by pattern matching. +/// +/// A little like `matches` but for attributes. +/// +/// ```rust,ignore (illustrative) +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, AttributeKind::Repr(_)) { +/// +/// } +/// ``` +/// +/// Often this requires you to first end up with a list of attributes. +/// A common way to get those is through `tcx.get_all_attrs(did)` +#[macro_export] +macro_rules! find_attr { + ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ + $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() + }}; + + ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {} + check_attribute_iterator(&$attributes_list); + + let find_attribute = |iter| { + for i in $attributes_list { + match i { + rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { + return Some($e); + } + _ => {} + } + } + + None + }; + find_attribute($attributes_list) + }}; +} diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index c335eeb5f71..24b552e2de4 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -16,8 +16,12 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 9841166b37d..249e71ef70d 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -80,7 +80,6 @@ #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[macro_use] @@ -95,47 +94,3 @@ pub use context::{AttributeParser, OmitDoc}; pub use rustc_attr_data_structures::*; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -/// Finds attributes in sequences of attributes by pattern matching. -/// -/// A little like `matches` but for attributes. -/// -/// ```rust,ignore (illustrative) -/// // finds the repr attribute -/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { -/// -/// } -/// -/// // checks if one has matched -/// if find_attr!(attrs, AttributeKind::Repr(_)) { -/// -/// } -/// ``` -/// -/// Often this requires you to first end up with a list of attributes. -/// A common way to get those is through `tcx.get_all_attrs(did)` -#[macro_export] -macro_rules! find_attr { - ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ - $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() - }}; - - ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {} - check_attribute_iterator(&$attributes_list); - - let find_attribute = |iter| { - for i in $attributes_list { - match i { - rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { - return Some($e); - } - _ => {} - } - } - - None - }; - find_attribute($attributes_list) - }}; -} diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml index cb0e145386b..1480b59f1e0 100644 --- a/compiler/rustc_baked_icu_data/Cargo.toml +++ b/compiler/rustc_baked_icu_data/Cargo.toml @@ -11,3 +11,6 @@ icu_locid_transform = "1.3.2" icu_provider = { version = "1.2", features = ["sync"] } zerovec = "0.10.0" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index f86a9db61c6..df9bee0ebf5 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -23,9 +23,9 @@ // tidy-alphabetical-start #![allow(elided_lifetimes_in_paths)] #![allow(internal_features)] +#![allow(unreachable_pub)] // because this crate is mostly generated code #![doc(rust_logo)] #![feature(rustdoc_internals)] -// #![warn(unreachable_pub)] // don't use because this crate is mostly generated code // tidy-alphabetical-end mod data { diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 9e7d55180a2..15338eeb37a 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -27,3 +27,6 @@ rustc_traits = { path = "../rustc_traits" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 30e94b0bec7..c9be5575da5 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { .expect_closure(); let span = match capture_clause { rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), + rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(), rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(), }; diag.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 9d500586f08..1209d8bf596 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -1,11 +1,8 @@ use rustc_data_structures::graph; use rustc_index::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::RegionVid; use crate::constraints::{OutlivesConstraint, OutlivesConstraintIndex, OutlivesConstraintSet}; -use crate::type_check::Locations; /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 @@ -23,8 +20,8 @@ pub(crate) type ReverseConstraintGraph = ConstraintGraph<Reverse>; /// Marker trait that controls whether a `R1: R2` constraint /// represents an edge `R1 -> R2` or `R2 -> R1`. pub(crate) trait ConstraintGraphDirection: Copy + 'static { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; + fn start_region(sup: RegionVid, sub: RegionVid) -> RegionVid; + fn end_region(sup: RegionVid, sub: RegionVid) -> RegionVid; fn is_normal() -> bool; } @@ -36,12 +33,12 @@ pub(crate) trait ConstraintGraphDirection: Copy + 'static { pub(crate) struct Normal; impl ConstraintGraphDirection for Normal { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup + fn start_region(sup: RegionVid, _sub: RegionVid) -> RegionVid { + sup } - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub + fn end_region(_sup: RegionVid, sub: RegionVid) -> RegionVid { + sub } fn is_normal() -> bool { @@ -57,12 +54,12 @@ impl ConstraintGraphDirection for Normal { pub(crate) struct Reverse; impl ConstraintGraphDirection for Reverse { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub + fn start_region(_sup: RegionVid, sub: RegionVid) -> RegionVid { + sub } - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup + fn end_region(sup: RegionVid, _sub: RegionVid) -> RegionVid { + sup } fn is_normal() -> bool { @@ -84,7 +81,7 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> { let mut next_constraints = IndexVec::from_elem(None, &set.outlives); for (idx, constraint) in set.outlives.iter_enumerated().rev() { - let head = &mut first_constraints[D::start_region(constraint)]; + let head = &mut first_constraints[D::start_region(constraint.sup, constraint.sub)]; let next = &mut next_constraints[idx]; debug_assert!(next.is_none()); *next = *head; @@ -105,63 +102,57 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> { RegionGraph::new(set, self, static_region) } + pub(crate) fn is_normal(&self) -> bool { + D::is_normal() + } + /// Given a region `R`, iterate over all constraints `R: R1`. - pub(crate) fn outgoing_edges<'a, 'tcx>( + pub(crate) fn outgoing_edges_from_graph<'a, 'tcx>( &'a self, region_sup: RegionVid, constraints: &'a OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> Edges<'a, 'tcx, D> { - //if this is the `'static` region and the graph's direction is normal, - //then setup the Edges iterator to return all regions #53178 - if region_sup == static_region && D::is_normal() { - Edges { - graph: self, - constraints, - pointer: None, - next_static_idx: Some(0), - static_region, - } - } else { - //otherwise, just setup the iterator as normal - let first = self.first_constraints[region_sup]; - Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region } - } + ) -> EdgesFromGraph<'a, 'tcx, D> { + EdgesFromGraph { graph: self, constraints, pointer: self.first_constraints[region_sup] } + } + + /// Returns all regions (#53178). + pub(crate) fn outgoing_edges_from_static(&self) -> EdgesFromStatic { + EdgesFromStatic { next_static_idx: 0, end_static_idx: self.first_constraints.len() } } } -pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> { +pub(crate) struct EdgesFromGraph<'a, 'tcx, D: ConstraintGraphDirection> { graph: &'a ConstraintGraph<D>, constraints: &'a OutlivesConstraintSet<'tcx>, pointer: Option<OutlivesConstraintIndex>, - next_static_idx: Option<usize>, - static_region: RegionVid, } -impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> { - type Item = OutlivesConstraint<'tcx>; +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for EdgesFromGraph<'a, 'tcx, D> { + type Item = &'a OutlivesConstraint<'tcx>; fn next(&mut self) -> Option<Self::Item> { if let Some(p) = self.pointer { self.pointer = self.graph.next_constraints[p]; + Some(&self.constraints[p]) + } else { + None + } + } +} + +pub(crate) struct EdgesFromStatic { + next_static_idx: usize, + end_static_idx: usize, +} + +impl Iterator for EdgesFromStatic { + type Item = RegionVid; - Some(self.constraints[p]) - } else if let Some(next_static_idx) = self.next_static_idx { - self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { - None - } else { - Some(next_static_idx + 1) - }; - - Some(OutlivesConstraint { - sup: self.static_region, - sub: next_static_idx.into(), - locations: Locations::All(DUMMY_SP), - span: DUMMY_SP, - category: ConstraintCategory::Internal, - variance_info: VarianceDiagInfo::default(), - from_closure: false, - }) + fn next(&mut self) -> Option<Self::Item> { + if self.next_static_idx < self.end_static_idx { + let ret = RegionVid::from_usize(self.next_static_idx); + self.next_static_idx += 1; + Some(ret) } else { None } @@ -193,21 +184,38 @@ impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> { - Successors { - edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), + // If this is the `'static` region and the graph's direction is normal, + // then setup the Edges iterator to return all regions (#53178). + if region_sup == self.static_region && D::is_normal() { + Successors::FromStatic(self.constraint_graph.outgoing_edges_from_static()) + } else { + // Otherwise, just setup the iterator as normal. + Successors::FromGraph( + self.constraint_graph.outgoing_edges_from_graph(region_sup, self.set), + ) } } } -pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> { - edges: Edges<'a, 'tcx, D>, +pub(crate) enum Successors<'a, 'tcx, D: ConstraintGraphDirection> { + FromStatic(EdgesFromStatic), + FromGraph(EdgesFromGraph<'a, 'tcx, D>), } impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option<Self::Item> { - self.edges.next().map(|c| D::end_region(&c)) + match self { + Successors::FromStatic(edges) => { + // No `D::end_region` call needed here: static successors are only possible when + // the direction is `Normal`, so we can directly use what would be the `sub` value. + edges.next() + } + Successors::FromGraph(edges) => { + edges.next().map(|constraint| D::end_region(constraint.sup, constraint.sub)) + } + } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index be4a7736b1c..145137f9236 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) => { capture_reason = format!("mutable borrow of `{upvar}`"); } - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { capture_reason = format!("possible mutation of `{upvar}`"); } _ => bug!("upvar `{upvar}` borrowed, but not mutably"), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 68e0ab0933e..4d3774682ce 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -13,7 +13,6 @@ #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; @@ -1490,14 +1489,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); - if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind - { - propagate_closure_used_mut_place(self, source); - } else { - bug!( - "closures should only capture user variables \ + match stmt.kind { + StatementKind::Assign(box ( + _, + Rvalue::Ref(_, _, source) + | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)), + )) => { + propagate_closure_used_mut_place(self, source); + } + _ => { + bug!( + "closures should only capture user variables \ or references to user variables" - ); + ); + } } } _ => propagate_closure_used_mut_place(self, place), diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index a00fce08c9b..bb209a95711 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -21,8 +21,8 @@ use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex}; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_span::Span; use rustc_span::hygiene::DesugaringKind; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; use crate::BorrowckInferCtxt; @@ -311,9 +311,11 @@ enum RegionRelationCheckResult { } #[derive(Clone, PartialEq, Eq, Debug)] -enum Trace<'tcx> { +enum Trace<'a, 'tcx> { StartRegion, - FromOutlivesConstraint(OutlivesConstraint<'tcx>), + FromGraph(&'a OutlivesConstraint<'tcx>), + FromStatic(RegionVid), + FromMember(RegionVid, RegionVid, Span), NotVisited, } @@ -1764,6 +1766,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); context[from_region] = Trace::StartRegion; + let fr_static = self.universal_regions().fr_static; + // Use a deque so that we do a breadth-first search. We will // stop at the first match, which ought to be the shortest // path (fewest constraints). @@ -1783,13 +1787,39 @@ impl<'tcx> RegionInferenceContext<'tcx> { if target_test(r) { let mut result = vec![]; let mut p = r; + // This loop is cold and runs at the end, which is why we delay + // `OutlivesConstraint` construction until now. loop { - match context[p].clone() { - Trace::NotVisited => { - bug!("found unvisited region {:?} on path to {:?}", p, r) + match context[p] { + Trace::FromGraph(c) => { + p = c.sup; + result.push(*c); } - Trace::FromOutlivesConstraint(c) => { + Trace::FromStatic(sub) => { + let c = OutlivesConstraint { + sup: fr_static, + sub, + locations: Locations::All(DUMMY_SP), + span: DUMMY_SP, + category: ConstraintCategory::Internal, + variance_info: ty::VarianceDiagInfo::default(), + from_closure: false, + }; + p = c.sup; + result.push(c); + } + + Trace::FromMember(sup, sub, span) => { + let c = OutlivesConstraint { + sup, + sub, + locations: Locations::All(span), + span, + category: ConstraintCategory::OpaqueType, + variance_info: ty::VarianceDiagInfo::default(), + from_closure: false, + }; p = c.sup; result.push(c); } @@ -1798,6 +1828,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { result.reverse(); return Some((result, r)); } + + Trace::NotVisited => { + bug!("found unvisited region {:?} on path to {:?}", p, r) + } } } } @@ -1808,45 +1842,42 @@ impl<'tcx> RegionInferenceContext<'tcx> { // A constraint like `'r: 'x` can come from our constraint // graph. - let fr_static = self.universal_regions().fr_static; - let outgoing_edges_from_graph = - self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); // Always inline this closure because it can be hot. - let mut handle_constraint = #[inline(always)] - |constraint: OutlivesConstraint<'tcx>| { - debug_assert_eq!(constraint.sup, r); - let sub_region = constraint.sub; - if let Trace::NotVisited = context[sub_region] { - context[sub_region] = Trace::FromOutlivesConstraint(constraint); - deque.push_back(sub_region); + let mut handle_trace = #[inline(always)] + |sub, trace| { + if let Trace::NotVisited = context[sub] { + context[sub] = trace; + deque.push_back(sub); } }; - // This loop can be hot. - for constraint in outgoing_edges_from_graph { - if matches!(constraint.category, ConstraintCategory::IllegalUniverse) { - debug!("Ignoring illegal universe constraint: {constraint:?}"); - continue; + // If this is the `'static` region and the graph's direction is normal, then set up the + // Edges iterator to return all regions (#53178). + if r == fr_static && self.constraint_graph.is_normal() { + for sub in self.constraint_graph.outgoing_edges_from_static() { + handle_trace(sub, Trace::FromStatic(sub)); + } + } else { + let edges = self.constraint_graph.outgoing_edges_from_graph(r, &self.constraints); + // This loop can be hot. + for constraint in edges { + if matches!(constraint.category, ConstraintCategory::IllegalUniverse) { + debug!("Ignoring illegal universe constraint: {constraint:?}"); + continue; + } + debug_assert_eq!(constraint.sup, r); + handle_trace(constraint.sub, Trace::FromGraph(constraint)); } - handle_constraint(constraint); } // Member constraints can also give rise to `'r: 'x` edges that // were not part of the graph initially, so watch out for those. // (But they are extremely rare; this loop is very cold.) for constraint in self.applied_member_constraints(self.constraint_sccs.scc(r)) { + let sub = constraint.min_choice; let p_c = &self.member_constraints[constraint.member_constraint_index]; - let constraint = OutlivesConstraint { - sup: r, - sub: constraint.min_choice, - locations: Locations::All(p_c.definition_span), - span: p_c.definition_span, - category: ConstraintCategory::OpaqueType, - variance_info: ty::VarianceDiagInfo::default(), - from_closure: false, - }; - handle_constraint(constraint); + handle_trace(sub, Trace::FromMember(r, sub, p_c.definition_span)); } } diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index b5f4f2efd1f..da3572eebee 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -3,10 +3,6 @@ name = "rustc_builtin_macros" version = "0.0.0" edition = "2024" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(llvm_enzyme)'] } - [lib] doctest = false @@ -34,3 +30,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index bb9dc651cec..a949ab94f3a 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::AssignOp(_, _, _) | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | ExprKind::Closure(_) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6d9c3575657..7b5c4a159b0 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -286,7 +286,7 @@ mod llvm_enzyme { let orig_annotatable: Annotatable = match item { Annotatable::Item(ref mut iitem) => { if !iitem.attrs.iter().any(|a| a.id == attr.id) { - iitem.attrs.push(attr.clone()); + iitem.attrs.push(attr); } if !iitem.attrs.iter().any(|a| a.id == inline_never.id) { iitem.attrs.push(inline_never.clone()); @@ -295,7 +295,7 @@ mod llvm_enzyme { } Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => { if !assoc_item.attrs.iter().any(|a| a.id == attr.id) { - assoc_item.attrs.push(attr.clone()); + assoc_item.attrs.push(attr); } if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) { assoc_item.attrs.push(inline_never.clone()); @@ -322,7 +322,7 @@ mod llvm_enzyme { let d_annotatable = if is_impl { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); let d_fn = P(ast::AssocItem { - attrs: thin_vec![d_attr.clone(), inline_never], + attrs: thin_vec![d_attr, inline_never], id: ast::DUMMY_NODE_ID, span, vis, @@ -332,12 +332,8 @@ mod llvm_enzyme { }); Annotatable::AssocItem(d_fn, Impl) } else { - let mut d_fn = ecx.item( - span, - d_ident, - thin_vec![d_attr.clone(), inline_never], - ItemKind::Fn(asdf), - ); + let mut d_fn = + ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Item(d_fn) }; @@ -446,7 +442,7 @@ mod llvm_enzyme { if primal_ret && n_active == 0 && x.mode.is_rev() { // We only have the primal ret. - body.stmts.push(ecx.stmt_expr(black_box_primal_call.clone())); + body.stmts.push(ecx.stmt_expr(black_box_primal_call)); return body; } @@ -471,7 +467,7 @@ mod llvm_enzyme { if primal_ret { // We have both primal ret and active floats. // primal ret is first, by construction. - exprs.push(primal_call.clone()); + exprs.push(primal_call); } // Now construct default placeholder for each active float. @@ -538,16 +534,11 @@ mod llvm_enzyme { return body; } [arg] => { - ret = ecx.expr_call( - new_decl_span, - blackbox_call_expr.clone(), - thin_vec![arg.clone()], - ); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]); } args => { let ret_tuple: P<ast::Expr> = ecx.expr_tuple(span, args.into()); - ret = - ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ret_tuple]); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]); } } assert!(has_ret(&d_sig.decl.output)); @@ -567,7 +558,7 @@ mod llvm_enzyme { let args: ThinVec<_> = idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); let self_expr = ecx.expr_self(span); - ecx.expr_method_call(span, self_expr, primal, args.clone()) + ecx.expr_method_call(span, self_expr, primal, args) } else { let args: ThinVec<_> = idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index ca16583a45d..c23ce1e5e4a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -18,7 +18,6 @@ #![feature(rustdoc_internals)] #![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro; diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 6933ca09349..ba63b185e09 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -60,6 +60,7 @@ pub fn inject( Edition2018 => sym::rust_2018, Edition2021 => sym::rust_2021, Edition2024 => sym::rust_2024, + EditionFuture => sym::rust_future, }]) .map(|&symbol| Ident::new(symbol, span)) .collect(); diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index c2027863b00..754025ff49d 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -11,7 +11,7 @@ test = { path = "../test" } - edition = "2021" + bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } - [dev-dependencies] - rand = { version = "0.8.5", default-features = false, features = ["alloc"] } + [features] + compiler-builtins-mem = ['compiler_builtins/mem'] -- 2.34.1 diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 717baebcd8c..9fe6baa3d25 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -16,7 +16,7 @@ use crate::context::CodegenCx; use crate::intrinsic::ArgAbiExt; use crate::type_of::LayoutGccExt; -impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { let func = self.current_func(); let param = func.get_param(index as i32); diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index c8b7616e645..6573b5b165e 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -2439,9 +2439,5 @@ fn get_maybe_pointer_size(value: RValue<'_>) -> u32 { #[cfg(not(feature = "master"))] fn get_maybe_pointer_size(value: RValue<'_>) -> u32 { let type_ = value.get_type(); - if type_.get_pointee().is_some() { - std::mem::size_of::<*const ()>() as _ - } else { - type_.get_size() - } + if type_.get_pointee().is_some() { size_of::<*const ()>() as _ } else { type_.get_size() } } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 628e34badf9..a63da6b6e27 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -59,7 +59,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } -impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } @@ -257,7 +257,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_gcc(self, alloc) } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index fb0ca31c543..c514b7a428b 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -302,9 +302,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn const_alloc_to_gcc<'gcc, 'tcx>( - cx: &CodegenCx<'gcc, 'tcx>, - alloc: ConstAllocation<'tcx>, +pub fn const_alloc_to_gcc<'gcc>( + cx: &CodegenCx<'gcc, '_>, + alloc: ConstAllocation<'_>, ) -> RValue<'gcc> { let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index cb08723431a..4e0a250b550 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -123,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index d3ce7c5a113..1741c3bacc7 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -43,3 +43,6 @@ serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8c75125e009..71059338151 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -654,7 +654,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } -impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { llvm::get_param(self.llfn(), index as c_uint) } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 66723cbf882..e614115f64b 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, }; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; -use crate::common::AsCCharPtr; -use crate::llvm::{self, Context, False, Module, True, Type}; -use crate::{ModuleLlvm, attributes, debuginfo}; +use crate::builder::SBuilder; +use crate::declare::declare_simple_fn; +use crate::llvm::{self, False, True, Type}; +use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, - module_llvm: &mut ModuleLlvm, + cx: SimpleCx<'_>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) { - let llcx = &*module_llvm.llcx; - let llmod = module_llvm.llmod(); - let usize = unsafe { - match tcx.sess.target.pointer_width { - 16 => llvm::LLVMInt16TypeInContext(llcx), - 32 => llvm::LLVMInt32TypeInContext(llcx), - 64 => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), - } + let usize = match tcx.sess.target.pointer_width { + 16 => cx.type_i16(), + 32 => cx.type_i32(), + 64 => cx.type_i64(), + tws => bug!("Unsupported target word size for int: {}", tws), }; - let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; - let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; + let i8 = cx.type_i8(); + let i8p = cx.type_ptr(); if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen( let from_name = global_fn_name(method.name); let to_name = default_fn_name(method.name); - create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); } } // rust alloc error handler create_wrapper_function( tcx, - llcx, - llmod, + &cx, "__rust_alloc_error_handler", alloc_error_handler_name(alloc_error_handler_kind), &[usize, usize], // size, align @@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen( unsafe { // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::set_initializer(ll_g, llval); } if tcx.sess.opts.debuginfo != DebugInfo::None { - let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); + let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod); debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx); dbg_cx.finalize(tcx.sess); } @@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen( fn create_wrapper_function( tcx: TyCtxt<'_>, - llcx: &Context, - llmod: &Module, + cx: &SimpleCx<'_>, from_name: &str, to_name: &str, args: &[&Type], output: Option<&Type>, no_return: bool, ) { - unsafe { - let ty = llvm::LLVMFunctionType( - output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)), - args.as_ptr(), - args.len() as c_uint, - False, - ); - let llfn = llvm::LLVMRustGetOrInsertFunction( - llmod, - from_name.as_c_char_ptr(), - from_name.len(), - ty, - ); - let no_return = if no_return { - // -> ! DIFlagNoReturn - let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); - Some(no_return) - } else { - None - }; - - llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - - if tcx.sess.must_emit_unwind_tables() { - let uwtable = - attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); - } + let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void())); + let llfn = declare_simple_fn( + &cx, + from_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ty, + ); + let no_return = if no_return { + // -> ! DIFlagNoReturn + let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); + Some(no_return) + } else { + None + }; - let callee = - llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); - - let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); - llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) - .collect::<Vec<_>>(); - let ret = llvm::LLVMBuildCallWithOperandBundles( - llbuilder, - ty, - callee, - args.as_ptr(), - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - c"".as_ptr(), - ); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - llvm::LLVMBuildRet(llbuilder, ret); - } else { - llvm::LLVMBuildRetVoid(llbuilder); - } - llvm::LLVMDisposeBuilder(llbuilder); + if tcx.sess.must_emit_unwind_tables() { + let uwtable = + attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); + } + + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; + + let mut bx = SBuilder::build(&cx, llbb); + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::<Vec<_>>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e8a69743157..88daa025740 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1,6 +1,5 @@ use std::assert_matches::assert_matches; -use libc::{c_char, c_uint}; use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -483,12 +482,13 @@ pub(crate) fn inline_asm_call<'ll>( debug!("Asm Output Type: {:?}", output); let fty = bx.cx.type_func(&argtys, output); - unsafe { - // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()); - debug!("constraint verification result: {:?}", constraints_ok); - if constraints_ok { - let v = llvm::LLVMRustInlineAsm( + // Ask LLVM to verify that the constraints are well-formed. + let constraints_ok = + unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) }; + debug!("constraint verification result: {:?}", constraints_ok); + if constraints_ok { + let v = unsafe { + llvm::LLVMRustInlineAsm( fty, asm.as_c_char_ptr(), asm.len(), @@ -498,54 +498,50 @@ pub(crate) fn inline_asm_call<'ll>( alignstack, dia, can_throw, - ); - - let call = if !labels.is_empty() { - assert!(catch_funclet.is_none()); - bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) - } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) - } else { - bx.call(fty, None, None, v, inputs, None, None) - }; + ) + }; - // Store mark in a metadata node so we can map LLVM errors - // back to source locations. See #17552. - let key = "srcloc"; - let kind = llvm::LLVMGetMDKindIDInContext( - bx.llcx, - key.as_ptr().cast::<c_char>(), - key.len() as c_uint, - ); + let call = if !labels.is_empty() { + assert!(catch_funclet.is_none()); + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) + } else if let Some((catch, funclet)) = catch_funclet { + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + } else { + bx.call(fty, None, None, v, inputs, None, None) + }; - // `srcloc` contains one 64-bit integer for each line of assembly code, - // where the lower 32 bits hold the lo byte position and the upper 32 bits - // hold the hi byte position. - let mut srcloc = vec![]; - if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { - // LLVM inserts an extra line to add the ".intel_syntax", so add - // a dummy srcloc entry for it. - // - // Don't do this if we only have 1 line span since that may be - // due to the asm template string coming from a macro. LLVM will - // default to the first srcloc for lines that don't have an - // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); - } - srcloc.extend(line_spans.iter().map(|span| { - llvm::LLVMValueAsMetadata(bx.const_u64( - u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), - )) - })); - let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); - let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); - llvm::LLVMSetMetadata(call, kind, md); + // Store mark in a metadata node so we can map LLVM errors + // back to source locations. See #17552. + let key = "srcloc"; + let kind = bx.get_md_kind_id(key); - Some(call) - } else { - // LLVM has detected an issue with our constraints, bail out - None + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. + let mut srcloc = vec![]; + if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata( + bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), + ) + })); + let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; + let md = bx.get_metadata_value(md); + llvm::LLVMSetMetadata(call, kind, md); + + Some(call) + } else { + // LLVM has detected an issue with our constraints, bail out + None } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3f20350d0ef..55d34f5f2ef 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -30,7 +30,7 @@ use tracing::{debug, instrument}; use crate::abi::FnAbiLlvmExt; use crate::common::Funclet; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, }; @@ -40,15 +40,15 @@ use crate::value::Value; use crate::{attributes, llvm_util}; #[must_use] -pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> { +pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SCx<'ll>>> { pub llbuilder: &'ll mut llvm::Builder<'ll>, - pub cx: &'a CX, + pub cx: &'a GenericCx<'ll, CX>, } -pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>; -pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>; +pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>; +pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, FullCx<'ll, 'tcx>>; -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow<SCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> { fn drop(&mut self) { unsafe { llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _)); @@ -57,7 +57,7 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> { } impl<'a, 'll> SBuilder<'a, 'll> { - fn call( + pub(crate) fn call( &mut self, llty: &'ll Type, llfn: &'ll Value, @@ -87,79 +87,36 @@ impl<'a, 'll> SBuilder<'a, 'll> { }; call } +} - fn with_scx(scx: &'a SimpleCx<'ll>) -> Self { +impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { + fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self { // Create a fresh builder from the simple context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) }; - SBuilder { llbuilder, cx: scx } + let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) }; + GenericBuilder { llbuilder, cx: scx } } -} -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) } } - fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + pub(crate) fn ret_void(&mut self) { + llvm::LLVMBuildRetVoid(self.llbuilder); } - fn ret(&mut self, v: &'ll Value) { + pub(crate) fn ret(&mut self, v: &'ll Value) { unsafe { llvm::LLVMBuildRet(self.llbuilder, v); } } -} -impl<'a, 'll> SBuilder<'a, 'll> { - fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> { - let bx = SBuilder::with_scx(cx); + + pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self { + let bx = Self::with_cx(cx); unsafe { llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); } bx } - - fn check_call<'b>( - &mut self, - typ: &str, - fn_ty: &'ll Type, - llfn: &'ll Value, - args: &'b [&'ll Value], - ) -> Cow<'b, [&'ll Value]> { - assert!( - self.cx.type_kind(fn_ty) == TypeKind::Function, - "builder::{typ} not passed a function, but {fn_ty:?}" - ); - - let param_tys = self.cx.func_params_types(fn_ty); - - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) - .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); - - if all_args_match { - return Cow::Borrowed(args); - } - - let casted_args: Vec<_> = iter::zip(param_tys, args) - .enumerate() - .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.cx.val_ty(actual_val); - if expected_ty != actual_ty { - debug!( - "type mismatch in function call of {:?}. \ - Expected {:?} for param {}, got {:?}; injecting bitcast", - llfn, expected_ty, i, actual_ty - ); - self.bitcast(actual_val, expected_ty) - } else { - actual_val - } - }) - .collect(); - - Cow::Owned(casted_args) - } } /// Empty string, to be used where LLVM expects an instruction name, indicating @@ -167,17 +124,17 @@ impl<'a, 'll> SBuilder<'a, 'll> { // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. const UNNAMED: *const c_char = c"".as_ptr(); -impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> { - type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value; - type Metadata = <CodegenCx<'ll, 'tcx> as BackendTypes>::Metadata; - type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function; - type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock; - type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type; - type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet; - - type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope; - type DILocation = <CodegenCx<'ll, 'tcx> as BackendTypes>::DILocation; - type DIVariable = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIVariable; +impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericBuilder<'_, 'll, CX> { + type Value = <GenericCx<'ll, CX> as BackendTypes>::Value; + type Metadata = <GenericCx<'ll, CX> as BackendTypes>::Metadata; + type Function = <GenericCx<'ll, CX> as BackendTypes>::Function; + type BasicBlock = <GenericCx<'ll, CX> as BackendTypes>::BasicBlock; + type Type = <GenericCx<'ll, CX> as BackendTypes>::Type; + type Funclet = <GenericCx<'ll, CX> as BackendTypes>::Funclet; + + type DIScope = <GenericCx<'ll, CX> as BackendTypes>::DIScope; + type DILocation = <GenericCx<'ll, CX> as BackendTypes>::DILocation; + type DIVariable = <GenericCx<'ll, CX> as BackendTypes>::DIVariable; } impl abi::HasDataLayout for Builder<'_, '_, '_> { @@ -293,9 +250,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + llvm::LLVMBuildRetVoid(self.llbuilder); } fn ret(&mut self, v: &'ll Value) { @@ -356,8 +311,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // This function handles switch instructions with more than 2 targets and it needs to // emit branch weights metadata instead of using the intrinsic. // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic. - let cold_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(1)) }; - let hot_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)) }; + let cold_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(1)); + let hot_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)); let weight = |is_cold: bool| -> &Metadata { if is_cold { cold_weight } else { hot_weight } }; @@ -1476,26 +1431,12 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> { - let bx = Builder::with_cx(cx); - unsafe { - llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); - } - bx - } - - fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self { - // Create a fresh builder from the crate context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) }; - Builder { llbuilder, cx } - } - pub(crate) fn llfn(&self) -> &'ll Value { unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) } } } -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { fn position_at_start(&mut self, llbb: &'ll BasicBlock) { unsafe { llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); @@ -1525,7 +1466,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } } } -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } } @@ -1626,9 +1567,7 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) }; ret.expect("LLVM does not have support for catchret") } -} -impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn check_call<'b>( &mut self, typ: &str, @@ -1643,7 +1582,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let param_tys = self.cx.func_params_types(fn_ty); - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.val_ty(v))) + let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); if all_args_match { @@ -1653,7 +1592,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let casted_args: Vec<_> = iter::zip(param_tys, args) .enumerate() .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.val_ty(actual_val); + let actual_ty = self.cx.val_ty(actual_val); if expected_ty != actual_ty { debug!( "type mismatch in function call of {:?}. \ @@ -1669,12 +1608,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { Cow::Owned(casted_args) } -} -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } } + impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(intrinsic); @@ -1694,7 +1633,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]); } } -impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { pub(crate) fn phi( &mut self, ty: &'ll Type, diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 2c7899975e3..71705ecb4d0 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -3,6 +3,7 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::back::write::ModuleConfig; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_errors::FatalError; use tracing::{debug, trace}; @@ -286,7 +287,8 @@ pub(crate) fn differentiate<'ll>( } let diag_handler = cgcx.create_dcx(); - let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx }; + + let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size); // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag? if !diff_items.is_empty() diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f264e3419e4..457e5452ce9 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,7 @@ //! Code that is useful in various codegen modules. +use std::borrow::Borrow; + use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::Primitive::Pointer; @@ -18,6 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; +use crate::context::{GenericCx, SCx}; use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -81,7 +84,7 @@ impl<'ll> Funclet<'ll> { } } -impl<'ll> BackendTypes for CodegenCx<'ll, '_> { +impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> { type Value = &'ll Value; type Metadata = &'ll Metadata; // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`. @@ -118,7 +121,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstNull(t) } } @@ -342,7 +345,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_llvm(self, alloc, /*static*/ false) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 330e8a8f406..a4e5749b3ac 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -16,7 +16,6 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::Lto; use tracing::{debug, instrument, trace}; use crate::common::{AsCCharPtr, CodegenCx}; @@ -344,11 +343,11 @@ impl<'ll> CodegenCx<'ll, '_> { // Local definitions can never be imported, so we must not apply // the DLLImport annotation. && !dso_local - // ThinLTO can't handle this workaround in all cases, so we don't - // emit the attrs. Instead we make them unnecessary by disallowing - // dynamic linking when linker plugin based LTO is enabled. - && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled() - && self.tcx.sess.lto() != Lto::Thin; + // Linker plugin ThinLTO doesn't create the self-dllimport Rust uses for rlibs + // as the code generation happens out of process. Instead we assume static linkage + // and disallow dynamic linking when linker plugin based LTO is enabled. + // Regular in-process ThinLTO doesn't need this workaround. + && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled(); // If this assertion triggers, there's something wrong with commandline // argument validation. @@ -490,7 +489,7 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = llvm::LLVMMetadataAsValue(self.llcx, meta); + let val = self.get_metadata_value(meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ed8426ae197..9f8ec0ea526 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,13 +1,13 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, c_char, c_uint}; +use std::marker::PhantomData; use std::ops::Deref; use std::str; -use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx}; +use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; -use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; @@ -32,9 +32,9 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::{self, AsCCharPtr}; +use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::{Metadata, MetadataType}; +use crate::llvm::Metadata; use crate::type_::Type; use crate::value::Value; use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; @@ -43,18 +43,19 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; /// However, there are various cx related functions which we want to be available to the builder and /// other compiler pieces. Here we define a small subset which has enough information and can be /// moved around more freely. -pub(crate) struct SimpleCx<'ll> { +pub(crate) struct SCx<'ll> { pub llmod: &'ll llvm::Module, pub llcx: &'ll llvm::Context, + pub isize_ty: &'ll Type, } -impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> { - fn borrow(&self) -> &SimpleCx<'ll> { +impl<'ll> Borrow<SCx<'ll>> for FullCx<'ll, '_> { + fn borrow(&self) -> &SCx<'ll> { &self.scx } } -impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> Deref for FullCx<'ll, 'tcx> { type Target = SimpleCx<'ll>; #[inline] @@ -63,10 +64,25 @@ impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { } } +pub(crate) struct GenericCx<'ll, T: Borrow<SCx<'ll>>>(T, PhantomData<SCx<'ll>>); + +impl<'ll, T: Borrow<SCx<'ll>>> Deref for GenericCx<'ll, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub(crate) type SimpleCx<'ll> = GenericCx<'ll, SCx<'ll>>; + /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM /// `llvm::Context` so that several codegen units may be processed in parallel. /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. -pub(crate) struct CodegenCx<'ll, 'tcx> { +pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>; + +pub(crate) struct FullCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, pub scx: SimpleCx<'ll>, pub use_dll_storage_attrs: bool, @@ -104,8 +120,6 @@ pub(crate) struct CodegenCx<'ll, 'tcx> { /// Mapping of scalar types to llvm types. pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>, - pub isize_ty: &'ll Type, - /// Extra per-CGU codegen state needed when coverage instrumentation is enabled. pub coverage_cx: Option<coverageinfo::CguCoverageContext<'ll, 'tcx>>, pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>, @@ -579,33 +593,33 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { None }; - let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits()); - - CodegenCx { - tcx, - scx: SimpleCx { llcx, llmod }, - use_dll_storage_attrs, - tls_model, - codegen_unit, - instances: Default::default(), - vtables: Default::default(), - const_str_cache: Default::default(), - const_globals: Default::default(), - statics_to_rauw: RefCell::new(Vec::new()), - used_statics: RefCell::new(Vec::new()), - compiler_used_statics: RefCell::new(Vec::new()), - type_lowering: Default::default(), - scalar_lltypes: Default::default(), - isize_ty, - coverage_cx, - dbg_cx, - eh_personality: Cell::new(None), - eh_catch_typeinfo: Cell::new(None), - rust_try_fn: Cell::new(None), - intrinsics: Default::default(), - local_gen_sym_counter: Cell::new(0), - renamed_statics: Default::default(), - } + GenericCx( + FullCx { + tcx, + scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size), + use_dll_storage_attrs, + tls_model, + codegen_unit, + instances: Default::default(), + vtables: Default::default(), + const_str_cache: Default::default(), + const_globals: Default::default(), + statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), + compiler_used_statics: RefCell::new(Vec::new()), + type_lowering: Default::default(), + scalar_lltypes: Default::default(), + coverage_cx, + dbg_cx, + eh_personality: Cell::new(None), + eh_catch_typeinfo: Cell::new(None), + rust_try_fn: Cell::new(None), + intrinsics: Default::default(), + local_gen_sym_counter: Cell::new(0), + renamed_statics: Default::default(), + }, + PhantomData, + ) } pub(crate) fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> { @@ -628,24 +642,32 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_section(g, c"llvm.metadata"); } } + impl<'ll> SimpleCx<'ll> { - pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type { - common::val_ty(v) + pub(crate) fn new( + llmod: &'ll llvm::Module, + llcx: &'ll llvm::Context, + pointer_size: Size, + ) -> Self { + let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits()); + Self(SCx { llmod, llcx, isize_ty }, PhantomData) } +} +impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value { - unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) } + llvm::LLVMMetadataAsValue(self.llcx(), metadata) } pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> { let name = SmallCStr::new(name); - unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) } + unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) } } - pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 { + pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId { unsafe { llvm::LLVMGetMDKindIDInContext( - self.llcx, + self.llcx(), name.as_ptr() as *const c_char, name.len() as c_uint, ) @@ -654,13 +676,9 @@ impl<'ll> SimpleCx<'ll> { pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len()) + llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) }) } - - pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind { - unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } - } } impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -1203,27 +1221,18 @@ impl CodegenCx<'_, '_> { name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY)); name } - - /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } - } } -// This is a duplication of the set_metadata function above. However, so far it's the only one -// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it -// for the Builder. -impl SimpleCx<'_> { - #[allow(unused)] +impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } + pub(crate) fn set_metadata<'a>( + &self, + val: &'a Value, + kind_id: impl Into<llvm::MetadataKindId>, + md: &'ll Metadata, + ) { + let node = self.get_metadata_value(md); + llvm::LLVMSetMetadata(val, kind_id.into(), node); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index c53ea6d4666..80e54bf045e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -8,7 +8,7 @@ use std::ffi::CString; use rustc_abi::Align; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, + BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods, }; use rustc_middle::mir::coverage::{ BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index e79662ebc64..2419ec1f888 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -11,6 +11,8 @@ //! * Use define_* family of methods when you might be defining the Value. //! * When in doubt, define. +use std::borrow::Borrow; + use itertools::Itertools; use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_data_structures::fx::FxIndexSet; @@ -22,7 +24,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::common::AsCCharPtr; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx}; use crate::llvm::AttributePlace::Function; use crate::llvm::Visibility; use crate::type_::Type; @@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>( llfn } -impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { /// Declare a global value. /// /// If there’s a value with the same name already declared, the function will /// return its Value instead. pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } + unsafe { + llvm::LLVMRustGetOrInsertGlobal( + (**self).borrow().llmod, + name.as_c_char_ptr(), + name.len(), + ty, + ) + } } +} +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Declare a C ABI function. /// /// Only use this for foreign function ABIs and glue. For Rust functions use diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 0272667e223..660fc7ec4c4 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -649,7 +649,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time // optimization pass replaces calls to this intrinsic with code to test type membership. - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); self.call_intrinsic("llvm.type.test", &[pointer, typeid]) } @@ -659,7 +659,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { vtable_byte_offset: u64, typeid: &'ll Metadata, ) -> Self::Value { - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); let type_checked_load = self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8f72307eeba..2f3c8c75b0b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -19,7 +19,6 @@ #![feature(rustdoc_internals)] #![feature(slice_as_array)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::any::Any; @@ -28,6 +27,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; +use context::SimpleCx; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; pub(crate) use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; @@ -115,9 +115,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { - let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let cx = + SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 25ca3498803..f6b23862907 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -3,13 +3,14 @@ use libc::{c_char, c_uint}; +use super::MetadataKindId; use super::ffi::{BasicBlock, Metadata, Module, Type, Value}; use crate::llvm::Bool; #[link(name = "llvm-wrapper", kind = "static")] unsafe extern "C" { // Enzyme - pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool; + pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool; pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value); pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>; pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e3d0b928c97..39087a4d6f4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -976,6 +976,16 @@ pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct MetadataKindId(c_uint); + +impl From<MetadataType> for MetadataKindId { + fn from(value: MetadataType) -> Self { + Self(value as c_uint) + } +} + unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMContextDispose(C: &'static mut Context); @@ -983,7 +993,7 @@ unsafe extern "C" { C: &Context, Name: *const c_char, SLen: c_uint, - ) -> c_uint; + ) -> MetadataKindId; // Create modules. pub(crate) fn LLVMModuleCreateWithNameInContext( @@ -1050,9 +1060,9 @@ unsafe extern "C" { pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char; pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); - pub(crate) fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value); + pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value); pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); - pub(crate) fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; + pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; // Operations on constants of any type pub(crate) fn LLVMConstNull(Ty: &Type) -> &Value; @@ -1146,7 +1156,7 @@ unsafe extern "C" { pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); - pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( @@ -1203,7 +1213,7 @@ unsafe extern "C" { pub(crate) fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>; // Terminators - pub(crate) fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; + pub(crate) safe fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; pub(crate) fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value; pub(crate) fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value; pub(crate) fn LLVMBuildCondBr<'a>( @@ -1679,7 +1689,7 @@ unsafe extern "C" { Packed: Bool, ); - pub(crate) fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; + pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index d61ce417562..b89ce90d1a1 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::{fmt, ptr}; use libc::{c_char, c_uint}; @@ -11,7 +12,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; use crate::llvm::{Bool, False, Metadata, True}; use crate::type_of::LayoutLlvmExt; @@ -36,29 +37,29 @@ impl fmt::Debug for Type { } impl<'ll> CodegenCx<'ll, '_> {} -impl<'ll> SimpleCx<'ll> { +impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type { let name = SmallCStr::new(name); - unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) } + unsafe { llvm::LLVMStructCreateNamed(self.llcx(), name.as_ptr()) } } pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } } pub(crate) fn type_void(&self) -> &'ll Type { - unsafe { llvm::LLVMVoidTypeInContext(self.llcx) } + unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } pub(crate) fn type_token(&self) -> &'ll Type { - unsafe { llvm::LLVMTokenTypeInContext(self.llcx) } + unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) } } pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) } + unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) } } ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } } pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { @@ -121,19 +122,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.type_array(self.type_from_integer(unit), size / unit_size) } } -impl<'ll> SimpleCx<'ll> { + +impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { + pub(crate) fn llcx(&self) -> &'ll llvm::Context { + (**self).borrow().llcx + } + + pub(crate) fn isize_ty(&self) -> &'ll Type { + (**self).borrow().isize_ty + } + pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } pub(crate) fn type_i1(&self) -> &'ll Type { - unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) } } pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { unsafe { llvm::LLVMStructTypeInContext( - self.llcx, + self.llcx(), els.as_ptr(), els.len() as c_uint, packed as Bool, @@ -142,45 +152,45 @@ impl<'ll> SimpleCx<'ll> { } } -impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { fn type_i8(&self) -> &'ll Type { - unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt8TypeInContext(self.llcx()) } } fn type_i16(&self) -> &'ll Type { - unsafe { llvm::LLVMInt16TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt16TypeInContext(self.llcx()) } } fn type_i32(&self) -> &'ll Type { - unsafe { llvm::LLVMInt32TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt32TypeInContext(self.llcx()) } } fn type_i64(&self) -> &'ll Type { - unsafe { llvm::LLVMInt64TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) } } fn type_i128(&self) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, 128) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) } } fn type_isize(&self) -> &'ll Type { - self.isize_ty + self.isize_ty() } fn type_f16(&self) -> &'ll Type { - unsafe { llvm::LLVMHalfTypeInContext(self.llcx) } + unsafe { llvm::LLVMHalfTypeInContext(self.llcx()) } } fn type_f32(&self) -> &'ll Type { - unsafe { llvm::LLVMFloatTypeInContext(self.llcx) } + unsafe { llvm::LLVMFloatTypeInContext(self.llcx()) } } fn type_f64(&self) -> &'ll Type { - unsafe { llvm::LLVMDoubleTypeInContext(self.llcx) } + unsafe { llvm::LLVMDoubleTypeInContext(self.llcx()) } } fn type_f128(&self) -> &'ll Type { - unsafe { llvm::LLVMFP128TypeInContext(self.llcx) } + unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) } } fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { @@ -196,7 +206,7 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type { - unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) } + unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) } } fn element_type(&self, ty: &'ll Type) -> &'ll Type { diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 1346efcb87c..c00be0e9926 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -63,3 +63,6 @@ features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", [target.'cfg(windows)'.dependencies.windows] version = "0.59.0" features = ["Win32_Globalization"] + +[lints] +workspace = true diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a170b2e3b6a..7d9971c021d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1177,7 +1177,7 @@ mod win { let mut cp: u32 = 0; // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32. // But the API requires us to pass the data as though it's a [u16] string. - let len = std::mem::size_of::<u32>() / std::mem::size_of::<u16>(); + let len = size_of::<u32>() / size_of::<u16>(); let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len); let len_written = GetLocaleInfoEx( LOCALE_NAME_SYSTEM_DEFAULT, @@ -3382,6 +3382,35 @@ fn add_lld_args( // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { cmd.cc_arg("-fuse-ld=lld"); + + // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some + // section garbage-collection features. For example, the somewhat popular `linkme` crate and + // its dependents rely in practice on this difference: when using lld, they need `-z + // nostart-stop-gc` to prevent encapsulation symbols and sections from being + // garbage-collected. + // + // More information about all this can be found in: + // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order + // - https://lld.llvm.org/ELF/start-stop-gc + // + // So when using lld, we restore, for now, the traditional behavior to help migration, but + // will remove it in the future. + // Since this only disables an optimization, it shouldn't create issues, but is in theory + // slightly suboptimal. However, it: + // - doesn't have any visible impact on our benchmarks + // - reduces the need to disable lld for the crates that depend on this + // + // Note that lld can detect some cases where this difference is relied on, and emits a + // dedicated error to add this link arg. We could make use of this error to emit an FCW. As + // of writing this, we don't do it, because lld is already enabled by default on nightly + // without this mitigation: no working project would see the FCW, so we do this to help + // stabilization. + // + // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the + // future. + if sess.target.llvm_target == "x86_64-unknown-linux-gnu" { + cmd.link_arg("-znostart-stop-gc"); + } } if !flavor.is_gnu() { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 818edaf6603..a8405a2aec9 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1655,9 +1655,9 @@ impl<'a> Linker for AixLinker<'a> { } } - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { @@ -1668,7 +1668,7 @@ impl<'a> Linker for AixLinker<'a> { fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c8bb229998e..87992ce2e11 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; +use rustc_abi::Size; use rustc_ast::attr; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -355,6 +356,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub target_is_like_aix: bool, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, + pub pointer_size: Size, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -1216,6 +1218,7 @@ fn start_executing_work<B: ExtraBackendMethods>( split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, + pointer_size: tcx.data_layout.pointer_size, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 4e758bfdec3..8ad04032414 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -14,7 +14,6 @@ #![feature(rustdoc_internals)] #![feature(trait_alias)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e2a9b540d30..6d1930a402d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,6 +3,7 @@ use std::cmp; use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange}; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::packed::Pu128; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; @@ -406,6 +407,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect); } + } else if target_iter.len() == 2 + && self.mir[targets.otherwise()].is_empty_unreachable() + && targets.all_values().contains(&Pu128(0)) + && targets.all_values().contains(&Pu128(1)) + { + // This is the really common case for `bool`, `Option`, etc. + // By using `trunc nuw` we communicate that other values are + // impossible without needing `switch` or `assume`s. + let true_bb = targets.target_for_value(1); + let false_bb = targets.target_for_value(0); + let true_ll = helper.llbb_with_cleanup(self, true_bb); + let false_ll = helper.llbb_with_cleanup(self, false_bb); + + let expected_cond_value = if self.cx.sess().opts.optimize == OptLevel::No { + None + } else { + match (self.cold_blocks[true_bb], self.cold_blocks[false_bb]) { + // Same coldness, no expectation + (true, true) | (false, false) => None, + // Different coldness, expect the non-cold one + (true, false) => Some(false), + (false, true) => Some(true), + } + }; + + let bool_ty = bx.tcx().types.bool; + let cond = if switch_ty == bool_ty { + discr_value + } else { + let bool_llty = bx.immediate_backend_type(bx.layout_of(bool_ty)); + bx.unchecked_utrunc(discr_value, bool_llty) + }; + bx.cond_br_with_expect(cond, true_ll, false_ll, expected_cond_value); } else if self.cx.sess().opts.optimize == OptLevel::No && target_iter.len() == 2 && self.mir[targets.otherwise()].is_empty_unreachable() diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 00e01e47fee..6988724b421 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout) } - pub fn len<Cx: ConstCodegenMethods<'tcx, Value = V>>(&self, cx: &Cx) -> V { + pub fn len<Cx: ConstCodegenMethods<Value = V>>(&self, cx: &Cx) -> V { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index ff555f4273c..95b108b1d33 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -364,6 +364,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); + // While optimizations will remove no-op transmutes, they might still be + // there in debug or things that aren't no-op in MIR because they change + // the Rust type but not the underlying layout/niche. + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + return imm; + } + use abi::Primitive::*; imm = bx.from_immediate(imm); diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece..49c51caa996 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -pub trait AbiBuilderMethods<'tcx>: BackendTypes { +pub trait AbiBuilderMethods: BackendTypes { fn get_param(&mut self, index: usize) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 99fd6b6510f..5f91133d5b4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -40,7 +40,7 @@ pub trait BuilderMethods<'a, 'tcx>: + CoverageInfoBuilderMethods<'tcx> + DebugInfoBuilderMethods + ArgAbiBuilderMethods<'tcx> - + AbiBuilderMethods<'tcx> + + AbiBuilderMethods + IntrinsicCallBuilderMethods<'tcx> + AsmBuilderMethods<'tcx> + StaticBuilderMethods diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index dc6b68ceff7..d83a04d814b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -3,7 +3,7 @@ use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; use super::BackendTypes; -pub trait ConstCodegenMethods<'tcx>: BackendTypes { +pub trait ConstCodegenMethods: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; /// Generate an uninitialized value (matching uninitialized memory in MIR). @@ -37,7 +37,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>; - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 90fcfbe4da7..239857a4298 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + PartialEq + fmt::Debug; pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + TypeCodegenMethods<'tcx> - + ConstCodegenMethods<'tcx> + + ConstCodegenMethods + StaticCodegenMethods + DebugInfoCodegenMethods<'tcx> + AsmCodegenMethods<'tcx> diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index fbd927d0d66..32d9f27d32d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -9,7 +9,7 @@ use super::misc::MiscCodegenMethods; use crate::common::TypeKind; use crate::mir::place::PlaceRef; -pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { +pub trait BaseTypeCodegenMethods: BackendTypes { fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { } pub trait DerivedTypeCodegenMethods<'tcx>: - BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> + BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { fn type_int(&self) -> Self::Type { match &self.sess().target.c_int_width[..] { @@ -87,10 +87,7 @@ pub trait DerivedTypeCodegenMethods<'tcx>: } impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where - Self: BaseTypeCodegenMethods<'tcx> - + MiscCodegenMethods<'tcx> - + HasTyCtxt<'tcx> - + HasTypingEnv<'tcx> + Self: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { } diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index a0cc2c65e6e..d76238a3992 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -26,3 +26,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 43631330f89..e4b2fe5d153 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -104,7 +104,7 @@ fn intern_as_new_static<'tcx>( ) { let feed = tcx.create_def( static_id, - sym::nested, + Some(sym::nested), DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index ed5489652fb..da52d60ae59 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -16,7 +16,6 @@ #![feature(unqualified_local_imports)] #![feature(yeet_expr)] #![warn(unqualified_local_imports)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod check_consts; diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index bdf5494f210..b364ab0dde4 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -54,3 +54,6 @@ memmap2 = "0.2.1" [target.'cfg(not(target_has_atomic = "64"))'.dependencies] portable-atomic = "1.5.1" + +[lints] +workspace = true diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs index 0e5ecfd9bff..a636d09fcae 100644 --- a/compiler/rustc_data_structures/src/aligned.rs +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -2,10 +2,8 @@ use std::ptr::Alignment; /// Returns the ABI-required minimum alignment of a type in bytes. /// -/// This is equivalent to [`mem::align_of`], but also works for some unsized +/// This is equivalent to [`align_of`], but also works for some unsized /// types (e.g. slices or rustc's `List`s). -/// -/// [`mem::align_of`]: std::mem::align_of pub const fn align_of<T: ?Sized + Aligned>() -> Alignment { T::ALIGN } @@ -15,10 +13,10 @@ pub const fn align_of<T: ?Sized + Aligned>() -> Alignment { /// # Safety /// /// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it -/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for +/// is [`align_of::<Self>()`], for unsized types it depends on the type, for /// example `[T]` has alignment of `T`. /// -/// [`mem::align_of<Self>()`]: std::mem::align_of +/// [`align_of::<Self>()`]: align_of pub unsafe trait Aligned { /// Alignment of `Self`. const ALIGN: Alignment; diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index b69b9dbc4a8..e48b9686c26 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -3,7 +3,7 @@ use std::cmp::max; use super::*; use crate::fx::FxHashMap; -pub struct TestGraph { +pub(super) struct TestGraph { num_nodes: usize, start_node: usize, successors: FxHashMap<usize, Vec<usize>>, @@ -11,7 +11,7 @@ pub struct TestGraph { } impl TestGraph { - pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { + pub(super) fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { let mut graph = TestGraph { num_nodes: start_node + 1, start_node, diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 78d69a66edc..8d19fc5f9cc 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -313,7 +313,7 @@ pub struct Error<O, E> { mod helper { use super::*; - pub type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>; + pub(super) type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>; impl<O: ForestObligation> ObligationForest<O> { pub fn new() -> ObligationForest<O> { ObligationForest { diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 39db551adfb..60f007083ba 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -863,15 +863,13 @@ fn get_thread_id() -> u32 { cfg_match! { windows => { pub fn get_resident_set_size() -> Option<usize> { - use std::mem; - use windows::{ Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, Win32::System::Threading::GetCurrentProcess, }; let mut pmc = PROCESS_MEMORY_COUNTERS::default(); - let pmc_size = mem::size_of_val(&pmc); + let pmc_size = size_of_val(&pmc); unsafe { K32GetProcessMemoryInfo( GetCurrentProcess(), @@ -889,7 +887,7 @@ cfg_match! { pub fn get_resident_set_size() -> Option<usize> { use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; use std::mem; - const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int; + const PROC_TASKINFO_SIZE: c_int = size_of::<proc_taskinfo>() as c_int; unsafe { let mut info: proc_taskinfo = mem::zeroed(); diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index e6be9c256f0..3016348f224 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,7 +1,7 @@ use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; -use std::{iter, mem}; +use std::iter; use either::Either; @@ -221,7 +221,7 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 { /// consistently for each `Sharded` instance. #[inline] fn get_shard_hash(hash: u64) -> usize { - let hash_len = mem::size_of::<usize>(); + let hash_len = size_of::<usize>(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. // hashbrown also uses the lowest bits, so we can't use those (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index a1cc75c4985..616a18a72ab 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -88,7 +88,7 @@ mod mode { // Whether thread safety might be enabled. #[inline] - pub fn might_be_dyn_thread_safe() -> bool { + pub(super) fn might_be_dyn_thread_safe() -> bool { DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE } diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 1ba631b8623..8ef8a3f3585 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -46,7 +46,7 @@ pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R { ret } -pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) +fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA, B: FnOnce() -> RB, diff --git a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs index 9c1e4cefa69..85b21a7c8ec 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs @@ -7,7 +7,7 @@ use crate::stable_hasher::{HashStable, StableHasher}; /// A tag type used in [`TaggedRef`] tests. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Tag2 { +enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index e3ee8351295..d27895a5e7a 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -10,3 +10,6 @@ crate-type = ["dylib"] # tidy-alphabetical-start rustc_driver_impl = { path = "../rustc_driver_impl" } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 8593d1faba2..4469fa4e1f3 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -79,3 +79,6 @@ rustc_randomized_layouts = [ 'rustc_middle/rustc_randomized_layouts' ] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a2ddff7183e..6e4020c6eca 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -16,7 +16,6 @@ #![feature(result_flattening)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cmp::max; diff --git a/compiler/rustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml index 55b4e899051..d89e4526016 100644 --- a/compiler/rustc_error_codes/Cargo.toml +++ b/compiler/rustc_error_codes/Cargo.toml @@ -6,3 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d53d5678832..dfeef5a957d 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -6,7 +6,6 @@ #![deny(rustdoc::invalid_codeblock_attributes)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // This higher-order macro defines the error codes that are in use. It is used diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 578af7fc51d..e9047ba16e5 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -19,3 +19,6 @@ rustc_span = { path = "../rustc_span" } tracing = "0.1" unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index ba1c3e185c2..a6fbbb29ccd 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -4,7 +4,6 @@ #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(type_alias_impl_trait)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index b11793c190a..fc39a726093 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -39,3 +39,6 @@ features = [ "Win32_Security", "Win32_System_Threading", ] + +[lints] +workspace = true diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 7fffeaddb86..9f4d2ea5c1a 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -490,7 +490,7 @@ pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { // would be bad. impl<G> !Clone for Diag<'_, G> {} -rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * std::mem::size_of::<usize>()); +rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>()); impl<G: EmissionGuarantee> Deref for Diag<'_, G> { type Target = DiagInner; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index f7f84239308..21255fcca96 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -113,24 +113,11 @@ impl Margin { self.computed_left > 0 } - fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // FIXME: This comment refers to the only callsite of this method. - // Rephrase it or refactor it, so it can stand on its own. - // Account for the "..." padding given above. Otherwise we end up with code lines - // that do fit but end in "..." as if they were trimmed. - // FIXME: Don't hard-code this offset. Is this meant to represent - // `2 * str_width(self.margin())`? - self.computed_right - 6 - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.column_width < line_len - } - fn compute(&mut self, max_line_len: usize) { // When there's a lot of whitespace (>20), we want to trim it as it is useless. + // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that + // calculation later, right before printing in order to be accurate with both unicode + // handling and trimming of long lines. self.computed_left = if self.whitespace_left > 20 { self.whitespace_left - 16 // We want some padding. } else { @@ -616,7 +603,6 @@ pub struct HumanEmitter { #[setters(skip)] fallback_bundle: LazyFallbackBundle, short_message: bool, - teach: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec<String>, diagnostic_width: Option<usize>, @@ -642,7 +628,6 @@ impl HumanEmitter { fluent_bundle: None, fallback_bundle, short_message: false, - teach: false, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), diagnostic_width: None, @@ -670,43 +655,43 @@ impl HumanEmitter { width_offset: usize, code_offset: usize, margin: Margin, - ) { - // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(!source_string.contains('\t')); + ) -> usize { let line_len = source_string.len(); // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. - let mut taken = 0; let code: String = source_string .chars() - .skip(left) - .take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - let next = char_width(*ch); - if taken + next > right - left { - return false; - } - taken += next; - true - }) + .enumerate() + .skip_while(|(i, _)| *i < left) + .take_while(|(i, _)| *i < right) + .map(|(_, c)| c) .collect(); + let code = normalize_whitespace(&code); + let was_cut_right = + source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); let placeholder = self.margin(); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } - if margin.was_cut_right(line_len) { + if was_cut_right { let padding = str_width(placeholder); // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); + buffer.puts( + line_offset, + code_offset + str_width(&code) - padding, + placeholder, + Style::LineNumber, + ); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + left } #[instrument(level = "trace", skip(self), ret)] @@ -738,22 +723,16 @@ impl HumanEmitter { return Vec::new(); } - let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&s), - None => return Vec::new(), + let Some(source_string) = file.get_line(line.line_index - 1) else { + return Vec::new(); }; trace!(?source_string); let line_offset = buffer.num_lines(); - // Left trim - let left = margin.left(source_string.len()); - + // Left trim. // FIXME: This looks fishy. See #132860. - // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum(); - - self.draw_line( + let left = self.draw_line( buffer, &source_string, line.line_index, @@ -784,7 +763,7 @@ impl HumanEmitter { let mut short_start = true; for ann in &line.annotations { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col.file).all(|c| c.is_whitespace()) { let uline = self.underline(ann.is_primary); let chr = uline.multiline_whole_line; annotations.push((depth, uline.style)); @@ -903,11 +882,16 @@ impl HumanEmitter { // | x_span // <EMPTY LINE> // + let mut overlap = vec![false; annotations.len()]; let mut annotations_position = vec![]; let mut line_len: usize = 0; let mut p = 0; for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) && j > i { + overlap[i] = true; + overlap[j] = true; + } if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). @@ -1035,24 +1019,21 @@ impl HumanEmitter { let pos = pos + 1; match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); self.draw_range( buffer, underline.multiline_horizontal, line_offset + pos, width_offset + depth, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset + pre, underline.style, ); } - _ if self.teach => { - buffer.set_style_range( - line_offset, - (code_offset + annotation.start_col.display).saturating_sub(left), - (code_offset + annotation.end_col.display).saturating_sub(left), - underline.style, - annotation.is_primary, - ); - } _ => {} } } @@ -1072,11 +1053,18 @@ impl HumanEmitter { let underline = self.underline(annotation.is_primary); let pos = pos + 1; + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::<usize>(); if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc( p, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineLine(_) => underline.multiline_vertical, _ => underline.vertical_text_line, @@ -1087,7 +1075,7 @@ impl HumanEmitter { if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.bottom_right, underline.style, ); @@ -1097,7 +1085,7 @@ impl HumanEmitter { { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.multiline_bottom_right_with_text, underline.style, ); @@ -1155,13 +1143,30 @@ impl HumanEmitter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - if annotation.end_col.display == 0 { - (pos + 1, (annotation.end_col.display + 2).saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.end_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + if annotation.end_col.file == 0 { + (pos + 1, (pre + 2)) } else { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + let pad = if annotation.end_col.file - annotation.start_col.file == 0 { + 2 + } else { + 1 + }; + (pos + 1, (pre + pad)) } } else { - (pos + 2, annotation.start_col.display.saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + (pos + 2, pre) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, code_offset + col, label, style); @@ -1194,14 +1199,35 @@ impl HumanEmitter { // | _^ test for &(pos, annotation) in &annotations_position { let uline = self.underline(annotation.is_primary); - for p in annotation.start_col.display..annotation.end_col.display { + let width = annotation.end_col.file - annotation.start_col.file; + let previous: String = + source_string.chars().take(annotation.start_col.file).skip(left).collect(); + let underlined: String = + source_string.chars().skip(annotation.start_col.file).take(width).collect(); + debug!(?previous, ?underlined); + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::<usize>(); + let ann_width: usize = source_string + .chars() + .skip(annotation.start_col.file) + .take(width) + .map(|c| char_width(c)) + .sum(); + let ann_width = if ann_width == 0 + && matches!(annotation.annotation_type, AnnotationType::Singleline) + { + 1 + } else { + ann_width + }; + for p in 0..ann_width { // The default span label underline. - buffer.putc( - line_offset + 1, - (code_offset + p).saturating_sub(left), - uline.underline, - uline.style, - ); + buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style); } if pos == 0 @@ -1213,7 +1239,7 @@ impl HumanEmitter { // The beginning of a multiline span with its leftward moving line on the same line. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.top_right_flat, AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, @@ -1231,7 +1257,7 @@ impl HumanEmitter { // so we start going down first. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.multiline_start_down, AnnotationType::MultilineEnd(_) => uline.multiline_end_up, @@ -1241,11 +1267,37 @@ impl HumanEmitter { ); } else if pos != 0 && annotation.has_label() { // The beginning of a span label with an actual label, we'll point down. - buffer.putc( + buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style); + } + } + + // We look for individual *long* spans, and we trim the *middle*, so that we render + // LL | ...= [0, 0, 0, ..., 0, 0]; + // | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]` + for (i, (_pos, annotation)) in annotations_position.iter().enumerate() { + // Skip cases where multiple spans overlap each other. + if overlap[i] { + continue; + }; + let AnnotationType::Singleline = annotation.annotation_type else { continue }; + let width = annotation.end_col.display - annotation.start_col.display; + if width > margin.column_width * 2 && width > 10 { + // If the terminal is *too* small, we keep at least a tiny bit of the span for + // display. + let pad = max(margin.column_width / 3, 5); + // Code line + buffer.replace( + line_offset, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), + ); + // Underline line + buffer.replace( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), - uline.label_start, - uline.style, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), ); } } @@ -1702,17 +1754,11 @@ impl HumanEmitter { // non-rustc_lexer::is_whitespace() chars are reported as an // error (ex. no-break-spaces \u{a0}), and thus can't be considered // for removal during error reporting. + // FIXME: doesn't account for '\t' properly. let leading_whitespace = source_string .chars() .take_while(|c| rustc_lexer::is_whitespace(*c)) - .map(|c| { - match c { - // Tabs are displayed as 4 spaces - '\t' => 4, - _ => 1, - } - }) - .sum(); + .count(); if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) { whitespace_margin = min(whitespace_margin, leading_whitespace); } @@ -1726,8 +1772,8 @@ impl HumanEmitter { let mut span_left_margin = usize::MAX; for line in &annotated_file.lines { for ann in &line.annotations { - span_left_margin = min(span_left_margin, ann.start_col.display); - span_left_margin = min(span_left_margin, ann.end_col.display); + span_left_margin = min(span_left_margin, ann.start_col.file); + span_left_margin = min(span_left_margin, ann.end_col.file); } } if span_left_margin == usize::MAX { @@ -1747,12 +1793,12 @@ impl HumanEmitter { .map_or(0, |s| s.len()), ); for ann in &line.annotations { - span_right_margin = max(span_right_margin, ann.start_col.display); - span_right_margin = max(span_right_margin, ann.end_col.display); + span_right_margin = max(span_right_margin, ann.start_col.file); + span_right_margin = max(span_right_margin, ann.end_col.file); // FIXME: account for labels not in the same line let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1); label_right_margin = - max(label_right_margin, ann.end_col.display + label_right); + max(label_right_margin, ann.end_col.file + label_right); } } @@ -1763,15 +1809,7 @@ impl HumanEmitter { width_offset + annotated_file.multiline_depth + 1 }; - let column_width = if let Some(width) = self.diagnostic_width { - width.saturating_sub(code_offset) - } else if self.ui_testing || cfg!(miri) { - DEFAULT_COLUMN_WIDTH - } else { - termize::dimensions() - .map(|(w, _)| w.saturating_sub(code_offset)) - .unwrap_or(DEFAULT_COLUMN_WIDTH) - }; + let column_width = self.column_width(code_offset); let margin = Margin::new( whitespace_margin, @@ -1928,6 +1966,18 @@ impl HumanEmitter { Ok(()) } + fn column_width(&self, code_offset: usize) -> usize { + if let Some(width) = self.diagnostic_width { + width.saturating_sub(code_offset) + } else if self.ui_testing || cfg!(miri) { + DEFAULT_COLUMN_WIDTH + } else { + termize::dimensions() + .map(|(w, _)| w.saturating_sub(code_offset)) + .unwrap_or(DEFAULT_COLUMN_WIDTH) + } + } + fn emit_suggestion_default( &mut self, span: &MultiSpan, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 86959b28e53..80e43ede445 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -25,7 +25,6 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_errors; diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 5ca9e9b18f3..790efd0286e 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -89,6 +89,19 @@ impl StyledBuffer { } } + pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) { + if start == end { + return; + } + if start > self.lines[line].len() || end > self.lines[line].len() { + return; + } + let _ = self.lines[line].drain(start..(end - string.chars().count())); + for (i, c) in string.chars().enumerate() { + self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber); + } + } + /// For given `line` inserts `string` with `style` before old content of that line, /// adding lines if needed pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) { diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 0ba139ea5cc..f051ea0c2ac 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -29,3 +29,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 777044e3f33..4222c9fe906 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -13,7 +13,6 @@ #![feature(rustdoc_internals)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro as pm; diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index a5ae06473cb..1aaace75404 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -10,3 +10,6 @@ rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 0b034a2ae10..25764755a8f 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -15,7 +15,6 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod accepted; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c6e992573d6..7741f6668c3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -474,6 +474,8 @@ declare_features! ( (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), + /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` + (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index ce76b2745ea..695e8b3fd5d 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -16,3 +16,6 @@ quote = "1" syn = { version = "2", features = ["full"] } unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index 3ad51fa1e64..c6e0484b921 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -7,7 +7,6 @@ #![feature(proc_macro_span)] #![feature(rustdoc_internals)] #![feature(track_path)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use proc_macro::TokenStream; diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index baca3bc7d49..3518209ea5b 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -6,3 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_graphviz/Cargo.toml b/compiler/rustc_graphviz/Cargo.toml index d84943760ba..2672a624eab 100644 --- a/compiler/rustc_graphviz/Cargo.toml +++ b/compiler/rustc_graphviz/Cargo.toml @@ -6,3 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index b5774f64b66..c8f8fd5be02 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -277,7 +277,6 @@ )] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; diff --git a/compiler/rustc_hashes/Cargo.toml b/compiler/rustc_hashes/Cargo.toml index c7a273cff88..ff46696c4c0 100644 --- a/compiler/rustc_hashes/Cargo.toml +++ b/compiler/rustc_hashes/Cargo.toml @@ -7,3 +7,6 @@ edition = "2024" # tidy-alphabetical-start rustc-stable-hash = { version = "0.1.0" } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 7ca8539845a..e45c49cd7db 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -21,3 +21,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 7e3a8561da0..5f8941d4754 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -253,7 +253,9 @@ impl DefKind { } } - pub fn def_path_data(self, name: Symbol) -> DefPathData { + // Some `DefKind`s require a name, some don't. Panics if one is needed but + // not provided. (`AssocTy` is an exception, see below.) + pub fn def_path_data(self, name: Option<Symbol>) -> DefPathData { match self { DefKind::Mod | DefKind::Struct @@ -264,9 +266,13 @@ impl DefKind { | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias - | DefKind::AssocTy | DefKind::TyParam - | DefKind::ExternCrate => DefPathData::TypeNs(name), + | DefKind::ExternCrate => DefPathData::TypeNs(Some(name.unwrap())), + + // An associated type names will be missing for an RPITIT. It will + // later be given a name with `synthetic` in it, if necessary. + DefKind::AssocTy => DefPathData::TypeNs(name), + // It's not exactly an anon const, but wrt DefPathData, there // is no difference. DefKind::Static { nested: true, .. } => DefPathData::AnonConst, @@ -276,9 +282,9 @@ impl DefKind { | DefKind::Static { .. } | DefKind::AssocFn | DefKind::AssocConst - | DefKind::Field => DefPathData::ValueNs(name), - DefKind::Macro(..) => DefPathData::MacroNs(name), - DefKind::LifetimeParam => DefPathData::LifetimeNs(name), + | DefKind::Field => DefPathData::ValueNs(name.unwrap()), + DefKind::Macro(..) => DefPathData::MacroNs(name.unwrap()), + DefKind::LifetimeParam => DefPathData::LifetimeNs(name.unwrap()), DefKind::Ctor(..) => DefPathData::Ctor, DefKind::Use => DefPathData::Use, DefKind::ForeignMod => DefPathData::ForeignMod, @@ -429,7 +435,7 @@ pub enum Res<Id = hir::HirId> { /// mention any generic parameters to allow the following with `min_const_generics`: /// ``` /// # struct Foo; - /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } } + /// impl Foo { fn test() -> [u8; size_of::<Self>()] { todo!() } } /// /// struct Bar([u8; baz::<Self>()]); /// const fn baz<T>() -> usize { 10 } @@ -439,7 +445,7 @@ pub enum Res<Id = hir::HirId> { /// compat lint: /// ``` /// fn foo<T>() { - /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; + /// let _bar = [1_u8; size_of::<*mut T>()]; /// } /// ``` // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c4c309e77e1..61f5efd9978 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -271,8 +271,9 @@ pub enum DefPathData { Use, /// A global asm item. GlobalAsm, - /// Something in the type namespace. - TypeNs(Symbol), + /// Something in the type namespace. Will be empty for RPITIT associated + /// types, which are given a synthetic name later, if necessary. + TypeNs(Option<Symbol>), /// Something in the value namespace. ValueNs(Symbol), /// Something in the macro namespace. @@ -410,8 +411,9 @@ impl DefPathData { pub fn get_opt_name(&self) -> Option<Symbol> { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => None, - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + TypeNs(name) => name, + + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst | OpaqueTy => None, @@ -421,12 +423,14 @@ impl DefPathData { pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => { - DefPathDataName::Anon { namespace: sym::synthetic } - } - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { - DefPathDataName::Named(name) + TypeNs(name) => { + if let Some(name) = name { + DefPathDataName::Named(name) + } else { + DefPathDataName::Anon { namespace: sym::synthetic } + } } + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name), // Note that this does not show up in user print-outs. CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, Impl => DefPathDataName::Anon { namespace: kw::Impl }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index df305e6e769..928455ace85 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2166,6 +2166,7 @@ impl Expr<'_> { | ExprKind::Tup(_) | ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) + | ExprKind::Use(..) | ExprKind::Err(_) => ExprPrecedence::Unambiguous, ExprKind::DropTemps(expr, ..) => expr.precedence(), @@ -2212,6 +2213,7 @@ impl Expr<'_> { ExprKind::Path(QPath::TypeRelative(..)) | ExprKind::Call(..) | ExprKind::MethodCall(..) + | ExprKind::Use(..) | ExprKind::Struct(..) | ExprKind::Tup(..) | ExprKind::If(..) @@ -2285,7 +2287,9 @@ impl Expr<'_> { pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { - ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false, + ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => { + false + } ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) @@ -2547,6 +2551,8 @@ pub enum ExprKind<'hir> { /// /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span), + /// An use expression (e.g., `var.use`). + Use(&'hir Expr<'hir>, Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), /// A binary operation (e.g., `a + b`, `a * b`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 41eb5b45bd1..25d2a825343 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -316,8 +316,8 @@ pub trait Visitor<'v>: Sized { fn visit_ident(&mut self, ident: Ident) -> Self::Result { walk_ident(self, ident) } - fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> Self::Result { - walk_mod(self, m, n) + fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result { + walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result { walk_foreign_item(self, i) @@ -464,8 +464,8 @@ pub trait Visitor<'v>: Sized { fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) -> Self::Result { - walk_enum_def(self, enum_definition, item_id) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result { + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result { walk_variant(self, v) @@ -532,28 +532,25 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { + try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ident(item.ident)); match item.kind { ItemKind::ExternCrate(orig_name) => { - try_visit!(visitor.visit_id(item.hir_id())); visit_opt!(visitor, visit_name, orig_name); } ItemKind::Use(ref path, _) => { try_visit!(visitor.visit_use(path, item.hir_id())); } ItemKind::Static(ref typ, _, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Const(ref typ, ref generics, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Fn { sig, generics, body: body_id, .. } => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), sig.decl, @@ -562,19 +559,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: item.owner_id.def_id, )); } - ItemKind::Macro(..) => { - try_visit!(visitor.visit_id(item.hir_id())); - } + ItemKind::Macro(..) => {} ItemKind::Mod(ref module) => { - // `visit_mod()` takes care of visiting the `Item`'s `HirId`. try_visit!(visitor.visit_mod(module, item.span, item.hir_id())); } ItemKind::ForeignMod { abi: _, items } => { - try_visit!(visitor.visit_id(item.hir_id())); walk_list!(visitor, visit_foreign_item_ref, items); } ItemKind::GlobalAsm { asm: _, fake_body } => { - try_visit!(visitor.visit_id(item.hir_id())); // Visit the fake body, which contains the asm statement. // Therefore we should not visit the asm statement again // outside of the body, or some visitors won't have their @@ -582,14 +574,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_nested_body(fake_body)); } ItemKind::TyAlias(ref ty, ref generics) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(ty)); try_visit!(visitor.visit_generics(generics)); } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. - try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id())); + try_visit!(visitor.visit_enum_def(enum_definition)); } ItemKind::Impl(Impl { constness: _, @@ -602,7 +592,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: self_ty, items, }) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); visit_opt!(visitor, visit_trait_ref, of_trait); try_visit!(visitor.visit_ty_unambig(self_ty)); @@ -611,17 +600,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_variant_data(struct_definition)); } ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } ItemKind::TraitAlias(ref generics, bounds) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); } @@ -638,12 +624,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul visitor.visit_name(ident.name) } -pub fn walk_mod<'v, V: Visitor<'v>>( - visitor: &mut V, - module: &'v Mod<'v>, - mod_hir_id: HirId, -) -> V::Result { - try_visit!(visitor.visit_id(mod_hir_id)); +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result { walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); V::Result::output() } @@ -821,6 +802,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(receiver)); walk_list!(visitor, visit_expr, arguments); } + ExprKind::Use(expr, _) => { + try_visit!(visitor.visit_expr(expr)); + } ExprKind::Binary(_, ref left_expression, ref right_expression) => { try_visit!(visitor.visit_expr(left_expression)); try_visit!(visitor.visit_expr(right_expression)); @@ -1145,7 +1129,6 @@ pub fn walk_use<'v, V: Visitor<'v>>( path: &'v UsePath<'v>, hir_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(hir_id)); let UsePath { segments, ref res, span } = *path; for &res in res { try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id)); @@ -1326,9 +1309,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>( pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, - item_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(item_id)); walk_list!(visitor, visit_variant, enum_definition.variants); V::Result::output() } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c3b14a4e06c..29f4d5b8076 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -171,6 +171,7 @@ language_item_table! { Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 270d4fbec30..84d369f1edd 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -13,7 +13,6 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_hir; diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 55a816a855a..99ced5ff0a9 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -32,3 +32,6 @@ rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index ba5b61d3fce..8a841a11556 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -124,7 +124,10 @@ pub(crate) fn check_negative_auto_trait_impl<'tcx>( // be implemented here to handle non-ADT rigid types. Ok(()) } else { - span_bug!(tcx.def_span(impl_def_id), "incoherent impl of negative auto trait"); + Err(tcx.dcx().span_delayed_bug( + tcx.def_span(impl_def_id), + "incoherent impl of negative auto trait", + )) } } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6b61d317d3f..883a1acdb30 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1462,7 +1462,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { - let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + let feed = + self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam); feed.def_span(ident.span); feed.def_ident_span(Some(ident.span)); feed.def_id() diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index f5e075367f3..3611db7c68f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -84,9 +84,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) + && !self.maybe_suggest_dyn_trait(self_ty, label, sugg, &mut diag) { - // FIXME: Only emit this suggestion if the trait is dyn-compatible. - diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); + self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag); } // Check if the impl trait that we are considering is an impl of a local trait. self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); @@ -123,6 +123,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn maybe_suggest_add_generic_impl_trait( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + let msg = "you might be missing a type parameter"; + let mut sugg = vec![]; + + let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id; + let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item(); + match parent_item.kind { + hir::ItemKind::Struct(_, generics) | hir::ItemKind::Enum(_, generics) => { + sugg.push(( + generics.where_clause_span, + format!( + "<T: {}>", + self.tcx().sess.source_map().span_to_snippet(self_ty.span).unwrap() + ), + )); + sugg.push((self_ty.span, "T".to_string())); + } + _ => {} + } + diag.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable); + true + } /// Make sure that we are in the condition to suggest the blanket implementation. fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>( &self, @@ -171,6 +198,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn maybe_suggest_dyn_trait( + &self, + self_ty: &hir::Ty<'_>, + label: &str, + sugg: Vec<(Span, String)>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id; + let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item(); + + // If the parent item is an enum, don't suggest the dyn trait. + if let hir::ItemKind::Enum(..) = parent_item.kind { + return false; + } + + // If the parent item is a struct, check if self_ty is the last field. + if let hir::ItemKind::Struct(variant_data, _) = parent_item.kind { + if variant_data.fields().last().unwrap().ty.span != self_ty.span { + return false; + } + } + + // FIXME: Only emit this suggestion if the trait is dyn-compatible. + diag.multipart_suggestion_verbose( + label.to_string(), + sugg, + Applicability::MachineApplicable, + ); + true + } + fn add_generic_param_suggestion( &self, generics: &hir::Generics<'_>, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 50b0e32b95e..26a20690a95 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -73,7 +73,6 @@ This API is completely unstable and subject to change. #![feature(slice_partition_dedup)] #![feature(try_blocks)] #![feature(unwrap_infallible)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // These are used by Clippy. diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 86989d1e55b..bc6431d0271 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -8,7 +8,10 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1f6fb3a329a..0e3721126fb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::Cell; @@ -16,7 +15,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; -use rustc_attr_parsing::{AttributeKind, PrintAttribute}; +use rustc_attr_data_structures::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, @@ -1470,6 +1469,10 @@ impl<'a> State<'a> { hir::ExprKind::MethodCall(segment, receiver, args, _) => { self.print_expr_method_call(segment, receiver, args); } + hir::ExprKind::Use(expr, _) => { + self.print_expr(expr); + self.word(".use"); + } hir::ExprKind::Binary(op, lhs, rhs) => { self.print_expr_binary(op, lhs, rhs); } @@ -2220,6 +2223,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value { .. } => self.word_space("move"), + hir::CaptureBy::Use { .. } => self.word_space("use"), hir::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index f1afb7b712d..1d6486fb7dc 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -27,3 +27,6 @@ rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 67419fdf1c3..d7b5c1ed5e1 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,8 +41,8 @@ use rustc_abi::ExternAbi; use rustc_attr_parsing::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; @@ -56,7 +56,7 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AliasTy, GenericArgsRef, Ty, TyCtxt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -593,6 +593,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Create an obligation for `Source: CoerceUnsized<Target>`. let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + let root_obligation = Obligation::new( + self.tcx, + cause.clone(), + self.fcx.param_env, + ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]), + ); + + // If the root `Source: CoerceUnsized<Target>` obligation can't possibly hold, + // we don't have to assume that this is unsizing coercion (it will always lead to an error) + // + // However, we don't want to bail early all the time, since the unholdable obligations + // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id<This = U>`), + // so we only bail if there (likely) is another way to convert the types. + if !self.infcx.predicate_may_hold(&root_obligation) { + if let Some(dyn_metadata_adt_def_id) = self.tcx.lang_items().get(LangItem::DynMetadata) + && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata) + { + self.probe(|_| { + let ocx = ObligationCtxt::new(&self.infcx); + + // returns `true` if `<ty as Pointee>::Metadata` is `DynMetadata<_>` + let has_dyn_trait_metadata = |ty| { + let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty( + &ObligationCause::dummy(), + self.fcx.param_env, + Ty::new_alias( + self.tcx, + ty::AliasTyKind::Projection, + AliasTy::new(self.tcx, metadata_type_def_id, [ty]), + ), + ); + + metadata_ty.is_ok_and(|metadata_ty| { + metadata_ty + .ty_adt_def() + .is_some_and(|d| d.did() == dyn_metadata_adt_def_id) + }) + }; + + // If both types are raw pointers to a (wrapper over a) trait object, + // this might be a cast like `*const W<dyn Trait> -> *const dyn Trait`. + // So it's better to bail and try that. (even if the cast is not possible, for + // example due to vtables not matching, cast diagnostic will likely still be better) + // + // N.B. use `target`, not `coerce_target` (the latter is a var) + if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() + && let &ty::RawPtr(target_pointee, _) = target.kind() + && has_dyn_trait_metadata(source_pointee) + && has_dyn_trait_metadata(target_pointee) + { + return Err(TypeError::Mismatch); + } + + Ok(()) + })?; + } + } // Use a FIFO queue for this custom fulfillment procedure. // @@ -601,12 +658,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( - self.tcx, - cause, - self.fcx.param_env, - ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) - )]; + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![root_obligation]; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2a89a03e0aa..786e8b876a6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -362,6 +362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression child of these expressions constitute reads. ExprKind::Array(_) | ExprKind::Call(_, _) + | ExprKind::Use(_, _) | ExprKind::MethodCall(_, _, _, _) | ExprKind::Tup(_) | ExprKind::Binary(_, _, _) @@ -552,6 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected), ExprKind::Block(body, _) => self.check_expr_block(body, expected), ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected), + ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected), ExprKind::MethodCall(segment, receiver, args, _) => { self.check_expr_method_call(expr, segment, receiver, args, expected) } @@ -1616,6 +1618,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } + /// Checks use `x.use`. + fn check_expr_use( + &self, + used_expr: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + self.check_expr_with_expectation(used_expr, expected) + } + fn check_expr_cast( &self, e: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c0617119d67..9ff7eeb2368 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -47,6 +47,21 @@ pub trait Delegate<'tcx> { /// the id of the binding in the pattern `pat`. fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is used, depending + /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. + /// + /// Use of a `Copy` type in a ByUse context is considered a use + /// by `ImmBorrow` and `borrow` is called instead. This is because + /// a shared borrow is the "minimum access" that would be needed + /// to perform a copy. + /// + /// + /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for + /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic + /// id will be the id of the expression `expr` but the place itself will have + /// the id of the binding in the pattern `pat`. + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is being borrowed with kind `bk`. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn borrow( @@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { (**self).consume(place_with_id, diag_expr_id) } + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).use_cloned(place_with_id, diag_expr_id) + } + fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn body_owner_def_id(&self) -> LocalDefId; fn tcx(&self) -> TyCtxt<'tcx>; @@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.infcx.type_is_copy_modulo_regions(self.param_env, ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.body_id } @@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { self.0.type_is_copy_modulo_regions(ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.0.type_is_use_cloned_modulo_regions(ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.1 } @@ -295,6 +324,24 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id); + + // `x.use` will do one of the following + // * if it implements `Copy`, it will be a copy + // * if it implements `UseCloned`, it will be a call to `clone` + // * otherwise, it is a move + // + // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned` + if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); + } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id); + } else { + self.delegate.borrow_mut().consume(place_with_id, diag_expr_id); + } + } + fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> { for expr in exprs { self.consume_expr(expr)?; @@ -313,6 +360,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { + debug!("consume_or_clone_expr(expr={:?})", expr); + + let place_with_id = self.cat_expr(expr)?; + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + self.walk_expr(expr)?; + Ok(()) + } + fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { let place_with_id = self.cat_expr(expr)?; self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id); @@ -366,6 +422,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.consume_exprs(args)?; } + hir::ExprKind::Use(expr, _) => { + self.consume_or_clone_expr(expr)?; + } + hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) self.consume_expr(receiver)?; @@ -1085,6 +1145,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ty::UpvarCapture::ByValue => { self.consume_or_copy(&place_with_id, place_with_id.hir_id); } + ty::UpvarCapture::ByUse => { + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow_mut().borrow( &place_with_id, @@ -1386,6 +1449,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure { .. } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 8b9c2b4a6ca..263fb84206e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -8,7 +8,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod _match; diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9a0b2247058..f570d0d8a0d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -671,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (place, capture_kind) = match capture_clause { hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind), + hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind), hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind), }; @@ -1165,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match closure_clause { hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value - hir::CaptureBy::Ref => { + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => { // For non move closure the capture kind is the max capture kind of all captures // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue let mut max_capture_info = root_var_min_capture_list.first().unwrap().info; @@ -1292,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } - hir::CaptureBy::Ref => {} + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {} } return None; @@ -1305,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for captured_place in root_var_min_capture_list.iter() { match captured_place.info.capture_kind { // Only care about captures that are moved into the closure - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { projections_list.push(captured_place.place.projections.as_slice()); diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { source_expr: captured_place.info.path_expr_id, @@ -1689,10 +1690,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // If the data will be moved out of this place, then the place will be truncated // at the first Deref in `adjust_for_move_closure` and then moved into the closure. + // + // For example: + // + // struct Buffer<'a> { + // x: &'a String, + // y: Vec<u8>, + // } + // + // fn get<'a>(b: Buffer<'a>) -> impl Sized + 'a { + // let c = move || b.x; + // drop(b); + // c + // } + // + // Even though the closure is declared as move, when we are capturing borrowed data (in + // this case, *b.x) we prefer to capture by reference. + // Otherwise you'd get an error in 2021 immediately because you'd be trying to take + // ownership of the (borrowed) String or else you'd take ownership of b, as in 2018 and + // before, which is also an error. hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => { ty::UpvarCapture::ByValue } - hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => { + hir::CaptureBy::Use { .. } if !place.deref_tys().any(Ty::is_ref) => { + ty::UpvarCapture::ByUse + } + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => { ty::UpvarCapture::ByRef(BorrowKind::Immutable) } } @@ -1927,7 +1950,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>( region: ty::Region<'tcx>, ) -> Ty<'tcx> { match capture_kind { - ty::UpvarCapture::ByValue => ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()), } } @@ -2024,6 +2047,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { } #[instrument(skip(self), level = "debug")] + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); + + self.capture_information.push(( + place_with_id.place.clone(), + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByUse, + }, + )); + } + + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -2164,6 +2202,20 @@ fn adjust_for_move_closure( (place, ty::UpvarCapture::ByValue) } +/// Truncate deref of any reference. +fn adjust_for_use_closure( + mut place: Place<'_>, + mut kind: ty::UpvarCapture, +) -> (Place<'_>, ty::UpvarCapture) { + let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(idx) = first_deref { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); + } + + (place, ty::UpvarCapture::ByUse) +} + /// Adjust closure capture just that if taking ownership of data, only move data /// from enclosing stack frame. fn adjust_for_non_move_closure( @@ -2174,7 +2226,7 @@ fn adjust_for_non_move_closure( place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); match kind { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { if let Some(idx) = contains_deref { truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); } @@ -2219,6 +2271,7 @@ fn construct_capture_kind_reason_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; @@ -2240,6 +2293,7 @@ fn construct_capture_info_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} -> {capture_kind_str}") @@ -2335,8 +2389,11 @@ fn determine_capture_info( // expressions. let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b, - (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false, + (ty::UpvarCapture::ByValue, _) + | (ty::UpvarCapture::ByUse, _) + | (ty::UpvarCapture::ByRef(_), _) => false, }; if eq_capture_kind { @@ -2346,10 +2403,20 @@ fn determine_capture_info( } } else { // We select the CaptureKind which ranks higher based the following priority order: - // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow + // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue, _) => capture_info_a, - (_, ty::UpvarCapture::ByValue) => capture_info_b, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => { + bug!("Same capture can't be ByUse and ByValue at the same time") + } + (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) + | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => { + capture_info_a + } + (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => { + capture_info_b + } (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { match (ref_a, ref_b) { // Take LHS: @@ -2401,7 +2468,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>( } ty::UpvarCapture::ByRef(..) => {} - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } place.projections.truncate(len); diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 4939bfb3a1c..4e5061f4f69 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rand = "0.8.4" +rand = "0.9.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -22,3 +22,6 @@ rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 563ed7614c6..299ee487638 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -7,7 +7,6 @@ #![doc(rust_logo)] #![feature(file_buffered)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod assert_dep_graph; diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 4c664ea6ba0..9cec2702a41 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -123,7 +123,7 @@ pub(crate) fn read_file( // Check HEADER_FORMAT_VERSION { - debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2); + debug_assert!(size_of_val(&HEADER_FORMAT_VERSION) == 2); let mut header_format_version = [0u8; 2]; file.read_exact(&mut header_format_version)?; let header_format_version = diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 19cca48af61..76a1ff3cf38 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -108,7 +108,7 @@ use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use rand::{RngCore, thread_rng}; +use rand::{RngCore, rng}; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::svh::Svh; @@ -445,7 +445,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let timestamp = timestamp_to_string(SystemTime::now()); debug!("generate_session_dir_path: timestamp = {}", timestamp); - let random_number = thread_rng().next_u32(); + let random_number = rng().next_u32(); debug!("generate_session_dir_path: random_number = {}", random_number); // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while. diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 3d83a3c98da..ee6fe11f9a5 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -21,3 +21,6 @@ nightly = [ ] rustc_randomized_layouts = [] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 6dc044a6d38..598409c9051 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1,7 +1,9 @@ use std::marker::PhantomData; +#[cfg(not(feature = "nightly"))] +use std::mem; use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl}; use std::rc::Rc; -use std::{fmt, iter, mem, slice}; +use std::{fmt, iter, slice}; use Chunk::*; #[cfg(feature = "nightly")] @@ -14,7 +16,7 @@ use crate::{Idx, IndexVec}; mod tests; type Word = u64; -const WORD_BYTES: usize = mem::size_of::<Word>(); +const WORD_BYTES: usize = size_of::<Word>(); const WORD_BITS: usize = WORD_BYTES * 8; // The choice of chunk size has some trade-offs. diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 3441a5f65c7..cc680838e7e 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -4,7 +4,6 @@ #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))] #![cfg_attr(feature = "nightly", feature(new_range_api))] #![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod bit_set; diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs index 381d79c24fc..5b0ca4b2b92 100644 --- a/compiler/rustc_index/src/vec/tests.rs +++ b/compiler/rustc_index/src/vec/tests.rs @@ -9,8 +9,6 @@ crate::newtype_index! { #[test] fn index_size_is_optimized() { - use std::mem::size_of; - assert_eq!(size_of::<MyIdx>(), 4); // Uses 0xFFFF_FFFB assert_eq!(size_of::<Option<MyIdx>>(), 4); diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 891e7ded619..de100bd0e2c 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -13,3 +13,6 @@ quote = "1" [features] nightly = [] + +[lints] +workspace = true diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index 67ec7761133..f0b58eabbff 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -305,7 +305,7 @@ impl Parse for Newtype { } } -pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub(crate) fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as Newtype); input.0.into() } diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 08c03614884..242886a9248 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -21,3 +21,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index a04b2bb2b08..ece18f4ea64 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -24,7 +24,6 @@ #![feature(let_chains)] #![feature(rustdoc_internals)] #![recursion_limit = "512"] // For rustdoc -#![warn(unreachable_pub)] // tidy-alphabetical-end mod errors; diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 9c9660cf504..add8c0e20e6 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -56,3 +56,6 @@ tracing = "0.1" # tidy-alphabetical-start llvm = ['dep:rustc_codegen_llvm'] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 54cd341698f..67e0be93523 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,7 +4,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod callbacks; diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 448a50faf45..b9b16eebc54 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -24,3 +24,6 @@ features = ["emoji"] [dev-dependencies] expect-test = "1.4.0" + +[lints] +workspace = true diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index bf18845a083..61638e45253 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -23,7 +23,6 @@ // We want to be able to build this crate with a stable compiler, // so no `#![feature]` attributes should be added. #![deny(unstable_features)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod cursor; diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index d6014f5006a..f6c10aa9744 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -28,3 +28,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" unicode-security = "0.1.0" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 74663e6b4bb..cd4106ebf83 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> { self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty) } + pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty) + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index fd6b3e90ada..91c7922638d 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -159,7 +159,10 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { ExprKind::Path(..) => false, // Calls return rvalues. - ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true, + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Use(..) + | ExprKind::Binary(..) => true, // Inner blocks are rvalues. ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true, diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index d22515d62d6..23d6efa0508 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -74,7 +74,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) { lint_callback!(self, check_mod, m, n); - hir_visit::walk_mod(self, m, n); + hir_visit::walk_mod(self, m); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7018774e5c6..35867d8c9ef 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,7 +32,6 @@ #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod async_closures; diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index 9ab350daf69..f9b45a00ec1 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -15,3 +15,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 10b85be2cfb..592c934997c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -73,7 +73,6 @@ declare_lint_pass! { NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, - ORDER_DEPENDENT_TRAIT_OBJECTS, OUT_OF_SCOPE_MACRO_CALLS, OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -1502,42 +1501,6 @@ declare_lint! { } declare_lint! { - /// The `order_dependent_trait_objects` lint detects a trait coherency - /// violation that would allow creating two trait impls for the same - /// dynamic trait object involving marker traits. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// pub trait Trait {} - /// - /// impl Trait for dyn Send + Sync { } - /// impl Trait for dyn Sync + Send { } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// A previous bug caused the compiler to interpret traits with different - /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types - /// when they were intended to be treated the same. This allowed code to - /// define separate trait implementations when there should be a coherence - /// error. This is a [future-incompatible] lint to transition this to a - /// hard error in the future. See [issue #56484] for more details. - /// - /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub ORDER_DEPENDENT_TRAIT_OBJECTS, - Deny, - "trait-object types were treated as different depending on marker-trait order", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", - }; -} - -declare_lint! { /// The `coherence_leak_check` lint detects conflicting implementations of /// a trait that are only distinguished by the old leak-check code. /// @@ -2710,7 +2673,7 @@ declare_lint! { /// /// ```rust /// const fn foo<T>() -> usize { - /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + /// if size_of::<*mut T>() < 8 { // size of *mut T does not depend on T /// 4 /// } else { /// 8 diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e564235c41a..46b4b1d4383 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,7 +1,3 @@ -// tidy-alphabetical-start -#![warn(unreachable_pub)] -// tidy-alphabetical-end - use rustc_abi::ExternAbi; use rustc_ast::AttrId; use rustc_ast::attr::AttributeExt; diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 061562b2ec5..dcfaf9a0282 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -14,3 +14,6 @@ libc = "0.2.73" # pinned `cc` in `rustc_codegen_ssa` if you update `cc` here. cc = "=1.2.16" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index aea2a8dd097..53df59930f4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -152,8 +152,12 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) { } extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, - const char *Triple) { - unwrap(M)->setTargetTriple(Triple::normalize(Triple)); + const char *Target) { +#if LLVM_VERSION_GE(21, 0) + unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target))); +#else + unwrap(M)->setTargetTriple(Triple::normalize(Target)); +#endif } extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) { diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index eda9b2b1fc0..68058250a26 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -4,7 +4,6 @@ #![doc(rust_logo)] #![feature(extern_types)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::RefCell; diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index 30f6e9ba805..665ebd52f47 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -20,3 +20,6 @@ rustc_span = { path = "../rustc_span" } # tidy-alphabetical-start max_level_info = ['tracing/max_level_info'] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index f9d3b758359..b937f75e892 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -13,3 +13,6 @@ quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 34fc0f00320..44ba064dd82 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -6,7 +6,6 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] #![feature(proc_macro_tracked_env)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use proc_macro::TokenStream; diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index a8821640f04..5fa3047d14e 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -31,3 +31,6 @@ rustc_type_ir = { path = "../rustc_type_ir" } tempfile = "3.2" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index ebcc0efd5a6..8898c5824fa 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -15,7 +15,6 @@ #![feature(proc_macro_internals)] #![feature(rustdoc_internals)] #![feature(trusted_len)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro; diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index aebd2181f31..3a6216e63a9 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -14,7 +14,8 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links rustc_errors = { path = "../rustc_errors" } @@ -42,3 +43,6 @@ tracing = "0.1" # tidy-alphabetical-start rustc_randomized_layouts = [] # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fad8c7dcbcb..c85af81ee25 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1356,7 +1356,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.submodules.push(item.owner_id); // A module collector does not recurse inside nested modules. if self.crate_collector { - intravisit::walk_mod(self, module, item.hir_id()); + intravisit::walk_mod(self, module); } } else { intravisit::walk_item(self, item) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 48ea7df5c23..8fe2cc7101b 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -61,7 +61,6 @@ #![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[cfg(test)] diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 311bc60c3cd..a94ead161c3 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,6 +1,6 @@ use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; -use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2260cad41b9..ec128c8c478 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_attr_parsing::{ +use rustc_attr_data_structures::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index cc6389e2989..fea5038e6dd 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -223,8 +223,8 @@ impl<D: TyDecoder> Decodable<D> for InitMaskMaterialized { // large. impl hash::Hash for InitMaskMaterialized { fn hash<H: hash::Hasher>(&self, state: &mut H) { - const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / std::mem::size_of::<Block>(); - const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / std::mem::size_of::<Block>(); + const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / size_of::<Block>(); + const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / size_of::<Block>(); // Partially hash the `blocks` buffer when it is large. To limit collisions with common // prefixes and suffixes, we hash the length and some slices of the buffer. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c48cfffa05c..2675b7e0fc5 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -573,7 +573,7 @@ pub fn write_target_uint( #[inline] pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> { // This u128 holds an "any-size uint" (since smaller uints can fits in it) - let mut buf = [0u8; std::mem::size_of::<u128>()]; + let mut buf = [0u8; size_of::<u128>()]; // So we do not read exactly 16 bytes into the u128, just the "payload". let uint = match endianness { Endian::Little => { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ea0bb5feb12..83857ab6c5c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -332,13 +332,13 @@ pub struct Body<'tcx> { /// /// ```rust /// fn test<T>() { - /// let _ = [0; std::mem::size_of::<*mut T>()]; + /// let _ = [0; size_of::<*mut T>()]; /// } /// ``` /// /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization /// removed the last mention of all generic params. We do not want to rely on optimizations and - /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this. + /// potentially allow things like `[u8; size_of::<T>() * 0]` due to this. pub is_polymorphic: bool, /// The phase at which this MIR should be "injected" into the compilation process. diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 58d5c94d033..897119c0712 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -2,7 +2,7 @@ use std::fmt; use std::hash::Hash; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cbd60920bc5..907618e428f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -27,7 +27,7 @@ pub type Erase<T: EraseType> = Erased<impl Copy>; pub fn erase<T: EraseType>(src: T) -> Erase<T> { // Ensure the sizes match const { - if std::mem::size_of::<T>() != std::mem::size_of::<T::Result>() { + if size_of::<T>() != size_of::<T::Result>() { panic!("size of T must match erased type T::Result") } }; @@ -231,9 +231,9 @@ trivial! { bool, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option<rustc_ast::expand::allocator::AllocatorKind>, - Option<rustc_attr_parsing::ConstStability>, - Option<rustc_attr_parsing::DefaultBodyStability>, - Option<rustc_attr_parsing::Stability>, + Option<rustc_attr_data_structures::ConstStability>, + Option<rustc_attr_data_structures::DefaultBodyStability>, + Option<rustc_attr_data_structures::Stability>, Option<rustc_data_structures::svh::Svh>, Option<rustc_hir::def::DefKind>, Option<rustc_hir::CoroutineKind>, @@ -256,10 +256,10 @@ trivial! { Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>, rustc_abi::ReprOptions, rustc_ast::expand::allocator::AllocatorKind, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_data_structures::svh::Svh, rustc_errors::ErrorGuaranteed, rustc_hir::Constness, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4ad4427594c..c8708857565 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -41,7 +41,7 @@ use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_target::spec::PanicStrategy; -use {rustc_abi as abi, rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; @@ -999,12 +999,6 @@ rustc_queries! { separate_provide_extern } - query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( - key: DefId - ) -> Option<ty::EarlyBinder<'tcx, ty::Ty<'tcx>>> { - desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) } - } - /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -1533,6 +1527,11 @@ rustc_queries! { query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } } + /// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`, + /// `ty.is_use_cloned()`, etc, since that will prune the environment where possible. + query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `UseCloned`", env.value } + } /// Query backing `Ty::is_sized`. query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 66a9e5fed4c..4834444ed1d 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -165,7 +165,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -#[inline] +#[inline(always)] pub fn query_get_at<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, @@ -370,7 +370,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::<Key<'static>>() > 88 { + if size_of::<Key<'static>>() > 88 { panic!("{}", concat!( "the query `", stringify!($name), @@ -386,7 +386,7 @@ macro_rules! define_callbacks { #[cfg(target_pointer_width = "64")] #[cfg(not(feature = "rustc_randomized_layouts"))] const _: () = { - if mem::size_of::<Value<'static>>() > 64 { + if size_of::<Value<'static>>() > 64 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 72f31cec008..f7b98d935d4 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -315,6 +315,14 @@ pub enum ExprKind<'tcx> { /// (e.g. `foo(a, b)` in `x.foo(a, b)`). fn_span: Span, }, + /// A use expression `x.use`. + ByUse { + /// The expression on which use is applied. + expr: ExprId, + /// The span of use, without the dot and receiver + /// (e.g. `use` in `x.use`). + span: Span, + }, /// A *non-overloaded* dereference. Deref { arg: ExprId, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index a9df4d1625b..d208692f4e7 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -59,6 +59,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_expr(&visitor.thir()[arg]); } } + ByUse { expr, span: _ } => { + visitor.visit_expr(&visitor.thir()[expr]); + } Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { visitor.visit_expr(&visitor.thir()[lhs]); diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 3605f2402e7..5d9b1ddfa38 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -51,6 +51,9 @@ pub enum UpvarCapture { /// depending on inference. ByValue, + /// Upvar is captured by use. This is true when the closure is labeled `use`. + ByUse, + /// Upvar is captured by reference. ByRef(BorrowKind), } @@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> { pub fn is_by_ref(&self) -> bool { match self.info.capture_kind { - ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false, ty::UpvarCapture::ByRef(..) => true, } } @@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { if !self.is_closure_like(def_id.to_def_id()) { return &[]; - }; + } self.closure_typeinfo(def_id).captures } } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 7c9280fae16..9f5e31d894c 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -408,7 +408,7 @@ macro_rules! from_x_for_scalar_int { fn from(u: $ty) -> Self { Self { data: u128::from(u), - size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(), + size: NonZero::new(size_of::<$ty>() as u8).unwrap(), } } } @@ -424,7 +424,7 @@ macro_rules! from_scalar_int_for_x { fn from(int: ScalarInt) -> Self { // The `unwrap` cannot fail because to_bits (if it succeeds) // is guaranteed to return a value that fits into the size. - int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) + int.to_bits(Size::from_bytes(size_of::<$ty>())) .try_into().unwrap() } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4013f7b2c85..edba2a2530f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1890,7 +1890,7 @@ impl<'tcx> TyCtxtAt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let feed = self.tcx.create_def(parent, name, def_kind); @@ -1905,7 +1905,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let data = def_kind.def_path_data(name); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 27576a2ec4a..f24910477dc 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,7 +2,6 @@ use core::intrinsics; use std::marker::PhantomData; -use std::mem; use std::num::NonZero; use std::ptr::NonNull; @@ -176,17 +175,17 @@ impl<'tcx> GenericArgKind<'tcx> { let (tag, ptr) = match self { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*lt.0.0) & TAG_MASK, 0); (REGION_TAG, NonNull::from(lt.0.0).cast()) } GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0); (TYPE_TAG, NonNull::from(ty.0.0).cast()) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 98ca71b86be..b99148f3368 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -203,7 +203,7 @@ impl<'tcx> Instance<'tcx> { if !tcx.sess.opts.share_generics() // However, if the def_id is marked inline(never), then it's fine to just reuse the // upstream monomorphization. - && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_parsing::InlineAttr::Never + && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_data_structures::InlineAttr::Never { return None; } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 272bb0cc915..ebb6a8c08a5 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,20 +1,17 @@ -use std::num::NonZero; use std::ops::Bound; use std::{cmp, fmt}; use rustc_abi::{ - AddressSpace, Align, BackendRepr, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, - PointeeInfo, PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo, + PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_hashes::Hash64; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; -use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -185,12 +182,7 @@ pub const WIDE_PTR_ADDR: usize = 0; /// - For a slice, this is the length. pub const WIDE_PTR_EXTRA: usize = 1; -/// The maximum supported number of lanes in a SIMD vector. -/// -/// This value is selected based on backend support: -/// * LLVM does not appear to have a vector width limit. -/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. -pub const MAX_SIMD_LANES: u64 = 1 << 0xF; +pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES; /// Used in `check_validity_requirement` to indicate the kind of initialization /// that is checked to be valid @@ -762,11 +754,9 @@ where variant_index: VariantIdx, ) -> TyAndLayout<'tcx> { let layout = match this.variants { - Variants::Single { index } - // If all variants but one are uninhabited, the variant layout is the enum layout. - if index == variant_index => - { - this.layout + // If all variants but one are uninhabited, the variant layout is the enum layout. + Variants::Single { index } if index == variant_index => { + return this; } Variants::Single { .. } | Variants::Empty => { @@ -783,29 +773,18 @@ where } let fields = match this.ty.kind() { - ty::Adt(def, _) if def.variants().is_empty() => - bug!("for_variant called on zero-variant enum {}", this.ty), + ty::Adt(def, _) if def.variants().is_empty() => { + bug!("for_variant called on zero-variant enum {}", this.ty) + } ty::Adt(def, _) => def.variant(variant_index).fields.len(), _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: variant_index }, - fields: match NonZero::new(fields) { - Some(fields) => FieldsShape::Union(fields), - None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, - }, - backend_repr: BackendRepr::Memory { sized: true }, - largest_niche: None, - uninhabited: true, - align: tcx.data_layout.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: tcx.data_layout.i8_align.abi, - randomization_seed: Hash64::ZERO, - }) + tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields)) } - Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()), + Variants::Multiple { ref variants, .. } => { + cx.tcx().mk_layout(variants[variant_index].clone()) + } }; assert_eq!(*layout.variants(), Variants::Single { index: variant_index }); diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 6718493f6b3..0fd370a5619 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -93,7 +93,7 @@ impl<H, T> RawList<H, T> { T: Copy, { assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(!slice.is_empty()); let (layout, _offset) = @@ -155,7 +155,7 @@ macro_rules! impl_list_empty { static EMPTY: ListSkeleton<$header_ty, MaxAlign> = ListSkeleton { header: $header_init, len: 0, data: [] }; - assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>()); + assert!(align_of::<T>() <= align_of::<MaxAlign>()); // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 527509af05f..c5509c0a608 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -17,7 +17,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::num::NonZero; use std::ptr::NonNull; -use std::{fmt, mem, str}; +use std::{fmt, str}; pub use adt::*; pub use assoc::*; @@ -27,7 +27,8 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -use rustc_attr_parsing::AttributeKind; +pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -51,7 +52,7 @@ pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; pub use self::closure::{ BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, @@ -637,12 +638,12 @@ impl<'tcx> TermKind<'tcx> { let (tag, ptr) = match self { TermKind::Ty(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0); (TYPE_TAG, NonNull::from(ty.0.0).cast()) } TermKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; @@ -1414,39 +1415,6 @@ pub enum ImplOverlapKind { /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait marker: bool, }, - /// These impls are allowed to overlap, but that raises an - /// issue #33140 future-compatibility warning (tracked in #56484). - /// - /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's - /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different. - /// - /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied on - /// that difference, doing what reduces to the following set of impls: - /// - /// ```compile_fail,(E0119) - /// trait Trait {} - /// impl Trait for dyn Send + Sync {} - /// impl Trait for dyn Sync + Send {} - /// ``` - /// - /// Obviously, once we made these types be identical, that code causes a coherence - /// error and a fairly big headache for us. However, luckily for us, the trait - /// `Trait` used in this case is basically a marker trait, and therefore having - /// overlapping impls for it is sound. - /// - /// To handle this, we basically regard the trait as a marker trait, with an additional - /// future-compatibility warning. To avoid accidentally "stabilizing" this feature, - /// it has the following restrictions: - /// - /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be - /// positive impls. - /// 2. The trait-ref of both impls must be equal. - /// 3. The trait-ref of both impls must be a trait object type consisting only of - /// marker traits. - /// 4. Neither of the impls can have any where-clauses. - /// - /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed. - FutureCompatOrderDepTraitObjects, } /// Useful source information about where a desugared associated type for an @@ -1624,7 +1592,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Returns `true` if the impls are the same polarity and the trait either + /// Returns `Some` if the impls are the same polarity and the trait either /// has no items or is annotated `#[marker]` and prevents item overrides. #[instrument(level = "debug", skip(self), ret)] pub fn impls_are_allowed_to_overlap( @@ -1665,18 +1633,6 @@ impl<'tcx> TyCtxt<'tcx> { return Some(ImplOverlapKind::Permitted { marker: true }); } - if let Some(self_ty1) = - self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id1) - && let Some(self_ty2) = - self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id2) - { - if self_ty1 == self_ty2 { - return Some(ImplOverlapKind::FutureCompatOrderDepTraitObjects); - } else { - debug!("found {self_ty1:?} != {self_ty2:?}"); - } - } - None } @@ -1757,7 +1713,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets all attributes. /// - /// To see if an item has a specific attribute, you should use [`rustc_attr_parsing::find_attr!`] so you can use matching. + /// To see if an item has a specific attribute, you should use [`rustc_attr_data_structures::find_attr!`] so you can use matching. pub fn get_all_attrs( self, did: impl Into<DefId>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 8eaf0a58f70..71fc38cb7ed 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -80,10 +80,10 @@ trivially_parameterized_over_tcx! { rustc_ast::Attribute, rustc_ast::DelimArgs, rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_hir::Constness, rustc_hir::Defaultness, rustc_hir::Safety, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 34d85534d0a..2a3a7705b7b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -569,7 +569,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { + DefPathData::TypeNs(Some(ref mut name)) if Some(visible_parent) != actual_parent => { // Item might be re-exported several times, but filter for the one // that's public and whose identifier isn't `_`. let reexport = self @@ -590,7 +590,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate)); + data = DefPathData::TypeNs(Some(self.tcx().crate_name(def_id.krate))); } _ => {} } diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index 7f0d82d89fe..2d9e0331451 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -23,9 +23,11 @@ fn true_significant_drop_ty<'tcx>( match key.disambiguated_data.data { rustc_hir::definitions::DefPathData::CrateRoot => { - name_rev.push(tcx.crate_name(did.krate)) + name_rev.push(tcx.crate_name(did.krate)); + } + rustc_hir::definitions::DefPathData::TypeNs(symbol) => { + name_rev.push(symbol.unwrap()); } - rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol), _ => return None, } if let Some(parent) = key.parent { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 237aa66f486..0c68913904f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> { ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty)) } + /// Checks whether `ty: UseCloned` holds while ignoring region constraints. + /// + /// This function should not be used if there is an `InferCtxt` available. + /// Use `InferCtxt::type_is_copy_modulo_regions` instead. + pub fn type_is_use_cloned_modulo_regions( + self, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty)) + } + /// Returns the deeply last field of nested structures, or the same type if /// not a structure at all. Corresponds to the only possible unsized field, /// and its type can be used to determine unsizing strategy. diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index d70d70a31a4..a29c0116266 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -28,3 +28,6 @@ rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 581f45db6c4..50ca924baf9 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Yield { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::WrapUnsafeBinder { .. } => { // these are not places, so we need to make a temporary. debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 2c9a1de7f99..97d34b85f50 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.and(Rvalue::Use(operand)) } + + ExprKind::ByUse { expr, span: _ } => { + let operand = unpack!( + block = + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + ); + block.and(Rvalue::Use(operand)) + } } } diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index ca55d36bfc6..34524aed406 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -56,6 +56,7 @@ impl Category { | ExprKind::RawBorrow { .. } | ExprKind::Yield { .. } | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 72443e2f60d..333e69475c5 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -4,11 +4,14 @@ use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; -use rustc_middle::ty::CanonicalUserTypeAnnotation; +use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty}; +use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; @@ -289,6 +292,57 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(block); success.unit() } + ExprKind::ByUse { expr, span } => { + let place = unpack!(block = this.as_place(block, expr)); + let ty = place.ty(&this.local_decls, this.tcx).ty; + + if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Copy(place)), + ); + block.unit() + } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { + // Convert `expr.use` to a call like `Clone::clone(&expr)` + let success = this.cfg.start_new_block(); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; + let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); + let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); + let ref_place = this.temp(ref_ty, span); + this.cfg.push_assign( + block, + source_info, + ref_place, + Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place), + ); + this.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func, + args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }] + .into(), + destination, + target: Some(success), + unwind: UnwindAction::Unreachable, + call_source: CallSource::Misc, + fn_span: expr_span, + }, + ); + success.unit() + } else { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Move(place)), + ); + block.unit() + } + } ExprKind::Use { source } => this.expr_into_dest(destination, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 94955954934..f9fa750e750 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( .map(|captured_place| { let name = captured_place.to_symbol(); match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => name, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name, ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")), } }) @@ -612,7 +612,8 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst - | DefKind::Static { .. } => (vec![], tcx.type_of(def_id).instantiate_identity(), None), + | DefKind::Static { .. } + | DefKind::GlobalAsm => (vec![], tcx.type_of(def_id).instantiate_identity(), None), DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => { let sig = tcx.liberate_late_bound_regions( def_id.to_def_id(), @@ -871,7 +872,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(FieldIdx::new(i), ty)); match capture { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c2eafd0a74e..d78c874c766 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -451,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Tuple { .. } | ExprKind::Unary { .. } | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | ExprKind::Break { .. } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index fa5db32d913..8e96d46dac2 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -8,7 +8,6 @@ #![feature(if_let_guard)] #![feature(let_chains)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // The `builder` module used to be named `build`, but that was causing GitHub's diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 7139516702e..e46e8c9871a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -464,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> { } } + hir::ExprKind::Use(expr, span) => { + ExprKind::ByUse { expr: self.mirror_expr(expr), span } + } + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => { ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) } } @@ -648,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> { } }, - hir::ExprKind::Closure { .. } => { + hir::ExprKind::Closure(hir::Closure { .. }) => { let closure_ty = self.typeck_results.expr_ty(expr); let (def_id, args, movability) = match *closure_ty.kind() { ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None), @@ -1248,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> { match upvar_capture { ty::UpvarCapture::ByValue => captured_place_expr, + ty::UpvarCapture::ByUse => { + let span = captured_place_expr.span; + let expr_id = self.thir.exprs.push(captured_place_expr); + + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: upvar_ty, + span: closure_expr.span, + kind: ExprKind::ByUse { expr: expr_id, span }, + } + } ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::Immutable => BorrowKind::Shared, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 954d0cf97ab..dadd1e85461 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Borrow { .. } | Box { .. } | Call { .. } + | ByUse { .. } | Closure { .. } | ConstBlock { .. } | ConstParam { .. } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index cd56d93afcf..16cef0ec3ac 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "}", depth_lvl); } + ByUse { expr, span } => { + print_indented!(self, "ByUse {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } Deref { arg } => { print_indented!(self, "Deref {", depth_lvl); self.print_expr(*arg, depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 293bcbef21b..a171f9641bb 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -21,3 +21,6 @@ rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index a8a56baa1ff..a0efc623b8e 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -7,7 +7,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::ty; diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index fb8d0ac5e74..4dc91723f03 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -30,3 +30,6 @@ rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0f5fcb0d8eb..9cd7045a0a2 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -78,7 +78,6 @@ use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir}; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::kw; pub(crate) fn coroutine_by_move_body_def_id<'tcx>( tcx: TyCtxt<'tcx>, @@ -170,7 +169,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( // this when building the field projection in the MIR body later on. let mut parent_capture_ty = parent_capture.place.ty(); parent_capture_ty = match parent_capture.info.capture_kind { - ty::UpvarCapture::ByValue => parent_capture_ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref( tcx, tcx.lifetimes.re_erased, @@ -214,7 +213,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. - let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody); + let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5df12ac4d8b..739cee5d7f4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -12,7 +12,6 @@ #![feature(never_type)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use hir::ConstContext; @@ -316,6 +315,10 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { // All body-owners have MIR associated with them. let mut set: FxIndexSet<_> = tcx.hir_body_owners().collect(); + // Remove the fake bodies for `global_asm!`, since they're not useful + // to be emitted (`--emit=mir`) or encoded (in metadata). + set.retain(|&def_id| !matches!(tcx.def_kind(def_id), DefKind::GlobalAsm)); + // Coroutine-closures (e.g. async closures) have an additional by-move MIR // body that isn't in the HIR. for body_owner in tcx.hir_body_owners() { diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 36b76d261de..51be8e55fa7 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -22,3 +22,6 @@ serde = "1" serde_json = "1" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 714b64b3a23..8f6914f3d72 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -4,7 +4,6 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(let_chains)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 63aa60f2f26..e119d23d41a 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -24,3 +24,6 @@ nightly = [ "rustc_index/nightly", "rustc_type_ir/nightly", ] + +[lints] +workspace = true diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index d67ae2550d9..f6963a79067 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(rustc::usage_of_type_ir_inherent)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod canonicalizer; diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c9dcab0c871..b78ac197dbb 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -26,3 +26,5 @@ unicode-width = "0.2.0" [dev-dependencies] termcolor = "1.2" +[lints] +workspace = true diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1d5b5942170..6d4308cda1a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,11 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later + +parse_async_use_order_incorrect = the order of `use` and `async` is incorrect + .suggestion = try switching the order + parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` @@ -348,6 +353,9 @@ parse_incorrect_use_of_await = incorrect use of `await` parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation +parse_incorrect_use_of_use = incorrect use of `use` + .parentheses_suggestion = `use` is not a method call, try removing the parentheses + parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: `pub(crate)`: visible only on the current crate diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8d2fd595942..e090d9cf760 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_incorrect_use_of_use)] +pub(crate) struct IncorrectUseOfUse { + #[primary_span] + #[suggestion( + parse_parentheses_suggestion, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( parse_incorrect_use_of_await_postfix_suggestion, @@ -1500,6 +1513,14 @@ pub(crate) struct AsyncMoveOrderIncorrect { } #[derive(Diagnostic)] +#[diag(parse_async_use_order_incorrect)] +pub(crate) struct AsyncUseOrderIncorrect { + #[primary_span] + #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_double_colon_in_bound)] pub(crate) struct DoubleColonInBound { #[primary_span] @@ -1668,6 +1689,13 @@ pub(crate) struct AsyncMoveBlockIn2015 { } #[derive(Diagnostic)] +#[diag(parse_async_use_block_in_2015)] +pub(crate) struct AsyncUseBlockIn2015 { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_async_bound_modifier_in_2015)] pub(crate) struct AsyncBoundModifierIn2015 { #[primary_span] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 1a104ff5e33..2edc8c83017 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -12,7 +12,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(string_from_utf8_lossy_owned)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 94db43bb59f..bb227a58cf1 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -31,15 +31,15 @@ use super::{ SeqSep, TokenType, }; use crate::errors::{ - AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, - BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, - ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, - ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, + AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, + ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, + IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, + QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, @@ -572,10 +572,17 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); } - if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { - // The 2015 edition is in use because parsing of `async move` has failed. + if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use)) + && self.prev_token.is_keyword(kw::Async) + { + // The 2015 edition is in use because parsing of `async move` or `async use` has failed. let span = self.prev_token.span.to(self.token.span); - return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + if self.token.is_keyword(kw::Move) { + return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + } else { + // kw::Use + return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span })); + } } let expect = tokens_to_string(&expected); @@ -1991,7 +1998,7 @@ impl<'a> Parser<'a> { self.parse_expr() } .map_err(|mut err| { - err.span_label(await_sp, "while parsing this incorrect await expression"); + err.span_label(await_sp, format!("while parsing this incorrect await expression")); err })?; Ok((expr.span, expr, is_question)) @@ -2030,6 +2037,21 @@ impl<'a> Parser<'a> { self.dcx().emit_err(IncorrectUseOfAwait { span }); } } + /// + /// If encountering `x.use()`, consumes and emits an error. + pub(super) fn recover_from_use(&mut self) { + if self.token == token::OpenDelim(Delimiter::Parenthesis) + && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + { + // var.use() + let lo = self.token.span; + self.bump(); // ( + let span = lo.to(self.token.span); + self.bump(); // ) + + self.dcx().emit_err(IncorrectUseOfUse { span }); + } + } pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> { let is_try = self.token.is_keyword(kw::Try); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0a08c6faeb4..b37dd64fbed 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -778,6 +778,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", + ExprKind::Use(_, _) => "`.use`", ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", ExprKind::Err(_) => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), @@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> { return Ok(self.mk_await_expr(self_arg, lo)); } + if self.eat_keyword(exp!(Use)) { + let use_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_span); + return Ok(self.mk_use_expr(self_arg, lo)); + } + // Post-fix match if self.eat_keyword(exp!(Match)) { let match_span = self.prev_token.span; @@ -1397,6 +1404,7 @@ impl<'a> Parser<'a> { } else if this.check_path() { this.parse_expr_path_start() } else if this.check_keyword(exp!(Move)) + || this.check_keyword(exp!(Use)) || this.check_keyword(exp!(Static)) || this.check_const_closure() { @@ -2388,7 +2396,7 @@ impl<'a> Parser<'a> { Ok(closure) } - /// Parses an optional `move` prefix to a closure-like construct. + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { let move_kw_span = self.prev_token.span; @@ -2401,6 +2409,16 @@ impl<'a> Parser<'a> { } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } + } else if self.eat_keyword(exp!(Use)) { + let use_kw_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span); + // Check for `use async` and recover + if self.check_keyword(exp!(Async)) { + let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span })) + } else { + Ok(CaptureBy::Use { use_kw: use_kw_span }) + } } else { Ok(CaptureBy::Ref) } @@ -3415,7 +3433,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(lookahead, &[kw]) && (( // `async move {` - self.is_keyword_ahead(lookahead + 1, &[kw::Move]) + self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() }) @@ -3818,6 +3836,13 @@ impl<'a> Parser<'a> { await_expr } + fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> { + let span = lo.to(self.prev_token.span); + let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span)); + self.recover_from_use(); + use_expr + } + pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> { P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } @@ -3966,6 +3991,7 @@ impl MutVisitor for CondChecker<'_> { } ExprKind::Unary(_, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c3b1956ad2e..0b9350c7199 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -209,7 +209,7 @@ impl<'a> Parser<'a> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); - let info = if self.eat_keyword_case(exp!(Use), case) { + let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { self.parse_use_item()? } else if self.check_fn_front_matter(check_pub, case) { // FUNCTION ITEM @@ -1277,6 +1277,21 @@ impl<'a> Parser<'a> { None } + fn is_use_closure(&self) -> bool { + if self.token.is_keyword(kw::Use) { + // Check if this could be a closure. + self.look_ahead(1, |token| { + // Move or Async here would be an error but still we're parsing a closure + let dist = + if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 }; + + self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr)) + }) + } else { + false + } + } + fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) @@ -1290,7 +1305,7 @@ impl<'a> Parser<'a> { if self.check_keyword(exp!(Static)) { // Check if this could be a closure. !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) { + if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) { return true; } matches!(token.kind, token::Or | token::OrOr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7dabc28c645..4ec8d9e5e49 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -813,9 +813,9 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(0, &[kw::Const]) && self.look_ahead(1, |t| match &t.kind { // async closures do not work with const closures, so we do not parse that here. - token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => { - true - } + token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No) + | token::OrOr + | token::Or => true, _ => false, }) } diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 110546d0ba6..886438fd583 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -619,7 +619,7 @@ impl Iterator for TokenTypeSetIter { type Item = TokenType; fn next(&mut self) -> Option<TokenType> { - let num_bits: u32 = (std::mem::size_of_val(&self.0.0) * 8) as u32; + let num_bits: u32 = (size_of_val(&self.0.0) * 8) as u32; assert_eq!(num_bits, 128); let z = self.0.0.trailing_zeros(); if z == num_bits { diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index a39cca716d2..a720903097a 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -8,3 +8,6 @@ edition = "2024" rustc_index = { path = "../rustc_index", default-features = false } rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 3b985621b57..287bd8678da 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -13,7 +13,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub use Alignment::*; diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index ba81ef3103b..4cd7fde6034 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -26,3 +26,6 @@ rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 91916b8f5fc..c6ae2c0fb9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1998,7 +1998,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) if item.is_some() { match target { - Target::Struct | Target::Union | Target::Enum => {} + Target::Struct | Target::Union | Target::Enum => continue, Target::Fn | Target::Method(_) => { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 92ea49f18e5..1278e98afcf 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -107,12 +107,12 @@ impl<'k> StatCollector<'k> { let node = self.nodes.entry(label1).or_insert(Node::new()); node.stats.count += 1; - node.stats.size = std::mem::size_of_val(val); + node.stats.size = size_of_val(val); if let Some(label2) = label2 { let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new()); subnode.count += 1; - subnode.size = std::mem::size_of_val(val); + subnode.size = size_of_val(val); } } @@ -255,9 +255,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_body(self, b); } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) { + fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) { self.record("Mod", None, m); - hir_visit::walk_mod(self, m, n) + hir_visit::walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { @@ -328,6 +328,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Array, Call, MethodCall, + Use, Tup, Binary, Unary, @@ -626,7 +627,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { (self, e, e.kind, None, ast, Expr, ExprKind), [ Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, - If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, + If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 1aa077ad2bb..93ff0f66d69 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -12,7 +12,6 @@ #![feature(map_try_insert)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::query::Providers; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 24dc018c661..822804893fe 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -426,6 +426,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Array(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | hir::ExprKind::AddrOf(..) @@ -705,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } } } @@ -1031,6 +1032,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(receiver, succ) } + hir::ExprKind::Use(expr, _) => { + let succ = self.check_is_ty_uninhabited(expr, succ); + self.propagate_through_expr(expr, succ) + } + hir::ExprKind::Tup(exprs) => self.propagate_through_exprs(exprs, succ), hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => { @@ -1418,6 +1424,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { // no correctness conditions related to liveness hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) @@ -1493,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> { for (&var_hir_id, min_capture_list) in closure_min_captures { for captured_place in min_capture_list { match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => continue, }; let span = captured_place.get_capture_kind_span(self.ir.tcx); diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 6e2f976e5b0..4c1f6ea141e 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -39,7 +39,7 @@ impl RWUTable { /// Size of packed RWU in bits. const RWU_BITS: usize = 4; /// Size of a word in bits. - const WORD_BITS: usize = std::mem::size_of::<u8>() * 8; + const WORD_BITS: usize = size_of::<u8>() * 8; /// Number of packed RWUs that fit into a single word. const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index cb17b0f6cf5..d35aedf9a56 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -182,6 +182,7 @@ impl CheckInlineAssembly { | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) + | ExprKind::Use(..) | ExprKind::Tup(..) | ExprKind::Binary(..) | ExprKind::Unary(..) diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 40d549630ac..0624fe96cd9 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -43,3 +43,6 @@ rustc = [ "smallvec/may_dangle", "rustc_index/nightly", ] + +[lints] +workspace = true diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index a3400ebb799..eeea724a29b 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(feature = "rustc", feature(let_chains))] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod constructor; diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index 365bc2d863f..8980b644f59 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -5,7 +5,7 @@ use rustc_pattern_analysis::usefulness::{PlaceValidity, UsefulnessReport}; use rustc_pattern_analysis::{MatchArm, PatCx, PrivateUninhabitedField}; /// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup. -pub fn init_tracing() { +fn init_tracing() { use tracing_subscriber::Layer; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; @@ -24,7 +24,7 @@ pub fn init_tracing() { /// A simple set of types. #[allow(dead_code)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Ty { +pub(super) enum Ty { /// Booleans Bool, /// 8-bit unsigned integers @@ -41,7 +41,7 @@ pub enum Ty { /// The important logic. impl Ty { - pub fn sub_tys(&self, ctor: &Constructor<Cx>) -> Vec<Self> { + pub(super) fn sub_tys(&self, ctor: &Constructor<Cx>) -> Vec<Self> { use Constructor::*; match (ctor, *self) { (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(), @@ -63,7 +63,7 @@ impl Ty { } } - pub fn ctor_set(&self) -> ConstructorSet<Cx> { + fn ctor_set(&self) -> ConstructorSet<Cx> { match *self { Ty::Bool => ConstructorSet::Bool, Ty::U8 => ConstructorSet::Integers { @@ -104,7 +104,7 @@ impl Ty { } } - pub fn write_variant_name( + fn write_variant_name( &self, f: &mut std::fmt::Formatter<'_>, ctor: &Constructor<Cx>, @@ -120,7 +120,7 @@ impl Ty { } /// Compute usefulness in our simple context (and set up tracing for easier debugging). -pub fn compute_match_usefulness<'p>( +pub(super) fn compute_match_usefulness<'p>( arms: &[MatchArm<'p, Cx>], ty: Ty, scrut_validity: PlaceValidity, @@ -137,7 +137,7 @@ pub fn compute_match_usefulness<'p>( } #[derive(Debug)] -pub struct Cx; +pub(super) struct Cx; /// The context for pattern analysis. Forwards anything interesting to `Ty` methods. impl PatCx for Cx { diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 242c67d732a..dc00ea8af43 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -18,3 +18,6 @@ rustc_span = { path = "../rustc_span" } rustc_ty_utils = { path = "../rustc_ty_utils" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5271d03a6f6..5e3e8d69b60 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -6,7 +6,6 @@ #![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod errors; diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index c85156e059e..42f78448151 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -20,3 +20,6 @@ rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 73c205fdb17..40da46a027d 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -8,7 +8,6 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_data_structures::stable_hasher::HashStable; diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 3e8ccb51021..c34d1170f0e 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -25,3 +25,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 5e6bee1dbd5..6ece01c211b 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1299,12 +1299,11 @@ impl Default for TaskDeps { #[cfg(debug_assertions)] node: None, reads: EdgesVec::new(), - read_set: FxHashSet::default(), + read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()), phantom_data: PhantomData, } } } - // A data structure that stores Option<DepNodeColor> values as a contiguous // array, using one u32 per entry. struct DepNodeColorMap { diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index bc78878a84a..2c6fd7d494f 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -63,7 +63,7 @@ rustc_index::newtype_index! { pub struct SerializedDepNodeIndex {} } -const DEP_NODE_SIZE: usize = std::mem::size_of::<SerializedDepNodeIndex>(); +const DEP_NODE_SIZE: usize = size_of::<SerializedDepNodeIndex>(); /// Amount of padding we need to add to the edge list data so that we can retrieve every /// SerializedDepNodeIndex with a fixed-size read then mask. const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; @@ -175,7 +175,7 @@ impl EdgeHeader { #[inline] fn mask(bits: usize) -> usize { - usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits) + usize::MAX >> ((size_of::<usize>() * 8) - bits) } impl SerializedDepGraph { @@ -208,9 +208,8 @@ impl SerializedDepGraph { // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 // length is about the same fractional overhead and it amortizes for yet greater lengths. - let mut edge_list_data = Vec::with_capacity( - graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<D>>(), - ); + let mut edge_list_data = + Vec::with_capacity(graph_bytes - node_count * size_of::<SerializedNodeHeader<D>>()); for _index in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size @@ -300,7 +299,7 @@ struct Unpacked { // M..M+N bytes per index // M+N..16 kind impl<D: Deps> SerializedNodeHeader<D> { - const TOTAL_BITS: usize = std::mem::size_of::<DepKind>() * 8; + const TOTAL_BITS: usize = size_of::<DepKind>() * 8; const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index ee984095ad8..a546362414c 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -6,7 +6,6 @@ #![feature(hash_raw_entry)] #![feature(let_chains)] #![feature(min_specialization)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod cache; diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index f4771f1af2c..8958a3ac304 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -28,3 +28,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 95d637b6b22..33f529851ae 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, sym}; use tracing::debug; use crate::{ImplTraitContext, InvocationParent, Resolver}; @@ -38,7 +38,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { fn create_def( &mut self, node_id: NodeId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -89,7 +89,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.visit_macro_invoc(field.id); } else { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); - let def = self.create_def(field.id, name, DefKind::Field, field.span); + let def = self.create_def(field.id, Some(name), DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); } } @@ -161,7 +161,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { return self.visit_macro_invoc(i.id); } }; - let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def_id = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); @@ -175,7 +175,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Struct, ctor_kind), i.span, ); @@ -211,20 +211,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } let (return_id, return_span) = coroutine_kind.return_id(); - let return_def = - self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span); + let return_def = self.create_def(return_id, None, DefKind::OpaqueTy, return_span); self.with_parent(return_def, |this| this.visit_fn_ret_ty(output)); // If this async fn has no body (i.e. it's an async fn signature in a trait) // then the closure_def will never be used, and we should avoid generating a // def-id for it. if let Some(body) = body { - let closure_def = self.create_def( - coroutine_kind.closure_id(), - kw::Empty, - DefKind::Closure, - span, - ); + let closure_def = + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(closure_def, |this| this.visit_block(body)); } } @@ -235,7 +230,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Async closures desugar to closures inside of closures, so // we must create two defs. let coroutine_def = - self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span); + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(coroutine_def, |this| this.visit_expr(body)); } _ => visit::walk_fn(self, fn_kind), @@ -243,7 +238,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, kw::Empty, DefKind::Use, use_tree.span); + self.create_def(id, None, DefKind::Use, use_tree.span); visit::walk_use_tree(self, use_tree, id); } @@ -262,7 +257,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), }; - let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span); + let def = self.create_def(fi.id, Some(fi.ident.name), def_kind, fi.span); self.with_parent(def, |this| visit::walk_item(this, fi)); } @@ -271,12 +266,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if v.is_placeholder { return self.visit_macro_invoc(v.id); } - let def = self.create_def(v.id, v.ident.name, DefKind::Variant, v.span); + let def = self.create_def(v.id, Some(v.ident.name), DefKind::Variant, v.span); self.with_parent(def, |this| { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Variant, ctor_kind), v.span, ); @@ -312,7 +307,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { GenericParamKind::Type { .. } => DefKind::TyParam, GenericParamKind::Const { .. } => DefKind::ConstParam, }; - self.create_def(param.id, param.ident.name, def_kind, param.ident.span); + self.create_def(param.id, Some(param.ident.name), def_kind, param.ident.span); // impl-Trait can happen inside generic parameters, like // ``` @@ -335,7 +330,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let def = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } @@ -347,8 +342,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let parent = - self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); + let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } @@ -356,18 +350,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let parent_def = match expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { - self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) + self.create_def(expr.id, None, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { for attr in &expr.attrs { visit::walk_attribute(self, attr); } - let def = self.create_def( - constant.id, - kw::Empty, - DefKind::InlineConst, - constant.value.span, - ); + let def = + self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span); self.with_parent(def, |this| visit::walk_anon_const(this, constant)); return; } @@ -391,7 +381,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, name, kind, ty.span); + let id = self.create_def(*id, Some(name), kind, ty.span); match self.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. @@ -495,7 +485,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { InlineAsmOperand::Const { anon_const } => { let def = self.create_def( anon_const.id, - kw::Empty, + None, DefKind::InlineConst, anon_const.value.span, ); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 92f5fba1f9b..79479986d07 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2995,7 +2995,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } // HACK(min_const_generics, generic_const_exprs): We - // want to keep allowing `[0; std::mem::size_of::<*mut T>()]` + // want to keep allowing `[0; size_of::<*mut T>()]` // with a future compat lint for now. We do this by adding an // additional special case for repeat expressions. // diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4c5d4041022..f724ecf76b3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -20,7 +20,6 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::{Cell, RefCell}; @@ -1340,7 +1339,7 @@ impl<'tcx> Resolver<'_, 'tcx> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, expn_id: ExpnId, span: Span, diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 900cd4243b1..e18ed121ca5 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -15,3 +15,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } + +[lints] +workspace = true diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index 55be931bcd6..e4792563e71 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -5,7 +5,6 @@ // tidy-alphabetical-start #![feature(let_chains)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod cfi; diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 948242352e7..10bfe14abde 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -16,3 +16,6 @@ thin-vec = "0.2.12" rustc_macros = { path = "../rustc_macros" } tempfile = "3.2" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index aa7c2858466..4a475805697 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -7,7 +7,7 @@ use crate::serialize::Decoder; /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len<T>() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. - (std::mem::size_of::<T>() * 8 + 6) / 7 + (size_of::<T>() * 8 + 6) / 7 } /// Returns the length of the longest LEB128 encoding of all supported integer types. diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 9e9b78cfdd5..13c1a273eb8 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -14,7 +14,6 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index a087725d34d..4b2b41ba845 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -37,3 +37,6 @@ features = [ "Win32_Foundation", "Win32_System_LibraryLoader", ] + +[lints] +workspace = true diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index ec83761da4a..cc2decc2fe4 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -92,7 +92,7 @@ fn current_dll_path() -> Result<PathBuf, String> { if libc::loadquery( libc::L_GETINFO, buffer.as_mut_ptr() as *mut u8, - (std::mem::size_of::<libc::ld_info>() * buffer.len()) as u32, + (size_of::<libc::ld_info>() * buffer.len()) as u32, ) >= 0 { break; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d432e84fdb2..0e19b982a13 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -7,7 +7,6 @@ // To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums // with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers"). #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod errors; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index aa1e9762f39..bcd9a73d9d3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -930,7 +930,6 @@ fn default_emitter( .fluent_bundle(bundle) .sm(source_map) .short_message(short) - .teach(sopts.unstable_opts.teach) .diagnostic_width(sopts.diagnostic_width) .macro_backtrace(macro_backtrace) .track_diagnostics(track_diagnostics) diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index a11df9a9c9b..d14bff73b8b 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -18,3 +18,6 @@ scoped-tls = "1.0" stable_mir = {path = "../stable_mir" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 2215e2f01ad..9f888875306 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -15,7 +15,6 @@ )] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod rustc_internal; diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 43a2d692577..a6f86151b81 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -22,3 +22,6 @@ sha2 = "0.10.1" tracing = "0.1" unicode-width = "0.2.0" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 36f9b4cff60..da298080ed2 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -23,11 +23,27 @@ pub enum Edition { Edition2021, /// The 2024 edition Edition2024, + /// The future edition - this variant will always exist and features associated with this + /// edition can be moved to the next 20XX edition when it is established and it is confirmed + /// that those features will be part of that edition. + /// + /// This variant allows edition changes to be implemented before being assigned to a concrete + /// edition - primarily when there are two different unstable behaviours that need tested across + /// an edition boundary. + /// + /// This edition will be permanently unstable and any features associated with this edition + /// must also be behind a feature gate. + EditionFuture, } // Must be in order from oldest to newest. -pub const ALL_EDITIONS: &[Edition] = - &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024]; +pub const ALL_EDITIONS: &[Edition] = &[ + Edition::Edition2015, + Edition::Edition2018, + Edition::Edition2021, + Edition::Edition2024, + Edition::EditionFuture, +]; pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024"; @@ -42,6 +58,7 @@ impl fmt::Display for Edition { Edition::Edition2018 => "2018", Edition::Edition2021 => "2021", Edition::Edition2024 => "2024", + Edition::EditionFuture => "future", }; write!(f, "{s}") } @@ -54,6 +71,7 @@ impl Edition { Edition::Edition2018 => "rust_2018_compatibility", Edition::Edition2021 => "rust_2021_compatibility", Edition::Edition2024 => "rust_2024_compatibility", + Edition::EditionFuture => "edition_future_compatibility", } } @@ -63,6 +81,7 @@ impl Edition { Edition::Edition2018 => true, Edition::Edition2021 => true, Edition::Edition2024 => true, + Edition::EditionFuture => false, } } @@ -85,6 +104,11 @@ impl Edition { pub fn at_least_rust_2024(self) -> bool { self >= Edition::Edition2024 } + + /// Are we allowed to use features from the future edition? + pub fn at_least_edition_future(self) -> bool { + self >= Edition::EditionFuture + } } impl FromStr for Edition { @@ -95,6 +119,7 @@ impl FromStr for Edition { "2018" => Ok(Edition::Edition2018), "2021" => Ok(Edition::Edition2021), "2024" => Ok(Edition::Edition2024), + "future" => Ok(Edition::EditionFuture), _ => Err(()), } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 798e186a94b..f19d4d9f362 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -32,7 +32,6 @@ #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(slice_as_chunks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // The code produced by the `Encodable`/`Decodable` derive macros refer to diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 573c65a772c..9e7f5047eb3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -862,6 +862,7 @@ symbols! { eprint_macro, eprintln_macro, eq, + ergonomic_clones, ermsb_target_feature, exact_div, except, @@ -1717,6 +1718,7 @@ symbols! { rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, + rust_future, rust_logo, rust_out, rustc, @@ -2185,6 +2187,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + use_cloned, use_extern_macros, use_nested_groups, used, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 90ddf4c8a04..89fe7ef2e40 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -19,3 +19,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 4312c82815c..269401ef3a2 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -93,7 +93,6 @@ #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_hir::def::DefKind; diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 189b19b0286..6a0268cdee7 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -22,3 +22,6 @@ default-features = false features = ["elf", "macho"] version = "0.36.2" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 198d08864be..6d0ee3c7ee5 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -31,6 +31,7 @@ mod sparc64; mod wasm; mod x86; mod x86_64; +mod x86_win32; mod x86_win64; mod xtensa; @@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> { }; let reg_struct_return = cx.x86_abi_opt().reg_struct_return; let opts = x86::X86Options { flavor, regparm, reg_struct_return }; - x86::compute_abi_info(cx, self, opts); + if spec.is_like_msvc { + x86_win32::compute_abi_info(cx, self, opts); + } else { + x86::compute_abi_info(cx, self, opts); + } } "x86_64" => match abi { ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 73aff85a0ad..6f112b49400 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -36,7 +36,7 @@ where if t.abi_return_struct_as_int || opts.reg_struct_return { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. - if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { + if fn_abi.ret.layout.is_single_fp_element(cx) { match fn_abi.ret.layout.size.bytes() { 4 => fn_abi.ret.cast_to(Reg::f32()), 8 => fn_abi.ret.cast_to(Reg::f64()), @@ -64,31 +64,11 @@ where continue; } - // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 - // See https://reviews.llvm.org/D72114 for Clang behavior - let t = cx.target_spec(); let align_4 = Align::from_bytes(4).unwrap(); let align_16 = Align::from_bytes(16).unwrap(); - if t.is_like_msvc - && arg.layout.is_adt() - && let Some(max_repr_align) = arg.layout.max_repr_align - && max_repr_align > align_4 - { - // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. - // Summarized here: - // - Arguments with _requested_ alignment > 4 are passed indirectly. - // - For backwards compatibility, arguments with natural alignment > 4 are still passed - // on stack (via `byval`). For example, this includes `double`, `int64_t`, - // and structs containing them, provided they lack an explicit alignment attribute. - assert!( - arg.layout.align.abi >= max_repr_align, - "abi alignment {:?} less than requested alignment {max_repr_align:?}", - arg.layout.align.abi, - ); - arg.make_indirect(); - } else if arg.layout.is_aggregate() { + if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized // here, they are: diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs new file mode 100644 index 00000000000..554a7368848 --- /dev/null +++ b/compiler/rustc_target/src/callconv/x86_win32.rs @@ -0,0 +1,81 @@ +use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface}; + +use crate::callconv::FnAbi; +use crate::spec::HasTargetSpec; + +pub(crate) fn compute_abi_info<'a, Ty, C>( + cx: &C, + fn_abi: &mut FnAbi<'a, Ty>, + opts: super::x86::X86Options, +) where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // https://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = cx.target_spec(); + // MSVC does not special-case 1-element float aggregates, unlike others. + // GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed: + // - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028 + // - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667 + if t.abi_return_struct_as_int || opts.reg_struct_return { + match fn_abi.ret.layout.size.bytes() { + 1 => fn_abi.ret.cast_to(Reg::i8()), + 2 => fn_abi.ret.cast_to(Reg::i16()), + 4 => fn_abi.ret.cast_to(Reg::i32()), + 8 => fn_abi.ret.cast_to(Reg::i64()), + _ => fn_abi.ret.make_indirect(), + } + } else { + fn_abi.ret.make_indirect(); + } + } else { + fn_abi.ret.extend_integer_width_to(32); + } + } + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() || !arg.layout.is_sized() { + continue; + } + + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 + // See https://reviews.llvm.org/D72114 for Clang behavior + + let align_4 = Align::from_bytes(4).unwrap(); + + if arg.layout.is_adt() + && let Some(max_repr_align) = arg.layout.max_repr_align + && max_repr_align > align_4 + { + // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. + // Summarized here: + // - Arguments with _requested_ alignment > 4 are passed indirectly. + // - For backwards compatibility, arguments with natural alignment > 4 are still passed + // on stack (via `byval`). For example, this includes `double`, `int64_t`, + // and structs containing them, provided they lack an explicit alignment attribute. + assert!( + arg.layout.align.abi >= max_repr_align, + "abi alignment {:?} less than requested alignment {max_repr_align:?}", + arg.layout.align.abi, + ); + arg.make_indirect(); + } else if arg.layout.is_aggregate() { + // Alignment of the `byval` argument. + // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. + let byval_align = align_4; + arg.pass_by_stack_offset(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } + } + + super::x86::fill_inregs(cx, fn_abi, opts, false); +} diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 7ebe96960ed..a8d7da5692d 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 72202129f5b..15936c731ea 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1915,7 +1915,6 @@ supported_targets! { ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), ("i686-win7-windows-msvc", i686_win7_windows_msvc), - ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), @@ -3503,7 +3502,15 @@ impl Target { return load_file(&p); } - Err(format!("Could not find specification for target {target_tuple:?}")) + // Leave in a specialized error message for the removed target. + // FIXME: If you see this and it's been a few months after this has been released, + // you can probably remove it. + if target_tuple == "i586-pc-windows-msvc" { + Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\ + Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into()) + } else { + Err(format!("Could not find specification for target {target_tuple:?}")) + } } TargetTuple::TargetJson { ref contents, .. } => { let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs deleted file mode 100644 index 394e6f9e6bf..00000000000 --- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::spec::Target; - -pub(crate) fn target() -> Target { - let mut base = super::i686_pc_windows_msvc::target(); - base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target - base.cpu = "pentium".into(); - base.llvm_target = "i586-pc-windows-msvc".into(); - base -} diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1c61e23362a..5def437bd80 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -26,3 +26,6 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2" tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f373706b296..5cf0600ade8 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } + fn type_is_use_cloned_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let ty = self.resolve_vars_if_possible(ty); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) + } + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index b235d0da83c..b18fb0fb8fd 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -31,7 +31,6 @@ #![feature(unwrap_infallible)] #![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc -#![warn(unreachable_pub)] // For rustdoc // tidy-alphabetical-end pub mod error_reporting; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 75f53b063d1..39333082acd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -2,7 +2,7 @@ //! //! For concrete constants, this is fairly simple as we can just try and evaluate it. //! -//! When dealing with polymorphic constants, for example `std::mem::size_of::<T>() - 1`, +//! When dealing with polymorphic constants, for example `size_of::<T>() - 1`, //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 77dbb43465e..0a54b8468fe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1925,9 +1925,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let mut impl_candidate = None; for c in impls { if let Some(prev) = impl_candidate.replace(c) { - if self.prefer_lhs_over_victim(has_non_region_infer, c, prev) { + if self.prefer_lhs_over_victim(has_non_region_infer, c, prev.0) { // Ok, prefer `c` over the previous entry - } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c) { + } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c.0) { // Ok, keep `prev` instead of the new entry impl_candidate = Some(prev); } else { @@ -1986,7 +1986,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &self, has_non_region_infer: bool, (lhs, lhs_evaluation): (DefId, EvaluationResult), - (victim, victim_evaluation): (DefId, EvaluationResult), + victim: DefId, ) -> bool { let tcx = self.tcx(); // See if we can toss out `victim` based on specialization. @@ -2002,14 +2002,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } match tcx.impls_are_allowed_to_overlap(lhs, victim) { - // For #33140 the impl headers must be exactly equal, the trait must not have - // any associated items and there are no where-clauses. - // - // We can just arbitrarily drop one of the impls. - Some(ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects) => { - assert_eq!(lhs_evaluation, victim_evaluation); - true - } // For candidates which already reference errors it doesn't really // matter what we do 🤷 Some(ty::ImplOverlapKind::Permitted { marker: false }) => { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index cb3e81f5477..448ac558cad 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; -use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS}; +use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; use rustc_type_ir::solve::NoSolution; use specialization_graph::GraphExt; @@ -557,13 +557,9 @@ fn report_conflicting_impls<'tcx>( let msg = || { format!( - "conflicting implementations of trait `{}`{}{}", + "conflicting implementations of trait `{}`{}", overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), - match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::OrderDepTraitObjects) => ": (E0119)", - _ => "", - } ) }; @@ -588,7 +584,6 @@ fn report_conflicting_impls<'tcx>( } Some(kind) => { let lint = match kind { - FutureCompatOverlapErrorKind::OrderDepTraitObjects => ORDER_DEPENDENT_TRAIT_OBJECTS, FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 19d3561dd59..9452dca9a4f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -12,7 +12,6 @@ use crate::traits; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { - OrderDepTraitObjects, LeakCheck, } @@ -151,12 +150,6 @@ impl<'tcx> Children { { match overlap_kind { ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects => { - *last_lint_mut = Some(FutureCompatOverlapError { - error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::OrderDepTraitObjects, - }); - } } return Ok((false, false)); diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 04aef4e7b9e..49bcaae8571 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -13,3 +13,6 @@ rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index d2f979bd6d9..697c8391803 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod codegen; diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index f0c783b3002..ae1beb10728 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -25,3 +25,6 @@ rustc = [ # tidy-alphabetical-start itertools = "0.12" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 81a11f7cfb2..00928137d29 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![feature(never_type)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 4c7a57f2931..61acc12d0eb 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -23,3 +23,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } tracing = "0.1" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index de2c3b63997..8bc7bf10865 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -14,6 +14,8 @@ ty_utils_borrow_not_supported = borrowing is not supported in generic constants ty_utils_box_not_supported = allocations are not allowed in generic constants +ty_utils_by_use_not_supported = .use is not allowed in generic constants + ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants ty_utils_const_block_not_supported = const blocks are not supported in generic constants diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index c8034f4e7b9..c84055f5b84 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -252,7 +252,8 @@ fn associated_type_for_impl_trait_in_trait( assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -304,7 +305,8 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 2157ab3c402..20646cf9a82 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty is_item_raw(tcx, query, LangItem::Copy) } +fn is_use_cloned_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { + is_item_raw(tcx, query, LangItem::UseCloned) +} + fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Sized) } @@ -33,5 +40,12 @@ fn is_item_raw<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; + *providers = Providers { + is_copy_raw, + is_use_cloned_raw, + is_sized_raw, + is_freeze_raw, + is_unpin_raw, + ..*providers + }; } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index ece796b3c71..b275cd382ab 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -230,7 +230,9 @@ fn recurse_build<'tcx>( error(GenericConstantTooComplexSub::LoopNotSupported(node.span))? } ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?, - + ExprKind::ByUse { .. } => { + error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))? + } ExprKind::Unary { .. } => unreachable!(), // we handle valid unary/binary ops above ExprKind::Binary { .. } => { @@ -317,6 +319,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::Box { .. } | thir::ExprKind::If { .. } | thir::ExprKind::Call { .. } + | thir::ExprKind::ByUse { .. } | thir::ExprKind::Deref { .. } | thir::ExprKind::Binary { .. } | thir::ExprKind::LogicalOp { .. } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 8877bb45ceb..0298e7e0e95 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -55,6 +55,8 @@ pub(crate) enum GenericConstantTooComplexSub { BoxNotSupported(#[primary_span] Span), #[label(ty_utils_binary_not_supported)] BinaryNotSupported(#[primary_span] Span), + #[label(ty_utils_by_use_not_supported)] + ByUseNotSupported(#[primary_span] Span), #[label(ty_utils_logical_op_not_supported)] LogicalOpNotSupported(#[primary_span] Span), #[label(ty_utils_assign_not_supported)] diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index a53f0538c58..5a4bb2c95da 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -1,31 +1,25 @@ -use std::fmt::Debug; -use std::iter; - use hir::def_id::DefId; use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, - HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, - StructKind, TagEncoding, VariantIdx, Variants, WrappingRange, + AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, + VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; -use rustc_index::bit_set::DenseBitSet; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::bug; -use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ - FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, MAX_SIMD_LANES, TyAndLayout, + FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt, - TypeVisitableExt, + self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt, }; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::{Symbol, sym}; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use {rustc_abi as abi, rustc_hir as hir}; use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType}; @@ -124,20 +118,23 @@ fn map_error<'tcx>( .delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}")); LayoutError::ReferencesError(guar) } + LayoutCalculatorError::ZeroLengthSimdType => { + // Can't be caught in typeck if the array length is generic. + cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty }) + } + LayoutCalculatorError::OversizedSimdType { max_lanes } => { + // Can't be caught in typeck if the array length is generic. + cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes }) + } + LayoutCalculatorError::NonPrimitiveSimdType(field) => { + // This error isn't caught in typeck, e.g., if + // the element type of the vector is generic. + cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty }) + } }; error(cx, err) } -fn univariant_uninterned<'tcx>( - cx: &LayoutCx<'tcx>, - ty: Ty<'tcx>, - fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, - kind: StructKind, -) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> { - let repr = ReprOptions::default(); - cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err)) -} - fn extract_const_value<'tcx>( cx: &LayoutCx<'tcx>, ty: Ty<'tcx>, @@ -188,6 +185,10 @@ fn layout_of_uncached<'tcx>( let tcx = cx.tcx(); let dl = cx.data_layout(); + let map_layout = |result: Result<_, _>| match result { + Ok(layout) => Ok(tcx.mk_layout(layout)), + Err(err) => Err(map_error(cx, ty, err)), + }; let scalar_unit = |value: Primitive| { let size = value.size(dl); assert!(size.bits() <= 128); @@ -195,8 +196,10 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value))); - let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, kind| { - Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?)) + let univariant = |tys: &[Ty<'tcx>], kind| { + let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::<IndexVec<_, _>>()?; + let repr = ReprOptions::default(); + map_layout(cx.calc.univariant(&fields, &repr, kind)) }; debug_assert!(!ty.has_non_region_infer()); @@ -258,7 +261,7 @@ fn layout_of_uncached<'tcx>( } // The never type. - ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()), + ty::Never => tcx.mk_layout(LayoutData::never_type(cx)), // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { @@ -329,7 +332,7 @@ fn layout_of_uncached<'tcx>( }; // Effectively a (ptr, meta) tuple. - tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata)) + tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata)) } ty::Dynamic(_, _, ty::DynStar) => { @@ -337,7 +340,7 @@ fn layout_of_uncached<'tcx>( data.valid_range_mut().start = 0; let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); vtable.valid_range_mut().start = 1; - tcx.mk_layout(cx.calc.scalar_pair(data, vtable)) + tcx.mk_layout(LayoutData::scalar_pair(cx, data, vtable)) } // Arrays and slices. @@ -347,96 +350,87 @@ fn layout_of_uncached<'tcx>( .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; let element = cx.layout_of(element)?; - let size = element - .size - .checked_mul(count, dl) - .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - - let abi = BackendRepr::Memory { sized: true }; - - let largest_niche = if count != 0 { element.largest_niche } else { None }; - let uninhabited = if count != 0 { element.uninhabited } else { false }; - - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: element.size, count }, - backend_repr: abi, - largest_niche, - uninhabited, - align: element.align, - size, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), - }) + map_layout(cx.calc.array_like(&element, Some(count)))? } ty::Slice(element) => { let element = cx.layout_of(element)?; - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: element.size, count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: element.align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - // adding a randomly chosen value to distinguish slices - randomization_seed: element - .randomization_seed - .wrapping_add(Hash64::new(0x2dcba99c39784102)), - }) + map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + // a randomly chosen value to distinguish slices + layout.randomization_seed = Hash64::new(0x2dcba99c39784102); + layout + }))? + } + ty::Str => { + let element = scalar(Int(I8, false)); + map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + // another random value + layout.randomization_seed = Hash64::new(0xc1325f37d127be22); + layout + }))? } - ty::Str => tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - // another random value - randomization_seed: Hash64::new(0xc1325f37d127be22), - }), // Odd unit types. - ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?, - ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { - let mut unit = - univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?; - match unit.backend_repr { - BackendRepr::Memory { ref mut sized } => *sized = false, - _ => bug!(), - } - tcx.mk_layout(unit) + ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { + let sized = matches!(ty.kind(), ty::FnDef(..)); + tcx.mk_layout(LayoutData::unit(cx, sized)) } - ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?, + ty::Coroutine(def_id, args) => { + use rustc_middle::ty::layout::PrimitiveExt as _; + + let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else { + return Err(error(cx, LayoutError::Unknown(ty))); + }; + + let local_layouts = info + .field_tys + .iter() + .map(|local| { + let field_ty = EarlyBinder::bind(local.ty); + let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args)); + cx.spanned_layout_of(uninit_ty, local.source_info.span) + }) + .try_collect::<IndexVec<_, _>>()?; - ty::Closure(_, args) => { - let tys = args.as_closure().upvar_tys(); - univariant( - &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - StructKind::AlwaysSized, - )? + let prefix_layouts = args + .as_coroutine() + .prefix_tys() + .iter() + .map(|ty| cx.layout_of(ty)) + .try_collect::<IndexVec<_, _>>()?; + + let layout = cx + .calc + .coroutine( + &local_layouts, + prefix_layouts, + &info.variant_fields, + &info.storage_conflicts, + |tag| TyAndLayout { + ty: tag.primitive().to_ty(tcx), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), + }, + ) + .map(|mut layout| { + // this is similar to how ReprOptions populates its field_shuffle_seed + layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash(); + debug!("coroutine layout ({:?}): {:#?}", ty, layout); + layout + }); + map_layout(layout)? } + ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?, + ty::CoroutineClosure(_, args) => { - let tys = args.as_coroutine_closure().upvar_tys(); - univariant( - &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - StructKind::AlwaysSized, - )? + univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)? } ty::Tuple(tys) => { let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, kind)? + univariant(tys, kind)? } // SIMD vector types. @@ -461,65 +455,9 @@ fn layout_of_uncached<'tcx>( .try_to_target_usize(tcx) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - // SIMD vectors of zero length are not supported. - // Additionally, lengths are capped at 2^16 as a fixed maximum backends must - // support. - // - // Can't be caught in typeck if the array length is generic. - if e_len == 0 { - tcx.dcx().emit_fatal(ZeroLengthSimdType { ty }); - } else if e_len > MAX_SIMD_LANES { - tcx.dcx().emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES }); - } - - // Compute the ABI of the element type: let e_ly = cx.layout_of(e_ty)?; - let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { - // This error isn't caught in typeck, e.g., if - // the element type of the vector is generic. - tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty }); - }; - // Compute the size and alignment of the vector: - let size = e_ly - .size - .checked_mul(e_len, dl) - .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - - let (abi, align) = if def.repr().packed() && !e_len.is_power_of_two() { - // Non-power-of-two vectors have padding up to the next power-of-two. - // If we're a packed repr, remove the padding while keeping the alignment as close - // to a vector as possible. - ( - BackendRepr::Memory { sized: true }, - AbiAndPrefAlign { - abi: Align::max_aligned_factor(size), - pref: dl.llvmlike_vector_align(size).pref, - }, - ) - } else { - ( - BackendRepr::SimdVector { element: e_abi, count: e_len }, - dl.llvmlike_vector_align(size), - ) - }; - let size = size.align_to(align.abi); - - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO].into(), - memory_index: [0].into(), - }, - backend_repr: abi, - largest_niche: e_ly.largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)), - }) + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? } // ADTs. @@ -545,11 +483,7 @@ fn layout_of_uncached<'tcx>( return Err(error(cx, LayoutError::ReferencesError(guar))); } - return Ok(tcx.mk_layout( - cx.calc - .layout_of_union(&def.repr(), &variants) - .map_err(|err| map_error(cx, ty, err))?, - )); + return map_layout(cx.calc.layout_of_union(&def.repr(), &variants)); } let get_discriminant_type = @@ -677,335 +611,6 @@ fn layout_of_uncached<'tcx>( }) } -/// Overlap eligibility and variant assignment for each CoroutineSavedLocal. -#[derive(Clone, Debug, PartialEq)] -enum SavedLocalEligibility { - Unassigned, - Assigned(VariantIdx), - Ineligible(Option<FieldIdx>), -} - -// When laying out coroutines, we divide our saved local fields into two -// categories: overlap-eligible and overlap-ineligible. -// -// Those fields which are ineligible for overlap go in a "prefix" at the -// beginning of the layout, and always have space reserved for them. -// -// Overlap-eligible fields are only assigned to one variant, so we lay -// those fields out for each variant and put them right after the -// prefix. -// -// Finally, in the layout details, we point to the fields from the -// variants they are assigned to. It is possible for some fields to be -// included in multiple variants. No field ever "moves around" in the -// layout; its offset is always the same. -// -// Also included in the layout are the upvars and the discriminant. -// These are included as fields on the "outer" layout; they are not part -// of any variant. - -/// Compute the eligibility and assignment of each local. -fn coroutine_saved_local_eligibility( - info: &CoroutineLayout<'_>, -) -> (DenseBitSet<CoroutineSavedLocal>, IndexVec<CoroutineSavedLocal, SavedLocalEligibility>) { - use SavedLocalEligibility::*; - - let mut assignments: IndexVec<CoroutineSavedLocal, SavedLocalEligibility> = - IndexVec::from_elem(Unassigned, &info.field_tys); - - // The saved locals not eligible for overlap. These will get - // "promoted" to the prefix of our coroutine. - let mut ineligible_locals = DenseBitSet::new_empty(info.field_tys.len()); - - // Figure out which of our saved locals are fields in only - // one variant. The rest are deemed ineligible for overlap. - for (variant_index, fields) in info.variant_fields.iter_enumerated() { - for local in fields { - match assignments[*local] { - Unassigned => { - assignments[*local] = Assigned(variant_index); - } - Assigned(idx) => { - // We've already seen this local at another suspension - // point, so it is no longer a candidate. - trace!( - "removing local {:?} in >1 variant ({:?}, {:?})", - local, variant_index, idx - ); - ineligible_locals.insert(*local); - assignments[*local] = Ineligible(None); - } - Ineligible(_) => {} - } - } - } - - // Next, check every pair of eligible locals to see if they - // conflict. - for local_a in info.storage_conflicts.rows() { - let conflicts_a = info.storage_conflicts.count(local_a); - if ineligible_locals.contains(local_a) { - continue; - } - - for local_b in info.storage_conflicts.iter(local_a) { - // local_a and local_b are storage live at the same time, therefore they - // cannot overlap in the coroutine layout. The only way to guarantee - // this is if they are in the same variant, or one is ineligible - // (which means it is stored in every variant). - if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] { - continue; - } - - // If they conflict, we will choose one to make ineligible. - // This is not always optimal; it's just a greedy heuristic that - // seems to produce good results most of the time. - let conflicts_b = info.storage_conflicts.count(local_b); - let (remove, other) = - if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; - ineligible_locals.insert(remove); - assignments[remove] = Ineligible(None); - trace!("removing local {:?} due to conflict with {:?}", remove, other); - } - } - - // Count the number of variants in use. If only one of them, then it is - // impossible to overlap any locals in our layout. In this case it's - // always better to make the remaining locals ineligible, so we can - // lay them out with the other locals in the prefix and eliminate - // unnecessary padding bytes. - { - let mut used_variants = DenseBitSet::new_empty(info.variant_fields.len()); - for assignment in &assignments { - if let Assigned(idx) = assignment { - used_variants.insert(*idx); - } - } - if used_variants.count() < 2 { - for assignment in assignments.iter_mut() { - *assignment = Ineligible(None); - } - ineligible_locals.insert_all(); - } - } - - // Write down the order of our locals that will be promoted to the prefix. - { - for (idx, local) in ineligible_locals.iter().enumerate() { - assignments[local] = Ineligible(Some(FieldIdx::from_usize(idx))); - } - } - debug!("coroutine saved local assignments: {:?}", assignments); - - (ineligible_locals, assignments) -} - -/// Compute the full coroutine layout. -fn coroutine_layout<'tcx>( - cx: &LayoutCx<'tcx>, - ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - args: GenericArgsRef<'tcx>, -) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> { - use SavedLocalEligibility::*; - let tcx = cx.tcx(); - let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args); - - let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else { - return Err(error(cx, LayoutError::Unknown(ty))); - }; - let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info); - - // Build a prefix layout, including "promoting" all ineligible - // locals as part of the prefix. We compute the layout of all of - // these fields at once to get optimal packing. - let tag_index = args.as_coroutine().prefix_tys().len(); - - // `info.variant_fields` already accounts for the reserved variants, so no need to add them. - let max_discr = (info.variant_fields.len() - 1) as u128; - let discr_int = abi::Integer::fit_unsigned(max_discr); - let tag = Scalar::Initialized { - value: Primitive::Int(discr_int, /* signed = */ false), - valid_range: WrappingRange { start: 0, end: max_discr }, - }; - let tag_layout = TyAndLayout { - ty: discr_int.to_ty(tcx, /* signed = */ false), - layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), - }; - - let promoted_layouts = ineligible_locals.iter().map(|local| { - let field_ty = instantiate_field(info.field_tys[local].ty); - let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty); - cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span) - }); - let prefix_layouts = args - .as_coroutine() - .prefix_tys() - .iter() - .map(|ty| cx.layout_of(ty)) - .chain(iter::once(Ok(tag_layout))) - .chain(promoted_layouts) - .try_collect::<IndexVec<_, _>>()?; - let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?; - - let (prefix_size, prefix_align) = (prefix.size, prefix.align); - - // Split the prefix layout into the "outer" fields (upvars and - // discriminant) and the "promoted" fields. Promoted fields will - // get included in each variant that requested them in - // CoroutineLayout. - debug!("prefix = {:#?}", prefix); - let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { - FieldsShape::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = memory_index.invert_bijective_mapping(); - - // "a" (`0..b_start`) and "b" (`b_start..`) correspond to - // "outer" and "promoted" fields respectively. - let b_start = FieldIdx::from_usize(tag_index + 1); - let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.as_usize())); - let offsets_a = offsets; - - // Disentangle the "a" and "b" components of `inverse_memory_index` - // by preserving the order but keeping only one disjoint "half" each. - // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index - .iter() - .filter_map(|&i| i.as_u32().checked_sub(b_start.as_u32()).map(FieldIdx::from_u32)) - .collect(); - inverse_memory_index.raw.retain(|&i| i < b_start); - let inverse_memory_index_a = inverse_memory_index; - - // Since `inverse_memory_index_{a,b}` each only refer to their - // respective fields, they can be safely inverted - let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); - let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); - - let outer_fields = - FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; - (outer_fields, offsets_b, memory_index_b) - } - _ => bug!(), - }; - - let mut size = prefix.size; - let mut align = prefix.align; - let variants = info - .variant_fields - .iter_enumerated() - .map(|(index, variant_fields)| { - // Only include overlap-eligible fields when we compute our variant layout. - let variant_only_tys = variant_fields - .iter() - .filter(|local| match assignments[**local] { - Unassigned => bug!(), - Assigned(v) if v == index => true, - Assigned(_) => bug!("assignment does not match variant"), - Ineligible(_) => false, - }) - .map(|local| { - let field_ty = instantiate_field(info.field_tys[*local].ty); - Ty::new_maybe_uninit(tcx, field_ty) - }); - - let mut variant = univariant_uninterned( - cx, - ty, - &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?, - StructKind::Prefixed(prefix_size, prefix_align.abi), - )?; - variant.variants = Variants::Single { index }; - - let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { - bug!(); - }; - - // Now, stitch the promoted and variant-only fields back together in - // the order they are mentioned by our CoroutineLayout. - // Because we only use some subset (that can differ between variants) - // of the promoted fields, we can't just pick those elements of the - // `promoted_memory_index` (as we'd end up with gaps). - // So instead, we build an "inverse memory_index", as if all of the - // promoted fields were being used, but leave the elements not in the - // subset as `INVALID_FIELD_IDX`, which we can filter out later to - // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: FieldIdx = FieldIdx::MAX; - debug_assert!(variant_fields.next_index() <= INVALID_FIELD_IDX); - - let mut combined_inverse_memory_index = IndexVec::from_elem_n( - INVALID_FIELD_IDX, - promoted_memory_index.len() + memory_index.len(), - ); - let mut offsets_and_memory_index = iter::zip(offsets, memory_index); - let combined_offsets = variant_fields - .iter_enumerated() - .map(|(i, local)| { - let (offset, memory_index) = match assignments[*local] { - Unassigned => bug!(), - Assigned(_) => { - let (offset, memory_index) = offsets_and_memory_index.next().unwrap(); - (offset, promoted_memory_index.len() as u32 + memory_index) - } - Ineligible(field_idx) => { - let field_idx = field_idx.unwrap(); - (promoted_offsets[field_idx], promoted_memory_index[field_idx]) - } - }; - combined_inverse_memory_index[memory_index] = i; - offset - }) - .collect(); - - // Remove the unused slots and invert the mapping to obtain the - // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.raw.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); - - variant.fields = FieldsShape::Arbitrary { - offsets: combined_offsets, - memory_index: combined_memory_index, - }; - - size = size.max(variant.size); - align = align.max(variant.align); - Ok(variant) - }) - .try_collect::<IndexVec<VariantIdx, _>>()?; - - size = size.align_to(align.abi); - - let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); - let abi = BackendRepr::Memory { sized: true }; - - // this is similar to how ReprOptions populates its field_shuffle_seed - let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash(); - - let layout = tcx.mk_layout(LayoutData { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: tag_index, - variants, - }, - fields: outer_fields, - backend_repr: abi, - // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to - // self-referentiality), getting the discriminant can cause aliasing violations. - // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that - // would do the same for us here. - // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>. - // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. - largest_niche: None, - uninhabited, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: def_hash, - }); - debug!("coroutine layout ({:?}): {:#?}", ty, layout); - Ok(layout) -} - fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 8be1611bb9a..35cc6f39856 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::query::Providers; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 8610c30ab70..bb61f4bee66 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -6,13 +6,11 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast}; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_trait_selection::traits; -use tracing::{debug, instrument}; +use tracing::instrument; #[instrument(level = "debug", skip(tcx), ret)] fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { @@ -260,57 +258,6 @@ fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty: typing_env.with_post_analysis_normalized(tcx).param_env } -/// If the given trait impl enables exploiting the former order dependence of trait objects, -/// returns its self type; otherwise, returns `None`. -/// -/// See [`ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects`] for more details. -#[instrument(level = "debug", skip(tcx))] -fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Option<EarlyBinder<'_, Ty<'_>>> { - let impl_ = - tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}")); - - let trait_ref = impl_.trait_ref.skip_binder(); - debug!(?trait_ref); - - let is_marker_like = impl_.polarity == ty::ImplPolarity::Positive - && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); - - // Check whether these impls would be ok for a marker trait. - if !is_marker_like { - debug!("not marker-like!"); - return None; - } - - // impl must be `impl Trait for dyn Marker1 + Marker2 + ...` - if trait_ref.args.len() != 1 { - debug!("impl has args!"); - return None; - } - - let predicates = tcx.predicates_of(def_id); - if predicates.parent.is_some() || !predicates.predicates.is_empty() { - debug!(?predicates, "impl has predicates!"); - return None; - } - - let self_ty = trait_ref.self_ty(); - let self_ty_matches = match self_ty.kind() { - ty::Dynamic(data, re, _) if re.is_static() => data.principal().is_none(), - _ => false, - }; - - if self_ty_matches { - debug!("MATCHES!"); - Some(EarlyBinder::bind(self_ty)) - } else { - debug!("non-matching self type"); - None - } -} - /// Check if a function is async. fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness { let node = tcx.hir_node_by_def_id(def_id); @@ -370,7 +317,6 @@ pub(crate) fn provide(providers: &mut Providers) { adt_sized_constraint, param_env, param_env_normalized_for_post_analysis, - self_ty_of_trait_impl_enabling_order_dep_trait_object_hack, defaultness, unsizing_params_for_adt, ..*providers diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 7b2593b96e3..0381797d7e9 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -34,5 +34,5 @@ nightly = [ "rustc_ast_ir/nightly", ] -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } +[lints] +workspace = true diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 15ef4e7d6c1..e2dfd9173fa 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -6,7 +6,6 @@ feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_type_ir; diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml index 15a55575099..a3fa4623855 100644 --- a/compiler/rustc_type_ir_macros/Cargo.toml +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -13,3 +13,6 @@ quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end + +[lints] +workspace = true diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index d691a0e4f22..358a3915402 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -6,3 +6,6 @@ edition = "2024" [dependencies] scoped-tls = "1.0" serde = { version = "1.0.125", features = [ "derive" ] } + +[lints] +workspace = true diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index 7e0c4a479b8..023807b76ae 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -58,7 +58,7 @@ impl IndexedVal for AllocId { /// Utility function used to read an allocation data into a unassigned integer. pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> { - let mut buf = [0u8; std::mem::size_of::<u128>()]; + let mut buf = [0u8; size_of::<u128>()]; match MachineInfo::target_endianness() { Endian::Little => { bytes.read_exact(&mut buf[..bytes.len()])?; @@ -73,7 +73,7 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> { /// Utility function used to read an allocation data into an assigned integer. pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> { - let mut buf = [0u8; std::mem::size_of::<i128>()]; + let mut buf = [0u8; size_of::<i128>()]; match MachineInfo::target_endianness() { Endian::Little => { bytes.read_exact(&mut buf[..bytes.len()])?; diff --git a/library/Cargo.lock b/library/Cargo.lock index 31656414121..405c69d9568 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -30,8 +30,6 @@ version = "0.0.0" dependencies = [ "compiler_builtins", "core", - "rand", - "rand_xorshift", ] [[package]] @@ -41,6 +39,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] +name = "alloctests" +version = "0.0.0" +dependencies = [ + "rand", + "rand_xorshift", +] + +[[package]] name = "cc" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/library/Cargo.toml b/library/Cargo.toml index 1205f7c9ed6..4d5955593ff 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -4,6 +4,7 @@ members = [ "std", "sysroot", "coretests", + "alloctests", ] exclude = [ diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 4cb83501256..dbdf292433b 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,32 +10,14 @@ autotests = false autobenches = false edition = "2021" +[lib] +test = false +bench = false + [dependencies] core = { path = "../core", public = true } compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } -[dev-dependencies] -rand = { version = "0.9.0", default-features = false, features = ["alloc"] } -rand_xorshift = "0.4.0" - -[[test]] -name = "alloctests" -path = "tests/lib.rs" - -[[test]] -name = "vec_deque_alloc_error" -path = "tests/vec_deque_alloc_error.rs" - -[[bench]] -name = "allocbenches" -path = "benches/lib.rs" -test = true - -[[bench]] -name = "vec_deque_append_bench" -path = "benches/vec_deque_append.rs" -harness = false - [features] compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 3bfdc68dcda..2f752f6eb39 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,9 +5,7 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -#[cfg(not(test))] use core::hint; -#[cfg(not(test))] use core::ptr::{self, NonNull}; unsafe extern "Rust" { @@ -44,14 +42,10 @@ unsafe extern "Rust" { /// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] -#[cfg(not(test))] // the compiler needs to know when a Box uses the global allocator vs a custom one #[lang = "global_alloc_ty"] pub struct Global; -#[cfg(test)] -pub use std::alloc::Global; - /// Allocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc`] method @@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { } } -#[cfg(not(test))] impl Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -246,7 +239,6 @@ impl Global { } #[unstable(feature = "allocator_api", issue = "32838")] -#[cfg(not(test))] unsafe impl Allocator for Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -346,7 +338,7 @@ unsafe impl Allocator for Global { } /// The allocator for `Box`. -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[lang = "exchange_malloc"] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -395,7 +387,7 @@ unsafe extern "Rust" { /// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] pub const fn handle_alloc_error(layout: Layout) -> ! { @@ -419,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { ct_error(layout) } -// For alloc test `std::alloc::handle_alloc_error` can be used directly. -#[cfg(all(not(no_global_oom_handling), test))] -pub use std::alloc::handle_alloc_error; - -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 17dad3277b9..07f51b7614f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,7 +32,7 @@ where /// implementing the `Clone` trait. But `Clone` works only for going from `&T` /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. -#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] +#[rustc_diagnostic_item = "ToOwned"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { /// The resulting type after obtaining ownership. @@ -54,7 +54,7 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")] + #[rustc_diagnostic_item = "to_owned_method"] fn to_owned(&self) -> Self::Owned; /// Uses borrowed data to replace owned data, usually by cloning. @@ -175,7 +175,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] +#[rustc_diagnostic_item = "Cow"] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index 61e61019b50..338c7ac7f88 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -12,13 +12,10 @@ use core::ops::{ Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use core::str::FromStr; use core::{fmt, hash}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; #[cfg(not(no_rc))] use crate::rc::Rc; @@ -181,7 +178,6 @@ impl Default for ByteString { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { // #[inline] @@ -190,7 +186,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<const N: usize> From<[u8; N]> for ByteString { // #[inline] @@ -199,7 +194,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a [u8]> for ByteString { // #[inline] @@ -226,7 +220,6 @@ impl From<ByteString> for Vec<u8> { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a str> for ByteString { // #[inline] @@ -243,7 +236,6 @@ impl From<ByteString> for Vec<u8> { // } // } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for ByteString { #[inline] @@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<ByteString> for Cow<'a, ByteStr> { #[inline] @@ -261,7 +252,6 @@ impl<'a> From<ByteString> for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] @@ -330,7 +320,6 @@ impl FromIterator<ByteString> for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl FromStr for ByteString { type Err = core::convert::Infallible; @@ -488,7 +477,6 @@ impl PartialEq for ByteString { macro_rules! impl_partial_eq_ord_cow { ($lhs:ty, $rhs:ty) => { - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$rhs> for $lhs { @@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$lhs> for $rhs { @@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$rhs> for $lhs { @@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$lhs> for $rhs { @@ -572,7 +557,6 @@ impl PartialOrd for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl ToOwned for ByteStr { type Owned = ByteString; @@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { // Additional impls for `ByteStr` that require types from `alloc`: -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl Clone for Box<ByteStr> { #[inline] @@ -614,7 +597,6 @@ impl Clone for Box<ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { #[inline] @@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From<Box<[u8]>> for Box<ByteStr> { #[inline] @@ -633,7 +614,6 @@ impl From<Box<[u8]>> for Box<ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From<Box<ByteStr>> for Box<[u8]> { #[inline] diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 965fd63a529..b764b8fa5d9 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -153,7 +153,9 @@ use core::{fmt, ptr}; use crate::alloc::Global; use crate::collections::TryReserveError; use crate::slice; -use crate::vec::{self, AsVecIntoIter, Vec}; +#[cfg(not(test))] +use crate::vec::AsVecIntoIter; +use crate::vec::{self, Vec}; /// A priority queue implemented with a binary heap. /// @@ -1600,6 +1602,7 @@ unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> { const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1); } +#[cfg(not(test))] unsafe impl<I> AsVecIntoIter for IntoIter<I> { type Item = I; diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 020cf4d7365..fac4d1a65ab 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -1,5 +1,8 @@ //! Collection types. +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. + #![stable(feature = "rust1", since = "1.0.0")] #[cfg(not(no_global_oom_handling))] @@ -24,41 +27,54 @@ pub mod btree_map { pub mod btree_set { //! An ordered set based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(test))] pub use super::btree::set::*; } +#[cfg(not(test))] use core::fmt::Display; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use binary_heap::BinaryHeap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_map::BTreeMap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_set::BTreeSet; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use linked_list::LinkedList; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use vec_deque::VecDeque; +#[cfg(not(test))] use crate::alloc::{Layout, LayoutError}; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] pub struct TryReserveError { kind: TryReserveErrorKind, } +#[cfg(test)] +pub use realalloc::collections::TryReserveError; + +#[cfg(not(test))] impl TryReserveError { /// Details about the allocation that caused the error #[inline] @@ -80,6 +96,7 @@ impl TryReserveError { reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] pub enum TryReserveErrorKind { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). @@ -103,11 +120,15 @@ pub enum TryReserveErrorKind { }, } +#[cfg(test)] +pub use realalloc::collections::TryReserveErrorKind; + #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] impl From<TryReserveErrorKind> for TryReserveError { #[inline] fn from(kind: TryReserveErrorKind) -> Self { @@ -116,6 +137,7 @@ impl From<TryReserveErrorKind> for TryReserveError { } #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] +#[cfg(not(test))] impl From<LayoutError> for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] @@ -125,6 +147,7 @@ impl From<LayoutError> for TryReserveErrorKind { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl Display for TryReserveError { fn fmt( &self, @@ -152,4 +175,5 @@ trait SpecExtend<I: IntoIterator> { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 299c8b8679e..f8844e2d3a5 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -645,6 +645,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// initialized rather than only supporting `0..len`. Requires that /// `initialized.start` ≤ `initialized.end` ≤ `capacity`. #[inline] + #[cfg(not(test))] pub(crate) unsafe fn from_contiguous_raw_parts_in( ptr: *mut T, initialized: Range<usize>, diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index d246385ca84..7c7072c4c3a 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -3,6 +3,7 @@ use core::slice; use super::VecDeque; use crate::alloc::Allocator; +#[cfg(not(test))] use crate::vec; // Specialization trait used for VecDeque::extend @@ -78,6 +79,7 @@ where } } +#[cfg(not(test))] impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> { #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) { diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs index 1efe84d6d7d..c80a30c2103 100644 --- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs +++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs @@ -19,6 +19,7 @@ where } } +#[cfg(not(test))] impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> { #[inline] fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fd93045a5ac..f6743c65710 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::Rc; -use crate::slice::hack::into_vec; use crate::string::String; #[cfg(target_has_atomic = "ptr")] use crate::sync::Arc; @@ -103,7 +102,7 @@ use crate::vec::Vec; /// of `CString` instances can lead to invalid memory accesses, memory leaks, /// and other memory errors. #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")] +#[rustc_diagnostic_item = "cstring_type"] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct CString { // Invariant 1: the slice ends with a zero byte and has a length of at least one. @@ -491,7 +490,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec<u8> { - let mut vec = into_vec(self.into_inner()); + let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); vec @@ -512,7 +511,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec<u8> { - into_vec(self.into_inner()) + self.into_inner().into_vec() } /// Returns the contents of this `CString` as a slice of bytes. @@ -573,7 +572,7 @@ impl CString { #[inline] #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")] + #[rustc_diagnostic_item = "cstring_as_c_str"] pub fn as_c_str(&self) -> &CStr { &*self } @@ -755,7 +754,6 @@ impl<'a> From<Cow<'a, CStr>> for CString { } } -#[cfg(not(test))] #[stable(feature = "box_from_c_str", since = "1.17.0")] impl From<&CStr> for Box<CStr> { /// Converts a `&CStr` into a `Box<CStr>`, @@ -766,7 +764,6 @@ impl From<&CStr> for Box<CStr> { } } -#[cfg(not(test))] #[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Box<CStr> { /// Converts a `&mut CStr` into a `Box<CStr>`, @@ -845,7 +842,6 @@ impl TryFrom<CString> for String { } } -#[cfg(not(test))] #[stable(feature = "more_box_slice_clone", since = "1.29.0")] impl Clone for Box<CStr> { #[inline] @@ -971,7 +967,6 @@ impl Default for Rc<CStr> { } } -#[cfg(not(test))] #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box<CStr> { fn default() -> Box<CStr> { @@ -1080,7 +1075,7 @@ impl ToOwned for CStr { } fn clone_into(&self, target: &mut CString) { - let mut b = into_vec(mem::take(&mut target.inner)); + let mut b = mem::take(&mut target.inner).into_vec(); self.to_bytes_with_nul().clone_into(&mut b); target.inner = b.into_boxed_slice(); } @@ -1113,7 +1108,6 @@ impl AsRef<CStr> for CString { } } -#[cfg(not(test))] impl CStr { /// Converts a `CStr` into a <code>[Cow]<[str]></code>. /// diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cb93100f56c..f0cdb1e4e0f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,6 +56,7 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +#![allow(incomplete_features)] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -92,7 +93,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] @@ -113,6 +113,7 @@ #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] +#![feature(ergonomic_clones)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -159,13 +160,11 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(test), feature(coroutine_trait))] -#![cfg_attr(test, feature(panic_update_hook))] -#![cfg_attr(test, feature(test))] #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] +#![feature(coroutine_trait)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(fundamental)] @@ -198,15 +197,6 @@ // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. #![feature(intra_doc_pointers)] -// Allow testing this library -#[cfg(test)] -#[macro_use] -extern crate std; -#[cfg(test)] -extern crate test; -#[cfg(test)] -mod testing; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; @@ -214,7 +204,6 @@ mod macros; mod raw_vec; // Heaps provided for low-level allocation strategies - pub mod alloc; // Primitive types using the heaps above @@ -222,13 +211,8 @@ pub mod alloc; // Need to conditionally define the mod from `boxed.rs` to avoid // duplicating the lang-items when building in test cfg; but also need // to allow code to have `use boxed::Box;` declarations. -#[cfg(not(test))] -pub mod boxed; -#[cfg(test)] -mod boxed { - pub(crate) use std::boxed::Box; -} pub mod borrow; +pub mod boxed; #[unstable(feature = "bstr", issue = "134915")] pub mod bstr; pub mod collections; @@ -252,20 +236,3 @@ pub mod __export { pub use core::format_args; pub use core::hint::must_use; } - -#[cfg(test)] -#[allow(dead_code)] // Not used in all configurations -pub(crate) mod test_helpers { - /// Copied from `std::test_helpers::test_rng`, since these tests rely on the - /// seed not being the same for every RNG invocation too. - pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { - use std::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - std::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = - hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) - } -} diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index c000fd6f4ef..214192b8c9a 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -34,7 +34,7 @@ /// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_macro"] @@ -55,25 +55,6 @@ macro_rules! vec { ); } -// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is -// required for this macro definition, is not available. Instead use the -// `slice::into_vec` function which is only available with cfg(test) -// NB see the slice::hack module in slice.rs for more information -#[cfg(all(not(no_global_oom_handling), test))] -#[allow(unused_macro_rules)] -macro_rules! vec { - () => ( - $crate::vec::Vec::new() - ); - ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) - ); - ($($x:expr),*) => ( - $crate::slice::into_vec($crate::boxed::Box::new([$($x),*])) - ); - ($($x:expr,)*) => (vec![$($x),*]) -} - /// Creates a `String` using interpolation of runtime expressions. /// /// The first argument `format!` receives is a format string. This must be a string @@ -120,7 +101,7 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(hint_must_use, liballoc_internals)] -#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")] +#[rustc_diagnostic_item = "format_macro"] macro_rules! format { ($($arg:tt)*) => { $crate::__export::must_use({ diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec/mod.rs index 70f32fbaab4..99ebc5c4bfc 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -1,4 +1,8 @@ #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] +#![cfg_attr(test, allow(dead_code))] + +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 09206c2f8b2..fc1cee28d03 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -245,6 +245,7 @@ use core::any::Any; use core::cell::Cell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -262,23 +263,17 @@ use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; -#[cfg(test)] -use std::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] use crate::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; -#[cfg(test)] -mod tests; - // This is repr(C) to future-proof against possible field-reordering, which // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. @@ -309,7 +304,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// /// [get_mut]: Rc::get_mut #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] +#[rustc_diagnostic_item = "Rc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Rc< @@ -2333,6 +2328,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Rc<T> { @@ -2984,7 +2982,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "rc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] +#[rustc_diagnostic_item = "RcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -3496,6 +3494,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {} + #[stable(feature = "rc_weak", since = "1.4.0")] impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8baf9685062..7c5d22e1ee9 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -8,9 +8,6 @@ //! A few functions are provided to create a slice from a value reference //! or from a raw pointer. #![stable(feature = "rust1", since = "1.0.0")] -// Many of the usings in this module are only used in the test configuration. -// It's cleaner to just turn off the unused_imports warning than to fix them. -#![cfg_attr(test, allow(unused_imports, dead_code))] use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] @@ -63,16 +60,6 @@ pub use core::slice::{range, try_range}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods //////////////////////////////////////////////////////////////////////////////// - -// HACK(japaric) needed for the implementation of `vec!` macro during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::into_vec; -// HACK(japaric) needed for the implementation of `Vec::clone` during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::to_vec; - use crate::alloc::Allocator; #[cfg(not(no_global_oom_handling))] use crate::alloc::Global; @@ -81,98 +68,6 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; -// HACK(japaric): With cfg(test) `impl [T]` is not available, these three -// functions are actually methods that are in `impl [T]` but not in -// `core::slice::SliceExt` - we need to supply these functions for the -// `test_permutations` test -#[allow(unreachable_pub)] // cfg(test) pub above -pub(crate) mod hack { - use core::alloc::Allocator; - - use crate::boxed::Box; - use crate::vec::Vec; - - // We shouldn't add inline attribute to this since this is used in - // `vec!` macro mostly and causes perf regression. See #71204 for - // discussion and perf results. - #[allow(missing_docs)] - pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> { - unsafe { - let len = b.len(); - let (b, alloc) = Box::into_raw_with_allocator(b); - Vec::from_raw_parts_in(b as *mut T, len, len, alloc) - } - } - - #[cfg(not(no_global_oom_handling))] - #[allow(missing_docs)] - #[inline] - pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> { - T::to_vec(s, alloc) - } - - #[cfg(not(no_global_oom_handling))] - pub trait ConvertVec { - fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> - where - Self: Sized; - } - - #[cfg(not(no_global_oom_handling))] - impl<T: Clone> ConvertVec for T { - #[inline] - default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> { - struct DropGuard<'a, T, A: Allocator> { - vec: &'a mut Vec<T, A>, - num_init: usize, - } - impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { - #[inline] - fn drop(&mut self) { - // SAFETY: - // items were marked initialized in the loop below - unsafe { - self.vec.set_len(self.num_init); - } - } - } - let mut vec = Vec::with_capacity_in(s.len(), alloc); - let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; - let slots = guard.vec.spare_capacity_mut(); - // .take(slots.len()) is necessary for LLVM to remove bounds checks - // and has better codegen than zip. - for (i, b) in s.iter().enumerate().take(slots.len()) { - guard.num_init = i; - slots[i].write(b.clone()); - } - core::mem::forget(guard); - // SAFETY: - // the vec was allocated and initialized above to at least this length. - unsafe { - vec.set_len(s.len()); - } - vec - } - } - - #[cfg(not(no_global_oom_handling))] - impl<T: Copy> ConvertVec for T { - #[inline] - fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> { - let mut v = Vec::with_capacity_in(s.len(), alloc); - // SAFETY: - // allocated above with the capacity of `s`, and initialize to `s.len()` in - // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); - } - v - } - } -} - -#[cfg(not(test))] impl<T> [T] { /// Sorts the slice, preserving initial order of equal elements. /// @@ -501,8 +396,64 @@ impl<T> [T] { where T: Clone, { - // N.B., see the `hack` module in this file for more details. - hack::to_vec(self, alloc) + return T::to_vec(self, alloc); + + trait ConvertVec { + fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> + where + Self: Sized; + } + + impl<T: Clone> ConvertVec for T { + #[inline] + default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec<T, A>, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::with_capacity_in(s.len(), alloc); + let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + vec + } + } + + impl<T: Copy> ConvertVec for T { + #[inline] + fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> { + let mut v = Vec::with_capacity_in(s.len(), alloc); + // SAFETY: + // allocated above with the capacity of `s`, and initialize to `s.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } + v + } + } } /// Converts `self` into a vector without clones or allocation. @@ -522,10 +473,13 @@ impl<T> [T] { #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")] + #[rustc_diagnostic_item = "slice_into_vec"] pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> { - // N.B., see the `hack` module in this file for more details. - hack::into_vec(self) + unsafe { + let len = self.len(); + let (b, alloc) = Box::into_raw_with_allocator(self); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) + } } /// Creates a vector by copying a slice `n` times. @@ -666,7 +620,6 @@ impl<T> [T] { } } -#[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte /// is mapped to its ASCII upper case equivalent. @@ -883,14 +836,9 @@ impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone> ToOwned for [T] { type Owned = Vec<T>; - #[cfg(not(test))] - fn to_owned(&self) -> Vec<T> { - self.to_vec() - } - #[cfg(test)] fn to_owned(&self) -> Vec<T> { - hack::to_vec(self, Global) + self.to_vec() } fn clone_into(&self, target: &mut Vec<T>) { diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 6fee8d3fe33..0664f2c3cf2 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -219,7 +219,6 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg(not(test))] impl str { /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating. /// @@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> { #[unstable(feature = "str_internals", issue = "none")] #[doc(hidden)] #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { // Process the input in chunks of 16 bytes to enable auto-vectorization. @@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { } } #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] #[allow(dead_code)] /// Faster implementation of string replacement for ASCII to ASCII cases. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2c034786549..9236f5cb8d1 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -356,7 +356,7 @@ use crate::vec::{self, Vec}; /// [`as_str()`]: String::as_str #[derive(PartialEq, PartialOrd, Eq, Ord)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), lang = "String")] +#[lang = "String"] pub struct String { vec: Vec<u8>, } @@ -438,7 +438,7 @@ impl String { /// ``` #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")] + #[rustc_diagnostic_item = "string_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> String { @@ -501,17 +501,6 @@ impl String { Ok(String { vec: Vec::try_with_capacity(capacity)? }) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Since we don't - // require this method for testing purposes, I'll just stub it - // NB see the slice::hack module in slice.rs for more information - #[inline] - #[cfg(test)] - #[allow(missing_docs)] - pub fn from_str(_: &str) -> String { - panic!("not available with cfg(test)"); - } - /// Converts a vector of bytes to a `String`. /// /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes @@ -570,7 +559,7 @@ impl String { /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")] + #[rustc_diagnostic_item = "string_from_utf8"] pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> { match str::from_utf8(&vec) { Ok(..) => Ok(String { vec }), @@ -1054,7 +1043,8 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_bytes(self) -> Vec<u8> { self.vec } @@ -1071,8 +1061,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "string_as_str"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1094,8 +1084,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "string_as_mut_str"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1117,7 +1107,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")] + #[rustc_diagnostic_item = "string_push_str"] pub fn push_str(&mut self, string: &str) { self.vec.extend_from_slice(string.as_bytes()) } @@ -1169,7 +1159,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1435,7 +1425,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_bytes(&self) -> &[u8] { self.vec.as_slice() } @@ -1755,7 +1745,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "insert_str", since = "1.16.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")] + #[rustc_diagnostic_item = "string_insert_str"] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -1789,7 +1779,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> { &mut self.vec } @@ -1811,7 +1801,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { self.vec.len() @@ -1831,7 +1821,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2724,7 +2714,7 @@ impl FromStr for String { /// implementation for free. /// /// [`Display`]: fmt::Display -#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")] +#[rustc_diagnostic_item = "ToString"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. @@ -2739,7 +2729,7 @@ pub trait ToString { /// ``` #[rustc_conversion_suggestion] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] + #[rustc_diagnostic_item = "to_string_method"] fn to_string(&self) -> String; } @@ -2979,7 +2969,6 @@ impl From<&String> for String { } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From<Box<str>> for String { /// Converts the given boxed `str` slice to a [`String`]. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1956dda5388..4999319f618 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,6 +11,7 @@ use core::any::Any; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -234,7 +235,7 @@ macro_rules! acquire { /// /// [rc_examples]: crate::rc#examples #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] +#[rustc_diagnostic_item = "Arc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Arc< @@ -311,7 +312,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "arc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")] +#[rustc_diagnostic_item = "ArcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -2197,6 +2198,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> { type Target = T; @@ -3158,6 +3162,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {} + #[stable(feature = "downgraded_weak", since = "1.10.0")] impl<T> Default for Weak<T> { /// Constructs a new `Weak<T>`, without allocating memory. diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 52597e41c1c..3eee988b6c9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -472,14 +472,9 @@ where #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> { - #[cfg(not(test))] fn clone(&self) -> Self { self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() } - #[cfg(test)] - fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 49878f2b6fa..da9a77154f9 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -404,7 +404,7 @@ mod spec_extend; /// [owned slice]: Box /// [`into_boxed_slice`]: Vec::into_boxed_slice #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")] +#[rustc_diagnostic_item = "Vec"] #[rustc_insignificant_dtor] pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> { buf: RawVec<T, A>, @@ -428,7 +428,7 @@ impl<T> Vec<T> { /// ``` #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")] + #[rustc_diagnostic_item = "vec_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> Self { @@ -489,7 +489,7 @@ impl<T> Vec<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")] + #[rustc_diagnostic_item = "vec_with_capacity"] #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -1254,7 +1254,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1279,7 +1279,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")] + #[rustc_diagnostic_item = "vec_reserve"] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } @@ -1568,8 +1568,8 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_as_slice"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_slice(&self) -> &[T] { // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size // `len` containing properly-initialized `T`s. Data must not be mutated for the returned @@ -1600,8 +1600,8 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_as_mut_slice"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any @@ -1673,7 +1673,7 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -1736,7 +1736,7 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -2511,7 +2511,7 @@ impl<T, A: Allocator> Vec<T, A> { /// Takes *O*(1) time. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")] + #[rustc_diagnostic_item = "vec_pop"] pub fn pop(&mut self) -> Option<T> { if self.len == 0 { None @@ -2687,7 +2687,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { let len = self.len; @@ -2712,8 +2712,8 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_is_empty"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3193,7 +3193,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")] +#[rustc_diagnostic_item = "vec_from_elem"] #[track_caller] pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> { <T as SpecFromElem>::from_elem(elem, n, Global) @@ -3293,23 +3293,12 @@ unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { - #[cfg(not(test))] #[track_caller] fn clone(&self) -> Self { let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Instead use the - // `slice::to_vec` function which is only available with cfg(test) - // NB see the slice::hack module in slice.rs for more information - #[cfg(test)] - fn clone(&self) -> Self { - let alloc = self.allocator().clone(); - crate::slice::to_vec(&**self, alloc) - } - /// Overwrites the contents of `self` with a clone of the contents of `source`. /// /// This method is preferred over simply assigning `source.clone()` to `self`, @@ -3854,15 +3843,10 @@ impl<T: Clone> From<&[T]> for Vec<T> { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &[T]) -> Vec<T> { s.to_vec() } - #[cfg(test)] - fn from(s: &[T]) -> Vec<T> { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3875,15 +3859,10 @@ impl<T: Clone> From<&mut [T]> for Vec<T> { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &mut [T]) -> Vec<T> { s.to_vec() } - #[cfg(test)] - fn from(s: &mut [T]) -> Vec<T> { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3928,16 +3907,10 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: [T; N]) -> Vec<T> { <[T]>::into_vec(Box::new(s)) } - - #[cfg(test)] - fn from(s: [T; N]) -> Vec<T> { - crate::slice::into_vec(Box::new(s)) - } } #[stable(feature = "vec_from_cow_slice", since = "1.14.0")] @@ -3966,7 +3939,6 @@ where } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> { /// Converts a boxed slice into a vector by transferring ownership of @@ -3985,7 +3957,6 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> { // note: test pulls in std, which causes errors here #[cfg(not(no_global_oom_handling))] -#[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> { /// Converts a vector into a boxed slice. diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs deleted file mode 100644 index 9d82a7621a2..00000000000 --- a/library/alloc/tests/rc.rs +++ /dev/null @@ -1,259 +0,0 @@ -use std::any::Any; -use std::cell::{Cell, RefCell}; -use std::iter::TrustedLen; -use std::rc::{Rc, Weak}; - -#[test] -fn uninhabited() { - enum Void {} - let mut a = Weak::<Void>::new(); - a = a.clone(); - assert!(a.upgrade().is_none()); - - let mut a: Weak<dyn Any> = a; // Unsizing - a = a.clone(); - assert!(a.upgrade().is_none()); -} - -#[test] -fn slice() { - let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); - let a: Rc<[u32]> = a; // Unsizing - let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion - assert_eq!(a, b); - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); -} - -#[test] -fn trait_object() { - let a: Rc<u32> = Rc::new(4); - let a: Rc<dyn Any> = a; // Unsizing - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); - - let mut b = Weak::<u32>::new(); - b = b.clone(); - assert!(b.upgrade().is_none()); - let mut b: Weak<dyn Any> = b; // Unsizing - b = b.clone(); - assert!(b.upgrade().is_none()); -} - -#[test] -fn float_nan_ne() { - let x = Rc::new(f32::NAN); - assert!(x != x); - assert!(!(x == x)); -} - -#[test] -fn partial_eq() { - struct TestPEq(RefCell<usize>); - impl PartialEq for TestPEq { - fn eq(&self, other: &TestPEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestPEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 4); -} - -#[test] -fn eq() { - #[derive(Eq)] - struct TestEq(RefCell<usize>); - impl PartialEq for TestEq { - fn eq(&self, other: &TestEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 0); -} - -const SHARED_ITER_MAX: u16 = 100; - -fn assert_trusted_len<I: TrustedLen>(_: &I) {} - -#[test] -fn shared_from_iter_normal() { - // Exercise the base implementation for non-`TrustedLen` iterators. - { - // `Filter` is never `TrustedLen` since we don't - // know statically how many elements will be kept: - let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); - - // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::<Vec<_>>(); - let rc = iter.collect::<Rc<[_]>>(); - assert_eq!(&*vec, &*rc); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. -} - -#[test] -fn shared_from_iter_trustedlen_normal() { - // Exercise the `TrustedLen` implementation under normal circumstances - // where `size_hint()` matches `(_, Some(exact_len))`. - { - let iter = (0..SHARED_ITER_MAX).map(Box::new); - assert_trusted_len(&iter); - - // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::<Vec<_>>(); - let rc = iter.collect::<Rc<[_]>>(); - assert_eq!(&*vec, &*rc); - assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. - - // Try a ZST to make sure it is handled well. - { - let iter = (0..SHARED_ITER_MAX).map(drop); - let vec = iter.clone().collect::<Vec<_>>(); - let rc = iter.collect::<Rc<[_]>>(); - assert_eq!(&*vec, &*rc); - assert_eq!(0, size_of_val(&*rc)); - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } -} - -#[test] -#[should_panic = "I've almost got 99 problems."] -fn shared_from_iter_trustedlen_panic() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. - let iter = (0..SHARED_ITER_MAX).map(|val| match val { - 98 => panic!("I've almost got 99 problems."), - _ => Box::new(val), - }); - assert_trusted_len(&iter); - let _ = iter.collect::<Rc<[_]>>(); - - panic!("I am unreachable."); -} - -#[test] -fn shared_from_iter_trustedlen_no_fuse() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. - struct Iter(std::vec::IntoIter<Option<Box<u8>>>); - - unsafe impl TrustedLen for Iter {} - - impl Iterator for Iter { - fn size_hint(&self) -> (usize, Option<usize>) { - (2, Some(2)) - } - - type Item = Box<u8>; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().flatten() - } - } - - let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; - let iter = Iter(vec.into_iter()); - assert_trusted_len(&iter); - assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>()); -} - -#[test] -fn weak_may_dangle() { - fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { - val.clone() - } - - // Without #[may_dangle] we get: - let mut val = Weak::new(); - hmm(&mut val); - // ~~~~~~~~ borrowed value does not live long enough - // - // `val` dropped here while still borrowed - // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` -} - -/// Test that a panic from a destructor does not leak the allocation. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_no_leak() { - use std::alloc::{AllocError, Allocator, Global, Layout}; - use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::ptr::NonNull; - - struct AllocCount(Cell<i32>); - unsafe impl Allocator for AllocCount { - fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { - self.0.set(self.0.get() + 1); - Global.allocate(layout) - } - unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { - self.0.set(self.0.get() - 1); - unsafe { Global.deallocate(ptr, layout) } - } - } - - struct PanicOnDrop; - impl Drop for PanicOnDrop { - fn drop(&mut self) { - panic!("PanicOnDrop"); - } - } - - let alloc = AllocCount(Cell::new(0)); - let rc = Rc::new_in(PanicOnDrop, &alloc); - assert_eq!(alloc.0.get(), 1); - - let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); - assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); - assert_eq!(alloc.0.get(), 0); -} - -#[allow(unused)] -mod pin_coerce_unsized { - use alloc::rc::{Rc, UniqueRc}; - use core::pin::Pin; - - pub trait MyTrait {} - impl MyTrait for String {} - - // Pin coercion should work for Rc - pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> { - arg - } - pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> { - arg - } -} diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml new file mode 100644 index 00000000000..306375f5f01 --- /dev/null +++ b/library/alloctests/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "alloctests" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "Tests for the Rust Allocation Library" +autotests = false +autobenches = false +edition = "2021" + +[lib] +path = "lib.rs" +test = true +bench = true +doc = false + +[dev-dependencies] +rand = { version = "0.9.0", default-features = false, features = ["alloc"] } +rand_xorshift = "0.4.0" + +[[test]] +name = "alloctests" +path = "tests/lib.rs" + +[[test]] +name = "vec_deque_alloc_error" +path = "tests/vec_deque_alloc_error.rs" + +[[bench]] +name = "allocbenches" +path = "benches/lib.rs" +test = true + +[[bench]] +name = "vec_deque_append_bench" +path = "benches/vec_deque_append.rs" +harness = false + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(bootstrap)', + 'cfg(no_global_oom_handling)', + 'cfg(no_rc)', + 'cfg(no_sync)', + 'cfg(randomized_layouts)', +] diff --git a/library/alloc/benches/binary_heap.rs b/library/alloctests/benches/binary_heap.rs index 1b8f7f1c242..1b8f7f1c242 100644 --- a/library/alloc/benches/binary_heap.rs +++ b/library/alloctests/benches/binary_heap.rs diff --git a/library/alloc/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs index 20f02dc3a96..20f02dc3a96 100644 --- a/library/alloc/benches/btree/map.rs +++ b/library/alloctests/benches/btree/map.rs diff --git a/library/alloc/benches/btree/mod.rs b/library/alloctests/benches/btree/mod.rs index 095ca5dd2e2..095ca5dd2e2 100644 --- a/library/alloc/benches/btree/mod.rs +++ b/library/alloctests/benches/btree/mod.rs diff --git a/library/alloc/benches/btree/set.rs b/library/alloctests/benches/btree/set.rs index 5aa395b4d52..5aa395b4d52 100644 --- a/library/alloc/benches/btree/set.rs +++ b/library/alloctests/benches/btree/set.rs diff --git a/library/alloc/benches/lib.rs b/library/alloctests/benches/lib.rs index 2633154318c..2633154318c 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloctests/benches/lib.rs diff --git a/library/alloc/benches/linked_list.rs b/library/alloctests/benches/linked_list.rs index b9322b6d4c3..b9322b6d4c3 100644 --- a/library/alloc/benches/linked_list.rs +++ b/library/alloctests/benches/linked_list.rs diff --git a/library/alloc/benches/slice.rs b/library/alloctests/benches/slice.rs index 27b0e6fac0a..27b0e6fac0a 100644 --- a/library/alloc/benches/slice.rs +++ b/library/alloctests/benches/slice.rs diff --git a/library/alloc/benches/str.rs b/library/alloctests/benches/str.rs index 98c7c5413ca..98c7c5413ca 100644 --- a/library/alloc/benches/str.rs +++ b/library/alloctests/benches/str.rs diff --git a/library/alloc/benches/string.rs b/library/alloctests/benches/string.rs index 3d79ab78c69..3d79ab78c69 100644 --- a/library/alloc/benches/string.rs +++ b/library/alloctests/benches/string.rs diff --git a/library/alloc/benches/vec.rs b/library/alloctests/benches/vec.rs index 1dab71fa1f4..1dab71fa1f4 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloctests/benches/vec.rs diff --git a/library/alloc/benches/vec_deque.rs b/library/alloctests/benches/vec_deque.rs index a56f8496963..a56f8496963 100644 --- a/library/alloc/benches/vec_deque.rs +++ b/library/alloctests/benches/vec_deque.rs diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs index 7c805da9737..7c805da9737 100644 --- a/library/alloc/benches/vec_deque_append.rs +++ b/library/alloctests/benches/vec_deque_append.rs diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs new file mode 100644 index 00000000000..6ce8a6d9ca1 --- /dev/null +++ b/library/alloctests/lib.rs @@ -0,0 +1,93 @@ +#![cfg(test)] +#![allow(unused_attributes)] +#![unstable(feature = "alloctests", issue = "none")] +#![no_std] +// Lints: +#![deny(unsafe_op_in_unsafe_fn)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![allow(explicit_outlives_requirements)] +#![allow(internal_features)] +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +#![deny(ffi_unwind_calls)] +// +// Library features: +// tidy-alphabetical-start +#![feature(alloc_layout_extra)] +#![feature(allocator_api)] +#![feature(array_into_iter_constructors)] +#![feature(assert_matches)] +#![feature(core_intrinsics)] +#![feature(exact_size_is_empty)] +#![feature(extend_one)] +#![feature(extend_one_unchecked)] +#![feature(hasher_prefixfree_extras)] +#![feature(inplace_iteration)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] +#![feature(maybe_uninit_slice)] +#![feature(maybe_uninit_uninit_array_transpose)] +#![feature(ptr_internals)] +#![feature(sized_type_properties)] +#![feature(slice_iter_mut_as_mut_slice)] +#![feature(slice_ptr_get)] +#![feature(slice_range)] +#![feature(std_internals)] +#![feature(temporary_niche_types)] +#![feature(trusted_fused)] +#![feature(trusted_len)] +#![feature(trusted_random_access)] +#![feature(try_reserve_kind)] +#![feature(try_trait_v2)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(cfg_sanitize)] +#![feature(dropck_eyepatch)] +#![feature(lang_items)] +#![feature(min_specialization)] +#![feature(negative_impls)] +#![feature(never_type)] +#![feature(optimize_attribute)] +#![feature(rustc_allow_const_fn_unstable)] +#![feature(rustc_attrs)] +#![feature(staged_api)] +#![feature(test)] +#![rustc_preserve_ub_checks] +// tidy-alphabetical-end + +// Allow testing this library +extern crate alloc as realalloc; +#[macro_use] +extern crate std; +#[cfg(test)] +extern crate test; +mod testing; +use realalloc::*; + +// We are directly including collections and raw_vec here as both use non-public +// methods and fields in tests and as such need to have the types to test in the +// same crate as the tests themself. +#[path = "../alloc/src/collections/mod.rs"] +mod collections; + +#[path = "../alloc/src/raw_vec/mod.rs"] +mod raw_vec; + +#[allow(dead_code)] // Not used in all configurations +pub(crate) mod test_helpers { + /// Copied from `std::test_helpers::test_rng`, since these tests rely on the + /// seed not being the same for every RNG invocation too. + pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = + hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) + } +} diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloctests/testing/crash_test.rs index 8e00e4f41e5..8e00e4f41e5 100644 --- a/library/alloc/src/testing/crash_test.rs +++ b/library/alloctests/testing/crash_test.rs diff --git a/library/alloc/src/testing/mod.rs b/library/alloctests/testing/mod.rs index c8457daf93e..c8457daf93e 100644 --- a/library/alloc/src/testing/mod.rs +++ b/library/alloctests/testing/mod.rs diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs index 55e1ae5e3de..55e1ae5e3de 100644 --- a/library/alloc/src/testing/ord_chaos.rs +++ b/library/alloctests/testing/ord_chaos.rs diff --git a/library/alloc/src/testing/rng.rs b/library/alloctests/testing/rng.rs index 77d3348f38a..77d3348f38a 100644 --- a/library/alloc/src/testing/rng.rs +++ b/library/alloctests/testing/rng.rs diff --git a/library/alloc/tests/alloc.rs b/library/alloctests/tests/alloc_test.rs index 1e722d66795..1e722d66795 100644 --- a/library/alloc/tests/alloc.rs +++ b/library/alloctests/tests/alloc_test.rs diff --git a/library/alloc/tests/arc.rs b/library/alloctests/tests/arc.rs index 0baa50f439b..0baa50f439b 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloctests/tests/arc.rs diff --git a/library/alloc/tests/autotraits.rs b/library/alloctests/tests/autotraits.rs index 6b82deeac8a..6b82deeac8a 100644 --- a/library/alloc/tests/autotraits.rs +++ b/library/alloctests/tests/autotraits.rs diff --git a/library/alloc/tests/borrow.rs b/library/alloctests/tests/borrow.rs index af7efb7d782..af7efb7d782 100644 --- a/library/alloc/tests/borrow.rs +++ b/library/alloctests/tests/borrow.rs diff --git a/library/alloc/tests/boxed.rs b/library/alloctests/tests/boxed.rs index 94389cf2de9..94389cf2de9 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloctests/tests/btree_set_hash.rs index 71a3a143209..71a3a143209 100644 --- a/library/alloc/tests/btree_set_hash.rs +++ b/library/alloctests/tests/btree_set_hash.rs diff --git a/library/alloc/tests/c_str.rs b/library/alloctests/tests/c_str.rs index 4a581793956..4a581793956 100644 --- a/library/alloc/tests/c_str.rs +++ b/library/alloctests/tests/c_str.rs diff --git a/library/alloc/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs index 0f4c27fa123..0f4c27fa123 100644 --- a/library/alloc/tests/c_str2.rs +++ b/library/alloctests/tests/c_str2.rs diff --git a/library/alloc/tests/collections/binary_heap.rs b/library/alloctests/tests/collections/binary_heap.rs index 95f4c3e614f..95f4c3e614f 100644 --- a/library/alloc/tests/collections/binary_heap.rs +++ b/library/alloctests/tests/collections/binary_heap.rs diff --git a/library/alloc/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs index e73f3aaef8c..e73f3aaef8c 100644 --- a/library/alloc/tests/collections/mod.rs +++ b/library/alloctests/tests/collections/mod.rs diff --git a/library/alloc/tests/const_fns.rs b/library/alloctests/tests/const_fns.rs index 4e7d7fc833e..4e7d7fc833e 100644 --- a/library/alloc/tests/const_fns.rs +++ b/library/alloctests/tests/const_fns.rs diff --git a/library/alloc/tests/cow_str.rs b/library/alloctests/tests/cow_str.rs index 62a5c245a54..62a5c245a54 100644 --- a/library/alloc/tests/cow_str.rs +++ b/library/alloctests/tests/cow_str.rs diff --git a/library/alloc/tests/fmt.rs b/library/alloctests/tests/fmt.rs index c13074c53b7..c13074c53b7 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloctests/tests/fmt.rs diff --git a/library/alloc/tests/heap.rs b/library/alloctests/tests/heap.rs index 246b341eeb3..246b341eeb3 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloctests/tests/heap.rs diff --git a/library/alloc/tests/lib.rs b/library/alloctests/tests/lib.rs index 785070fb2bb..46c11ea150b 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -43,11 +43,12 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +extern crate alloc; extern crate test; use std::hash::{DefaultHasher, Hash, Hasher}; -mod alloc; +mod alloc_test; mod arc; mod autotraits; mod borrow; diff --git a/library/alloc/tests/linked_list.rs b/library/alloctests/tests/linked_list.rs index 65b09cb00c4..65b09cb00c4 100644 --- a/library/alloc/tests/linked_list.rs +++ b/library/alloctests/tests/linked_list.rs diff --git a/library/alloc/tests/misc_tests.rs b/library/alloctests/tests/misc_tests.rs index b95d11cb07e..b95d11cb07e 100644 --- a/library/alloc/tests/misc_tests.rs +++ b/library/alloctests/tests/misc_tests.rs diff --git a/library/alloc/src/rc/tests.rs b/library/alloctests/tests/rc.rs index 2210a7c24c0..bb68eb4ac9e 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloctests/tests/rc.rs @@ -1,7 +1,263 @@ -use std::cell::RefCell; -use std::clone::Clone; +use std::any::Any; +use std::cell::{Cell, RefCell}; +use std::iter::TrustedLen; +use std::mem; +use std::rc::{Rc, UniqueRc, Weak}; -use super::*; +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::<Void>::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak<dyn Any> = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); + let a: Rc<[u32]> = a; // Unsizing + let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Rc<u32> = Rc::new(4); + let a: Rc<dyn Any> = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::<u32>::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak<dyn Any> = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} + +#[test] +fn float_nan_ne() { + let x = Rc::new(f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq(RefCell<usize>); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq(RefCell<usize>); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len<I: TrustedLen>(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::<Vec<_>>(); + let rc = iter.collect::<Rc<[_]>>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::<Vec<_>>(); + let rc = iter.collect::<Rc<[_]>>(); + assert_eq!(&*vec, &*rc); + assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(drop); + let vec = iter.clone().collect::<Vec<_>>(); + let rc = iter.collect::<Rc<[_]>>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX).map(|val| match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + }); + assert_trusted_len(&iter); + let _ = iter.collect::<Rc<[_]>>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter<Option<Box<u8>>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option<usize>) { + (2, Some(2)) + } + + type Item = Box<u8>; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next().flatten() + } + } + + let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>()); +} + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` +} + +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell<i32>); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::rc::{Rc, UniqueRc}; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Rc + pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> { + arg + } + pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> { + arg + } +} #[test] fn test_clone() { @@ -61,16 +317,20 @@ fn weak_self_cyclic() { #[test] fn is_unique() { + fn is_unique<T>(this: &Rc<T>) -> bool { + Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 + } + let x = Rc::new(3); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); let y = x.clone(); - assert!(!Rc::is_unique(&x)); + assert!(!is_unique(&x)); drop(y); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); let w = Rc::downgrade(&x); - assert!(!Rc::is_unique(&x)); + assert!(!is_unique(&x)); drop(w); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); } #[test] diff --git a/library/alloc/tests/slice.rs b/library/alloctests/tests/slice.rs index 2516563187f..2516563187f 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloctests/tests/slice.rs diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloctests/tests/sort/ffi_types.rs index 11515ea4769..11515ea4769 100644 --- a/library/alloc/tests/sort/ffi_types.rs +++ b/library/alloctests/tests/sort/ffi_types.rs diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloctests/tests/sort/known_good_stable_sort.rs index 2df89146253..2df89146253 100644 --- a/library/alloc/tests/sort/known_good_stable_sort.rs +++ b/library/alloctests/tests/sort/known_good_stable_sort.rs diff --git a/library/alloc/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs index 0e2494ca9d3..0e2494ca9d3 100644 --- a/library/alloc/tests/sort/mod.rs +++ b/library/alloctests/tests/sort/mod.rs diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs index 0f1ec664d3d..0f1ec664d3d 100644 --- a/library/alloc/tests/sort/patterns.rs +++ b/library/alloctests/tests/sort/patterns.rs diff --git a/library/alloc/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs index d321f8df518..d321f8df518 100644 --- a/library/alloc/tests/sort/tests.rs +++ b/library/alloctests/tests/sort/tests.rs diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloctests/tests/sort/zipf.rs index 3dad2db521f..3dad2db521f 100644 --- a/library/alloc/tests/sort/zipf.rs +++ b/library/alloctests/tests/sort/zipf.rs diff --git a/library/alloc/tests/str.rs b/library/alloctests/tests/str.rs index 906fa2d425e..906fa2d425e 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloctests/tests/str.rs diff --git a/library/alloc/tests/string.rs b/library/alloctests/tests/string.rs index d996c55f946..d996c55f946 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloctests/tests/string.rs diff --git a/library/alloc/tests/sync.rs b/library/alloctests/tests/sync.rs index 6d3ab1b1d11..6d3ab1b1d11 100644 --- a/library/alloc/tests/sync.rs +++ b/library/alloctests/tests/sync.rs diff --git a/library/alloc/tests/task.rs b/library/alloctests/tests/task.rs index 390dec14484..390dec14484 100644 --- a/library/alloc/tests/task.rs +++ b/library/alloctests/tests/task.rs diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloctests/tests/testing/crash_test.rs index 502fe6c10c6..502fe6c10c6 100644 --- a/library/alloc/tests/testing/crash_test.rs +++ b/library/alloctests/tests/testing/crash_test.rs diff --git a/library/alloc/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs index 0a3dd191dc8..0a3dd191dc8 100644 --- a/library/alloc/tests/testing/mod.rs +++ b/library/alloctests/tests/testing/mod.rs diff --git a/library/alloc/tests/thin_box.rs b/library/alloctests/tests/thin_box.rs index 4c46b614127..4c46b614127 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloctests/tests/thin_box.rs diff --git a/library/alloc/tests/vec.rs b/library/alloctests/tests/vec.rs index f430d979fa8..f430d979fa8 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloctests/tests/vec.rs diff --git a/library/alloc/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 1b03c29e5bd..1b03c29e5bd 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloctests/tests/vec_deque_alloc_error.rs index 21a9118a05b..21a9118a05b 100644 --- a/library/alloc/tests/vec_deque_alloc_error.rs +++ b/library/alloctests/tests/vec_deque_alloc_error.rs diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 9d64348289c..c777dd995a6 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -184,6 +184,59 @@ pub macro Clone($item:item) { /* compiler built-in */ } +/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted) +/// +/// Cloning an object implementing this trait should in general: +/// - be O(1) (constant) time regardless of the amount of data managed by the object, +/// - not require a memory allocation, +/// - not require copying more than roughly 64 bytes (a typical cache line size), +/// - not block the current thread, +/// - not have any semantic side effects (e.g. allocating a file descriptor), and +/// - not have overhead larger than a couple of atomic operations. +/// +/// The `UseCloned` trait does not provide a method; instead, it indicates that +/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax. +/// +/// ## .use postfix syntax +/// +/// Values can be `.use`d by adding `.use` postfix to the value you want to use. +/// +/// ```ignore (this won't work until we land use) +/// fn foo(f: Foo) { +/// // if `Foo` implements `Copy` f would be copied into x. +/// // if `Foo` implements `UseCloned` f would be cloned into x. +/// // otherwise f would be moved into x. +/// let x = f.use; +/// // ... +/// } +/// ``` +/// +/// ## use closures +/// +/// Use closures allow captured values to be automatically used. +/// This is similar to have a closure that you would call `.use` over each captured value. +#[unstable(feature = "ergonomic_clones", issue = "132290")] +#[cfg_attr(not(bootstrap), lang = "use_cloned")] +pub trait UseCloned: Clone { + // Empty. +} + +macro_rules! impl_use_cloned { + ($($t:ty)*) => { + $( + #[unstable(feature = "ergonomic_clones", issue = "132290")] + impl UseCloned for $t {} + )* + } +} + +impl_use_cloned! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f16 f32 f64 f128 + bool char +} + // FIXME(aburka): these structs are used solely by #[derive] to // assert that every component of a type implements Clone or Copy. // diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 40e6eaf075e..e33f58197bb 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -404,6 +404,8 @@ macro_rules! define_bignum { } } + impl crate::clone::UseCloned for $name {} + impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { let sz = if self.size < 1 { 1 } else { self.size }; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6c9b366d903..7585ec140e3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,7 @@ //! Definitions of integer that is known not to equal zero. use super::{IntErrorKind, ParseIntError}; +use crate::clone::UseCloned; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Freeze, StructuralPartialEq}; @@ -182,6 +183,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {} + #[stable(feature = "nonzero", since = "1.28.0")] impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {} diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d8709d51ccc..58689275839 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2533,15 +2533,20 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")] /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { // note: longer-term this should be done via an intrinsic, but this has been shown // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic - let (a, b) = self.overflowing_sub(rhs); - let (c, d) = a.overflowing_sub(borrow as $SelfT); - (c, b | d) + let (a, c1) = self.overflowing_sub(rhs); + let (b, c2) = a.overflowing_sub(borrow as $SelfT); + // SAFETY: Only one of `c1` and `c2` can be set. + // For c1 to be set we need to have underflowed, but if we did then + // `a` is nonzero, which means that `c2` cannot possibly + // underflow because it's subtracting at most `1` (since it came from `bool`) + (b, unsafe { intrinsics::disjoint_bitor(c1, c2) }) } /// Calculates `self` - `rhs` with a signed `rhs` diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a9f06b92ad5..f668c6f0672 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2050,6 +2050,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {} + #[stable(feature = "rust1", since = "1.0.0")] impl<T> Default for Option<T> { /// Returns [`None`][Option::None]. diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 590ffd64b5b..8d867a269a2 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -70,3 +70,26 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } + +/// The Future version of the core prelude. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::convert::{TryFrom, TryInto}; + + #[stable(feature = "prelude_2024", since = "1.85.0")] + #[doc(no_inline)] + pub use crate::future::{Future, IntoFuture}; +} diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 92b5cba1531..ee98a47523f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1744,6 +1744,14 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl<T, E> crate::clone::UseCloned for Result<T, E> +where + T: crate::clone::UseCloned, + E: crate::clone::UseCloned, +{ +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T, E> IntoIterator for Result<T, E> { type Item = T; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index bac92ef94e7..ae28ec4baa0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -44,8 +44,9 @@ //! The most important aspect of this model is that *data races* are undefined behavior. A data race //! is defined as conflicting non-synchronized accesses where at least one of the accesses is //! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at -//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* -//! the other, according to the happens-before order of the memory model. +//! least one of them is a write. (A `compare_exchange` or `compare_exchange_weak` that does not +//! succeed is not considered a write.) They are *non-synchronized* if neither of them +//! *happens-before* the other, according to the happens-before order of the memory model. //! //! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust //! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e62aeb2ede0..6961fa8ea94 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -202,6 +202,9 @@ impl fmt::Debug for VarsOs { /// Returns [`VarError::NotUnicode`] if the variable's value is not valid /// Unicode. If this is not desired, consider using [`var_os`]. /// +/// Use [`env!`] or [`option_env!`] instead if you want to check environment +/// variables at compile time. +/// /// # Examples /// /// ``` diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 4314c8a0b18..46b5860123f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2446,7 +2446,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// # Platform-specific behavior /// /// This function currently corresponds to the `rename` function on Unix -/// and the `SetFileInformationByHandle` function on Windows. +/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows. /// /// Because of this, the behavior when both `from` and `to` exist differs. On /// Unix, if `from` is a directory, `to` must also be an (empty) directory. If diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index bdd330611de..5ac3dbc3e98 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2121,8 +2121,8 @@ mod unsafe_keyword {} #[doc(keyword = "use")] // -/// Import or rename items from other crates or modules, or specify precise capturing -/// with `use<..>`. +/// Import or rename items from other crates or modules, use values under ergonomic clones +/// semantic, or specify precise capturing with `use<..>`. /// /// ## Importing items /// @@ -2205,6 +2205,11 @@ mod unsafe_keyword {} /// /// For more details about precise capturing, see the [Reference][ref-impl-trait]. /// +/// ## Ergonomic clones +/// +/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the +/// value implements `UseCloned` or moving it otherwise. +/// /// [`crate`]: keyword.crate.html /// [`self`]: keyword.self.html /// [`super`]: keyword.super.html diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 992a9207a72..5f7097c26e2 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -160,3 +160,18 @@ pub mod rust_2024 { #[doc(no_inline)] pub use core::prelude::rust_2024::*; } + +/// The Future version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[unstable(feature = "prelude_next", issue = "none")] + #[doc(no_inline)] + pub use core::prelude::rust_future::*; +} diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys/fs/common.rs index bfd684d295b..bfd684d295b 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys/fs/common.rs diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/fs/hermit.rs index d4bf84dc185..e9339ff261c 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,18 +1,18 @@ -use super::fd::FileDesc; -use super::hermit_abi::{ - self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, - O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, -}; use crate::ffi::{CStr, OsStr, OsString, c_char}; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; +use crate::os::hermit::hermit_abi::{ + self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, + O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, +}; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; +pub use crate::sys::fs::common::{copy, exists}; +use crate::sys::pal::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::{cvt, unsupported}; -pub use crate::sys_common::fs::{copy, exists}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, mem}; diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs new file mode 100644 index 00000000000..c2e19eb393a --- /dev/null +++ b/library/std/src/sys/fs/mod.rs @@ -0,0 +1,28 @@ +#![deny(unsafe_op_in_unsafe_fn)] + +pub mod common; + +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/fs/solid.rs index 4e741943283..39de933b724 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/fs/solid.rs @@ -1,4 +1,5 @@ -use super::{abi, error}; +#![allow(dead_code)] + use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; @@ -7,9 +8,10 @@ use crate::os::raw::{c_int, c_short}; use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; +pub use crate::sys::fs::common::exists; +use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; use crate::sys::unsupported; -pub use crate::sys_common::fs::exists; use crate::sys_common::ignore_notfound; type CIntNotMinusOne = core::num::niche_types::NotAllOnes<c_int>; diff --git a/library/std/src/sys/pal/uefi/fs.rs b/library/std/src/sys/fs/uefi.rs index 45e93deffa3..45e93deffa3 100644 --- a/library/std/src/sys/pal/uefi/fs.rs +++ b/library/std/src/sys/fs/uefi.rs diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/fs/unix.rs index 20ba915af13..914971934bf 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1,3 +1,5 @@ +#![allow(nonstandard_style)] +#![allow(unsafe_op_in_unsafe_fn)] // miri has some special hacks here that make things unused. #![cfg_attr(miri, allow(unused))] @@ -79,13 +81,13 @@ use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::FileDesc; +pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; #[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::syscall; #[cfg(target_os = "android")] use crate::sys::weak::weak; use crate::sys::{cvt, cvt_r}; -pub use crate::sys_common::fs::exists; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{mem, ptr}; @@ -699,6 +701,8 @@ impl Iterator for ReadDir { target_os = "hurd", ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { + use crate::sys::os::{errno, set_errno}; + if self.end_of_stream { return None; } @@ -710,7 +714,7 @@ impl Iterator for ReadDir { // with unlimited or variable NAME_MAX. Many modern platforms guarantee // thread safety for readdir() as long an individual DIR* is not accessed // concurrently, which is sufficient for Rust. - super::os::set_errno(0); + set_errno(0); let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0); if entry_ptr.is_null() { // We either encountered an error, or reached the end. Either way, @@ -719,7 +723,7 @@ impl Iterator for ReadDir { // To distinguish between errors and end-of-directory, we had to clear // errno beforehand to check for an error now. - return match super::os::errno() { + return match errno() { 0 => None, e => Some(Err(Error::from_raw_os_error(e))), }; @@ -1932,7 +1936,7 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::File; - use crate::sys_common::fs::NOT_FILE_ERROR; + use crate::sys::fs::common::NOT_FILE_ERROR; let reader = File::open(from)?; let metadata = reader.metadata()?; @@ -2151,7 +2155,7 @@ pub use remove_dir_impl::remove_dir_all; miri ))] mod remove_dir_impl { - pub use crate::sys_common::fs::remove_dir_all; + pub use crate::sys::fs::common::remove_dir_all; } // Modern implementation using openat(), unlinkat() and fdopendir() diff --git a/library/std/src/sys/pal/unix/fs/tests.rs b/library/std/src/sys/fs/unix/tests.rs index 71be3472148..8875a318db7 100644 --- a/library/std/src/sys/pal/unix/fs/tests.rs +++ b/library/std/src/sys/fs/unix/tests.rs @@ -1,4 +1,4 @@ -use crate::sys::pal::unix::fs::FilePermissions; +use crate::sys::fs::FilePermissions; #[test] fn test_debug_permissions() { diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/fs/unsupported.rs index 45e93deffa3..45e93deffa3 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/fs/unsupported.rs diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/fs/wasi.rs index 6d7d125fc4d..773040571bc 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -1,6 +1,3 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use super::fd::WasiFd; use crate::ffi::{CStr, OsStr, OsString}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, ManuallyDrop}; @@ -10,9 +7,10 @@ use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::fd::WasiFd; +pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; use crate::sys::unsupported; -pub use crate::sys_common::fs::exists; use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; use crate::{fmt, iter, ptr}; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/fs/windows.rs index 17dc3e5c257..362e64abf1a 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1,15 +1,17 @@ -use super::api::{self, WinError, set_file_information_by_handle}; -use super::{IoResult, to_u16s}; -use crate::alloc::{alloc, handle_alloc_error}; +#![allow(nonstandard_style)] + +use crate::alloc::{Layout, alloc, dealloc}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem::{self, MaybeUninit}; +use crate::mem::{self, MaybeUninit, offset_of}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::handle::Handle; +use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; +use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; use crate::sys::path::maybe_verbatim; use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; @@ -167,7 +169,7 @@ impl DirEntry { } pub fn file_name(&self) -> OsString { - let filename = super::truncate_utf16_at_nul(&self.data.cFileName); + let filename = truncate_utf16_at_nul(&self.data.cFileName); OsString::from_wide(filename) } @@ -695,7 +697,7 @@ impl File { // Turn `\??\` into `\\?\` (a verbatim path). subst[1] = b'\\' as u16; // Attempt to convert to a more user-friendly path. - let user = super::args::from_wide_to_user_path( + let user = crate::sys::args::from_wide_to_user_path( subst.iter().copied().chain([0]).collect(), )?; Ok(PathBuf::from(OsString::from_wide(user.strip_suffix(&[0]).unwrap_or(&user)))) @@ -1241,139 +1243,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { let old = maybe_verbatim(old)?; let new = maybe_verbatim(new)?; - let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap(); - - // The last field of FILE_RENAME_INFO, the file name, is unsized, - // and FILE_RENAME_INFO has two padding bytes. - // Therefore we need to make sure to not allocate less than - // size_of::<c::FILE_RENAME_INFO>() bytes, which would be the case with - // 0 or 1 character paths + a null byte. - let struct_size = size_of::<c::FILE_RENAME_INFO>() - .max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * size_of::<u16>()); - - let struct_size: u32 = struct_size.try_into().unwrap(); - - let create_file = |extra_access, extra_flags| { - let handle = unsafe { - HandleOrInvalid::from_raw_handle(c::CreateFileW( - old.as_ptr(), - c::SYNCHRONIZE | c::DELETE | extra_access, - c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, - ptr::null(), - c::OPEN_EXISTING, - c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags, - ptr::null_mut(), - )) - }; - - OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error()) - }; - - // The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly. - // If `old` refers to a mount point, we move it instead of the target. - let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) { - Ok(handle) => { - let mut file_attribute_tag_info: MaybeUninit<c::FILE_ATTRIBUTE_TAG_INFO> = - MaybeUninit::uninit(); - - let result = unsafe { - cvt(c::GetFileInformationByHandleEx( - handle.as_raw_handle(), - c::FileAttributeTagInfo, - file_attribute_tag_info.as_mut_ptr().cast(), - size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(), - )) + if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { + let err = api::get_last_error(); + // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move + // the file while ignoring the readonly attribute. + // This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`. + if err == WinError::ACCESS_DENIED { + let mut opts = OpenOptions::new(); + opts.access_mode(c::DELETE); + opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); + let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() }; + + // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` + // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. + let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into() + else { + return Err(err).io_result(); }; - - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) - || err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _) - { - // `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes. - // Since we know we passed the correct arguments, this means the underlying driver didn't understand our request; - // `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior. - None - } else { - Some(Err(err)) - } - } else { - // SAFETY: The struct has been initialized by GetFileInformationByHandleEx - let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() }; - let file_type = FileType::new( - file_attribute_tag_info.FileAttributes, - file_attribute_tag_info.ReparseTag, - ); - - if file_type.is_symlink() { - // The file is a mount point, junction point or symlink so - // don't reopen the file so that the link gets renamed. - Some(Ok(handle)) - } else { - // Otherwise reopen the file without inhibiting reparse point behavior. - None + let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap(); + let struct_size = offset + new_len_without_nul_in_bytes + 2; + let layout = + Layout::from_size_align(struct_size as usize, align_of::<c::FILE_RENAME_INFO>()) + .unwrap(); + + // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. + let file_rename_info; + unsafe { + file_rename_info = alloc(layout).cast::<c::FILE_RENAME_INFO>(); + if file_rename_info.is_null() { + return Err(io::ErrorKind::OutOfMemory.into()); } - } - } - // The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it. - Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None, - Err(err) => Some(Err(err)), - } - .unwrap_or_else(|| create_file(0, 0))?; - - let layout = - core::alloc::Layout::from_size_align(struct_size as _, align_of::<c::FILE_RENAME_INFO>()) - .unwrap(); - - let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO; - - if file_rename_info.is_null() { - handle_alloc_error(layout); - } - // SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator. - let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) }; + (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { + Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS + | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, + }); - // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename. - unsafe { - (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { - Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, - }); - - (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); - (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - - new.as_ptr() - .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len()); - } - - // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`. - let result = unsafe { - cvt(c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfoEx, - (&raw const *file_rename_info).cast::<c_void>(), - struct_size, - )) - }; + (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); + // Don't include the NULL in the size + (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) { - // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo. - file_rename_info.Anonymous.ReplaceIfExists = true; + new.as_ptr().copy_to_nonoverlapping( + (&raw mut (*file_rename_info).FileName).cast::<u16>(), + new.len(), + ); + } - cvt(unsafe { + let result = unsafe { c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfo, - (&raw const *file_rename_info).cast::<c_void>(), + f.as_raw_handle(), + c::FileRenameInfoEx, + file_rename_info.cast::<c_void>(), struct_size, ) - })?; + }; + unsafe { dealloc(file_rename_info.cast::<u8>(), layout) }; + if result == 0 { + if api::get_last_error() == WinError::DIR_NOT_EMPTY { + return Err(WinError::DIR_NOT_EMPTY).io_result(); + } else { + return Err(err).io_result(); + } + } } else { - return Err(err); + return Err(err).io_result(); } } - Ok(()) } @@ -1559,7 +1494,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { } fn get_path(f: &File) -> io::Result<PathBuf> { - super::fill_utf16_buf( + fill_utf16_buf( |buf, sz| unsafe { c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, diff --git a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index 9416049da78..f51eced8416 100644 --- a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -33,7 +33,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use super::{AsRawHandle, DirBuff, File, FromRawHandle}; use crate::sys::c; -use crate::sys::pal::windows::api::WinError; +use crate::sys::pal::api::WinError; use crate::thread; // The maximum number of times to spin when waiting for deletes to complete. diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 1032fcba5e2..09677b9d642 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -12,11 +12,13 @@ pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; pub mod exit_guard; +pub mod fs; pub mod io; pub mod net; pub mod os_str; pub mod path; pub mod random; +pub mod stdio; pub mod sync; pub mod thread_local; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 21cbac643bb..608245bd430 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -21,14 +21,12 @@ use crate::os::raw::c_char; pub mod args; pub mod env; pub mod fd; -pub mod fs; pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs deleted file mode 100644 index 3ea00f5cc5e..00000000000 --- a/library/std/src/sys/pal/hermit/stdio.rs +++ /dev/null @@ -1,97 +0,0 @@ -use super::hermit_abi; -use crate::io; -use crate::io::{IoSlice, IoSliceMut}; -use crate::mem::ManuallyDrop; -use crate::os::hermit::io::FromRawFd; -use crate::sys::fd::FileDesc; - -pub struct Stdin; -pub struct Stdout; -pub struct Stderr; - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) } - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs) - } - } - - #[inline] - fn is_read_vectored(&self) -> bool { - true - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs) - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs) - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 128; - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(hermit_abi::EBADF) -} - -pub fn panic_output() -> Option<impl io::Write> { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs index 90981bd6a6a..2c805a4d0af 100644 --- a/library/std/src/sys/pal/sgx/abi/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/mod.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::Write; // runtime features -pub(super) mod panic; +pub mod panic; mod reloc; // library features diff --git a/library/std/src/sys/pal/sgx/libunwind_integration.rs b/library/std/src/sys/pal/sgx/libunwind_integration.rs index 6d0d78d1eb9..b5419ad05de 100644 --- a/library/std/src/sys/pal/sgx/libunwind_integration.rs +++ b/library/std/src/sys/pal/sgx/libunwind_integration.rs @@ -4,6 +4,7 @@ #![cfg(not(test))] use crate::sys::sync::RwLock; +use crate::{slice, str}; // Verify that the byte pattern libunwind uses to initialize an RwLock is // equivalent to the value of RwLock::new(). If the value changes, @@ -44,3 +45,14 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 { unsafe { (*p).write_unlock() }; return 0; } + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{s}"); + } +} diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 37ca6b08c95..bb419c2530e 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -12,15 +12,12 @@ pub mod abi; pub mod args; pub mod env; pub mod fd; -#[path = "../unsupported/fs.rs"] -pub mod fs; mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod thread_parking; pub mod time; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 06af7bfade0..e4a61fdcfe3 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -22,13 +22,11 @@ pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` pub(crate) mod error; -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub use self::itron::{thread, thread_parking}; pub mod time; diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index 3f9bbb0b63c..c39d715c6a6 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -35,7 +35,7 @@ impl SystemTime { SystemTime(t) } - pub(super) fn from_time_t(t: abi::time_t) -> Self { + pub fn from_time_t(t: abi::time_t) -> Self { Self(t) } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 3632524157d..41b25121592 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -11,14 +11,11 @@ pub mod args; #[path = "../unsupported/env.rs"] pub mod env; //pub mod fd; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; #[allow(non_upper_case_globals)] #[path = "../unix/time.rs"] diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 6a03e240c6b..714dc392688 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -15,13 +15,11 @@ pub mod args; pub mod env; -pub mod fs; pub mod helpers; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index c0b56d8d2b2..419abe732ac 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -9,7 +9,6 @@ pub mod weak; pub mod args; pub mod env; pub mod fd; -pub mod fs; pub mod futex; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod kernel_copy; @@ -19,7 +18,6 @@ pub mod os; pub mod pipe; pub mod process; pub mod stack_overflow; -pub mod stdio; pub mod sync; pub mod thread; pub mod thread_parking; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index b1aaeb1b4c8..bcea699f3b2 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -2,11 +2,9 @@ pub mod args; pub mod env; -pub mod fs; pub mod os; pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index f4588a60ea9..c89832857dd 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -16,7 +16,6 @@ pub mod args; pub mod env; pub mod fd; -pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; @@ -26,7 +25,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 72c9742b2e5..3008ba88753 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -12,8 +12,6 @@ pub mod args; pub mod env; #[path = "../wasi/fd.rs"] pub mod fd; -#[path = "../wasi/fs.rs"] -pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; @@ -24,8 +22,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../wasi/stdio.rs"] -pub mod stdio; #[path = "../wasi/thread.rs"] pub mod thread; #[path = "../wasi/time.rs"] diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 32d59c4d0f7..175fe75357f 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -19,16 +19,12 @@ #[path = "../unsupported/args.rs"] pub mod args; pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stdio.rs"] -pub mod stdio; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 40b2bed73c0..004cbee52f6 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -237,6 +237,17 @@ compat_fn_with_fallback! { STATUS_NOT_IMPLEMENTED } #[cfg(target_vendor = "uwp")] + pub fn NtOpenFile( + filehandle: *mut HANDLE, + desiredaccess: u32, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + shareaccess: u32, + openoptions: u32 + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + #[cfg(target_vendor = "uwp")] pub fn NtReadFile( filehandle: HANDLE, event: HANDLE, diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 1eca346b76c..6eb68f3a3bc 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -17,14 +17,12 @@ pub mod api; pub mod args; pub mod c; pub mod env; -pub mod fs; #[cfg(not(target_vendor = "win7"))] pub mod futex; pub mod handle; pub mod os; pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; cfg_if::cfg_if! { @@ -37,7 +35,7 @@ cfg_if::cfg_if! { } /// Map a [`Result<T, WinError>`] to [`io::Result<T>`](crate::io::Result<T>). -trait IoResult<T> { +pub trait IoResult<T> { fn io_result(self) -> crate::io::Result<T>; } impl<T> IoResult<T> for Result<T, api::WinError> { diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 1bd0e67f371..7d823012ad1 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -3,14 +3,11 @@ pub mod args; #[path = "../unsupported/env.rs"] pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 8d8fe321f66..499e2787201 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -14,14 +14,11 @@ pub mod abi; #[path = "../zkvm/args.rs"] pub mod args; pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; #[path = "../unsupported/time.rs"] diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs new file mode 100644 index 00000000000..2a9167bfe96 --- /dev/null +++ b/library/std/src/sys/stdio/mod.rs @@ -0,0 +1,38 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(any( + target_family = "unix", + target_os = "hermit" + ))] { + mod unix; + pub use unix::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "teeos")] { + mod teeos; + pub use teeos::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/sgx/stdio.rs b/library/std/src/sys/stdio/sgx.rs index 726a93acae4..03d754cb217 100644 --- a/library/std/src/sys/pal/sgx/stdio.rs +++ b/library/std/src/sys/stdio/sgx.rs @@ -1,10 +1,6 @@ use fortanix_sgx_abi as abi; use crate::io; -#[cfg(not(test))] -use crate::slice; -#[cfg(not(test))] -use crate::str; use crate::sys::fd::FileDesc; pub struct Stdin(()); @@ -70,19 +66,5 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub fn panic_output() -> Option<impl io::Write> { - super::abi::panic::SgxPanicOutput::new() -} - -// This function is needed by libunwind. The symbol is named in pre-link args -// for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{s}"); - } + crate::sys::pal::abi::panic::SgxPanicOutput::new() } diff --git a/library/std/src/sys/pal/solid/stdio.rs b/library/std/src/sys/stdio/solid.rs index 50f0176967b..a2ff4bb212f 100644 --- a/library/std/src/sys/pal/solid/stdio.rs +++ b/library/std/src/sys/stdio/solid.rs @@ -1,5 +1,5 @@ -use super::abi; use crate::io; +use crate::sys::pal::abi; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys/pal/teeos/stdio.rs b/library/std/src/sys/stdio/teeos.rs index 67e251812da..67e251812da 100644 --- a/library/std/src/sys/pal/teeos/stdio.rs +++ b/library/std/src/sys/stdio/teeos.rs diff --git a/library/std/src/sys/pal/uefi/stdio.rs b/library/std/src/sys/stdio/uefi.rs index 257e321dd03..257e321dd03 100644 --- a/library/std/src/sys/pal/uefi/stdio.rs +++ b/library/std/src/sys/stdio/uefi.rs diff --git a/library/std/src/sys/pal/unix/stdio.rs b/library/std/src/sys/stdio/unix.rs index 8c2f61a40de..8d133857c59 100644 --- a/library/std/src/sys/pal/unix/stdio.rs +++ b/library/std/src/sys/stdio/unix.rs @@ -1,5 +1,15 @@ -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +#[cfg(target_os = "hermit")] +use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; +#[cfg(target_family = "unix")] +use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; + +#[cfg(target_family = "unix")] +use crate::io::BorrowedCursor; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; +#[cfg(target_os = "hermit")] +use crate::os::hermit::io::FromRawFd; +#[cfg(target_family = "unix")] use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; @@ -15,15 +25,16 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) } } + #[cfg(not(target_os = "hermit"))] fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) } } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_vectored(bufs) } } #[inline] @@ -40,13 +51,11 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs) - } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write_vectored(bufs) } } #[inline] @@ -68,13 +77,11 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs) - } + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write_vectored(bufs) } } #[inline] @@ -89,7 +96,7 @@ impl io::Write for Stderr { } pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) + err.raw_os_error() == Some(EBADF as i32) } pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; diff --git a/library/std/src/sys/pal/unsupported/stdio.rs b/library/std/src/sys/stdio/unsupported.rs index b5e3f5be988..b5e3f5be988 100644 --- a/library/std/src/sys/pal/unsupported/stdio.rs +++ b/library/std/src/sys/stdio/unsupported.rs diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/stdio/wasi.rs index fb21cb4d393..8105b0cfa2f 100644 --- a/library/std/src/sys/pal/wasi/stdio.rs +++ b/library/std/src/sys/stdio/wasi.rs @@ -1,10 +1,10 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use super::fd::WasiFd; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::sys::pal::fd::WasiFd; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/stdio/windows.rs index 58d3406e138..9b27f76b9dd 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/stdio/windows.rs @@ -3,10 +3,10 @@ use core::char::MAX_LEN_UTF8; use core::str::utf8_char_width; -use super::api::{self, WinError}; use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::sys::handle::Handle; +use crate::sys::pal::api::{self, WinError}; use crate::sys::{c, cvt}; use crate::{cmp, io, ptr, str}; diff --git a/library/std/src/sys/pal/windows/stdio/tests.rs b/library/std/src/sys/stdio/windows/tests.rs index 1e53e0bee63..1e53e0bee63 100644 --- a/library/std/src/sys/pal/windows/stdio/tests.rs +++ b/library/std/src/sys/stdio/windows/tests.rs diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/stdio/xous.rs index 71736145221..71736145221 100644 --- a/library/std/src/sys/pal/xous/stdio.rs +++ b/library/std/src/sys/stdio/xous.rs diff --git a/library/std/src/sys/pal/zkvm/stdio.rs b/library/std/src/sys/stdio/zkvm.rs index 0bcb54744b0..f31c6c26e87 100644 --- a/library/std/src/sys/pal/zkvm/stdio.rs +++ b/library/std/src/sys/stdio/zkvm.rs @@ -1,6 +1,5 @@ -use super::abi; -use super::abi::fileno; use crate::io::{self, BorrowedCursor}; +use crate::sys::pal::abi::{self, fileno}; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 4dc67d26bd8..2a5de7f6666 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod fs; pub mod process; pub mod wstr; pub mod wtf8; diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index e89bde8b1ab..939fab7d5fe 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -34,7 +34,7 @@ pub macro link { } #[cfg(not(feature = "windows_raw_dylib"))] -#[link(name = "advapi32")] +#[cfg_attr(target_vendor = "win7", link(name = "advapi32"))] #[link(name = "ntdll")] #[link(name = "userenv")] #[link(name = "ws2_32")] diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 88aa70d4f2f..6cb0b19d763 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -56,6 +56,7 @@ check-aux: # Run standard library tests in Miri. $(Q)$(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --no-doc @@ -63,6 +64,7 @@ check-aux: $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --doc diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b8bbe1eb5f8..18aa3119842 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -45,7 +45,10 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library") + run.crate_or_deps("sysroot") + .crate_or_deps("coretests") + .crate_or_deps("alloctests") + .path("library") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 78219500737..319a2233b1c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2020,7 +2020,9 @@ impl Step for Assemble { builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage=target_compiler.stage)); } - maybe_install_llvm_bitcode_linker(target_compiler); + let mut precompiled_compiler = target_compiler; + precompiled_compiler.forced_compiler(true); + maybe_install_llvm_bitcode_linker(precompiled_compiler); return target_compiler; } @@ -2203,7 +2205,7 @@ impl Step for Assemble { ); } - maybe_install_llvm_bitcode_linker(build_compiler); + maybe_install_llvm_bitcode_linker(target_compiler); // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0296346009f..ec0edeab996 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -230,8 +230,10 @@ fn make_win_dist( "libiconv.a", "libmoldname.a", "libpthread.a", - //Windows import libs - //This should contain only the set of libraries necessary to link the standard library. + // Windows import libs + // This *should* contain only the set of libraries necessary to link the standard library, + // however we've had problems with people accidentally depending on extra libs being here, + // so we can't easily remove entries. "libadvapi32.a", "libbcrypt.a", "libcomctl32.a", diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index e8b6a577cea..70789fbbeeb 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -125,6 +125,7 @@ impl Step for Gcc { t!(stamp.remove()); let _time = helpers::timeit(builder); t!(fs::create_dir_all(&out_dir)); + t!(fs::create_dir_all(&install_dir)); let libgccjit_path = libgccjit_built_path(&install_dir); if builder.config.dry_run() { @@ -185,8 +186,16 @@ impl Step for Gcc { } configure_cmd.run(builder); - command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder); - command("make").current_dir(&out_dir).arg("install").run(builder); + command("make") + .current_dir(&out_dir) + .arg("--silent") + .arg(format!("-j{}", builder.jobs())) + .run_capture_stdout(builder); + command("make") + .current_dir(&out_dir) + .arg("--silent") + .arg("install") + .run_capture_stdout(builder); let lib_alias = install_dir.join("lib/libgccjit.so.0"); if !lib_alias.exists() { diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index fea8232296e..1ef86e674f0 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -367,3 +367,28 @@ impl Step for FeaturesStatusDump { cmd.run(builder); } } + +/// Dummy step that can be used to deliberately trigger bootstrap's step cycle +/// detector, for automated and manual testing. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct CyclicStep { + n: u32, +} + +impl Step for CyclicStep { + type Output = (); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("cyclic-step") + } + + fn make_run(run: RunConfig<'_>) { + // Start with n=2, so that we build up a few stack entries before panicking. + run.builder.ensure(CyclicStep { n: 2 }) + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // When n=0, the step will try to ensure itself, causing a step cycle. + builder.ensure(CyclicStep { n: self.n.saturating_sub(1) }) + } +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4b7c8d5770e..e80f8f9a4b7 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2609,7 +2609,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests") + run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests") } fn make_run(run: RunConfig<'_>) { @@ -2724,12 +2724,16 @@ impl Step for Crate { }; let mut crates = self.crates.clone(); - // The core crate can't directly be tested. We could silently - // ignore it, but adding it's own test crate is less confusing - // for users. We still keep core itself for doctests. + // The core and alloc crates can't directly be tested. We + // could silently ignore them, but adding their own test + // crates is less confusing for users. We still keep core and + // alloc themself for doctests if crates.iter().any(|crate_| crate_ == "core") { crates.push("coretests".to_owned()); } + if crates.iter().any(|crate_| crate_ == "alloc") { + crates.push("alloctests".to_owned()); + } run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 65633c9ea7c..e0cf2c12139 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -121,10 +121,18 @@ impl Step for ToolBuild { match self.mode { Mode::ToolRustc => { - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, target)); + // If compiler was forced, its artifacts should be prepared earlier. + if !self.compiler.is_forced_compiler() { + builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); + builder.ensure(compile::Rustc::new(self.compiler, target)); + } + } + Mode::ToolStd => { + // If compiler was forced, its artifacts should be prepared earlier. + if !self.compiler.is_forced_compiler() { + builder.ensure(compile::Std::new(self.compiler, target)) + } } - Mode::ToolStd => builder.ensure(compile::Std::new(self.compiler, target)), Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), } @@ -319,18 +327,20 @@ pub(crate) fn get_tool_rustc_compiler( builder: &Builder<'_>, target_compiler: Compiler, ) -> Compiler { - if builder.download_rustc() && target_compiler.stage == 1 { - // We already have the stage 1 compiler, we don't need to cut the stage. - builder.compiler(target_compiler.stage, builder.config.build) - } else if target_compiler.is_forced_compiler() { - target_compiler - } else { - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage - // compilers, which isn't what we want. Rustc tools should be linked in the same way as the - // compiler it's paired with, so it must be built with the previous stage compiler. - builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build) + if target_compiler.is_forced_compiler() { + return target_compiler; } + + if builder.download_rustc() && target_compiler.stage > 0 { + // We already have the stage N compiler, we don't need to cut the stage. + return builder.compiler(target_compiler.stage, builder.config.build); + } + + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage + // compilers, which isn't what we want. Rustc tools should be linked in the same way as the + // compiler it's paired with, so it must be built with the previous stage compiler. + builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build) } /// Links a built tool binary with the given `name` from the build directory to the @@ -1191,13 +1201,23 @@ fn run_tool_build_step( } } -tool_extended!(Cargofmt { path: "src/tools/rustfmt", tool_name: "cargo-fmt", stable: true }); -tool_extended!(CargoClippy { path: "src/tools/clippy", tool_name: "cargo-clippy", stable: true }); +tool_extended!(Cargofmt { + path: "src/tools/rustfmt", + tool_name: "cargo-fmt", + stable: true, + add_bins_to_sysroot: ["cargo-fmt"] +}); +tool_extended!(CargoClippy { + path: "src/tools/clippy", + tool_name: "cargo-clippy", + stable: true, + add_bins_to_sysroot: ["cargo-clippy"] +}); tool_extended!(Clippy { path: "src/tools/clippy", tool_name: "clippy-driver", stable: true, - add_bins_to_sysroot: ["clippy-driver", "cargo-clippy"] + add_bins_to_sysroot: ["clippy-driver"] }); tool_extended!(Miri { path: "src/tools/miri", @@ -1216,7 +1236,7 @@ tool_extended!(Rustfmt { path: "src/tools/rustfmt", tool_name: "rustfmt", stable: true, - add_bins_to_sysroot: ["rustfmt", "cargo-fmt"] + add_bins_to_sysroot: ["rustfmt"] }); #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d1d52d82eaa..2cbf82ccda3 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -597,7 +597,7 @@ impl Builder<'_> { // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib // unconditionally. - if let Mode::Rustc | Mode::ToolRustc = mode { + if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode { rustflags.arg("--cfg=windows_raw_dylib"); } @@ -1072,12 +1072,17 @@ impl Builder<'_> { } if mode == Mode::Rustc { + // NOTE: rustc-specific lints are specified here. Normal rust lints + // are specified in the `[workspace.lints.rust]` section in the + // top-level `Cargo.toml`. If/when tool lints are supported by + // Cargo, these lints can be move to a `[workspace.lints.rustc]` + // section in the top-level `Cargo.toml`. + // + // NOTE: these flags are added to RUSTFLAGS, which is ignored when + // compiling proc macro crates such as `rustc_macros`, + // unfortunately. rustflags.arg("-Wrustc::internal"); rustflags.arg("-Drustc::symbol_intern_string_literal"); - // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all - // of the individual lints are satisfied. - rustflags.arg("-Wkeyword_idents_2024"); - rustflags.arg("-Wunsafe_op_in_unsafe_fn"); } if self.config.rust_frame_pointers { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 801894e9ff1..8e1cecfcd18 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -50,7 +50,7 @@ pub struct Builder<'a> { /// A stack of [`Step`]s to run before we can run this builder. The output /// of steps is cached in [`Self::cache`]. - stack: RefCell<Vec<Box<dyn Any>>>, + stack: RefCell<Vec<Box<dyn AnyDebug>>>, /// The total amount of time we spent running [`Step`]s in [`Self::stack`]. time_spent_on_dependencies: Cell<Duration>, @@ -69,6 +69,21 @@ impl Deref for Builder<'_> { } } +/// This trait is similar to `Any`, except that it also exposes the underlying +/// type's [`Debug`] implementation. +/// +/// (Trying to debug-print `dyn Any` results in the unhelpful `"Any { .. }"`.) +trait AnyDebug: Any + Debug {} +impl<T: Any + Debug> AnyDebug for T {} +impl dyn AnyDebug { + /// Equivalent to `<dyn Any>::downcast_ref`. + fn downcast_ref<T: Any>(&self) -> Option<&T> { + (self as &dyn Any).downcast_ref() + } + + // Feel free to add other `dyn Any` methods as necessary. +} + pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// Result type of `Step::run`. type Output: Clone; @@ -890,6 +905,7 @@ impl<'a> Builder<'a> { gcc::Gcc, llvm::Sanitizers, tool::Rustfmt, + tool::Cargofmt, tool::Miri, tool::CargoMiri, llvm::Lld, @@ -1101,6 +1117,7 @@ impl<'a> Builder<'a> { run::GenerateCompletions, run::UnicodeTableGenerator, run::FeaturesStatusDump, + run::CyclicStep, ), Kind::Setup => { describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 63a1bbc24f1..e8820e3a828 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1,4 +1,4 @@ -use std::thread; +use std::{panic, thread}; use llvm::prebuilt_llvm_config; @@ -1135,3 +1135,35 @@ fn test_get_tool_rustc_compiler() { let actual = tool::get_tool_rustc_compiler(&builder, compiler); assert_eq!(expected, actual); } + +/// When bootstrap detects a step dependency cycle (which is a bug), its panic +/// message should show the actual steps on the stack, not just several copies +/// of `Any { .. }`. +#[test] +fn step_cycle_debug() { + let cmd = ["run", "cyclic-step"].map(str::to_owned); + let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); + + let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err(); + let err = err.downcast_ref::<String>().unwrap().as_str(); + + assert!(!err.contains("Any")); + assert!(err.contains("CyclicStep { n: 1 }")); +} + +/// The `AnyDebug` trait should delegate to the underlying type's `Debug`, and +/// should also allow downcasting as expected. +#[test] +fn any_debug() { + #[derive(Debug, PartialEq, Eq)] + struct MyStruct { + x: u32, + } + + let x: &dyn AnyDebug = &MyStruct { x: 7 }; + + // Debug-formatting should delegate to the underlying type. + assert_eq!(format!("{x:?}"), format!("{:?}", MyStruct { x: 7 })); + // Downcasting to the underlying type should succeed. + assert_eq!(x.downcast_ref::<MyStruct>(), Some(&MyStruct { x: 7 })); +} diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 788c8bbdc84..994ccabf0eb 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -96,7 +96,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[ pub struct Compiler { stage: u32, host: TargetSelection, - /// Indicates whether `compiler_for` was used to force a specific compiler stage. + /// Indicates whether the compiler was forced to use a specific stage. /// This field is ignored in `Hash` and `PartialEq` implementations as only the `stage` /// and `host` fields are relevant for those. forced_compiler: bool, @@ -1998,7 +1998,7 @@ impl Compiler { self.stage == 0 && self.host == build.build } - /// Indicates whether `compiler_for` was used to force a specific compiler stage. + /// Indicates whether the compiler was forced to use a specific stage. pub fn is_forced_compiler(&self) -> bool { self.forced_compiler } diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index eb306550fc4..b6daac32a44 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -74,7 +74,7 @@ pub struct Test { pub outcome: TestOutcome, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] #[serde(tag = "outcome", rename_all = "snake_case")] pub enum TestOutcome { Passed, diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 16edd681886..52e7638d98b 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,5 +1,6 @@ mod cpu_usage; mod datadog; +mod merge_report; mod metrics; mod utils; @@ -13,6 +14,7 @@ use serde_yaml::Value; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; +use crate::merge_report::post_merge_report; use crate::metrics::postprocess_metrics; use crate::utils::load_env_var; @@ -373,6 +375,13 @@ enum Args { /// Path to a CSV containing the CI job CPU usage. cpu_usage_csv: PathBuf, }, + /// Generate a report of test execution changes between two rustc commits. + PostMergeReport { + /// Parent commit to use as a base of the comparison. + parent: String, + /// Current commit that will be compared to `parent`. + current: String, + }, } #[derive(clap::ValueEnum, Clone)] @@ -410,6 +419,9 @@ fn main() -> anyhow::Result<()> { Args::PostprocessMetrics { metrics_path, summary_path } => { postprocess_metrics(&metrics_path, &summary_path)?; } + Args::PostMergeReport { current: commit, parent } => { + post_merge_report(load_db(default_jobs_file)?, parent, commit)?; + } } Ok(()) diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs new file mode 100644 index 00000000000..5dd662280f0 --- /dev/null +++ b/src/ci/citool/src/merge_report.rs @@ -0,0 +1,257 @@ +use std::cmp::Reverse; +use std::collections::HashMap; + +use anyhow::Context; +use build_helper::metrics::{JsonRoot, TestOutcome}; + +use crate::JobDatabase; +use crate::metrics::get_test_suites; + +type Sha = String; +type JobName = String; + +/// Computes a post merge CI analysis report between the `parent` and `current` commits. +pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> { + let jobs = download_all_metrics(&job_db, &parent, ¤t)?; + let diffs = aggregate_test_diffs(&jobs)?; + report_test_changes(diffs); + + Ok(()) +} + +struct JobMetrics { + parent: Option<JsonRoot>, + current: JsonRoot, +} + +/// Download before/after metrics for all auto jobs in the job database. +fn download_all_metrics( + job_db: &JobDatabase, + parent: &str, + current: &str, +) -> anyhow::Result<HashMap<JobName, JobMetrics>> { + let mut jobs = HashMap::default(); + + for job in &job_db.auto_jobs { + eprintln!("Downloading metrics of job {}", job.name); + let metrics_parent = match download_job_metrics(&job.name, parent) { + Ok(metrics) => Some(metrics), + Err(error) => { + eprintln!( + r#"Did not find metrics for job `{}` at `{}`: {error:?}. +Maybe it was newly added?"#, + job.name, parent + ); + None + } + }; + let metrics_current = download_job_metrics(&job.name, current)?; + jobs.insert( + job.name.clone(), + JobMetrics { parent: metrics_parent, current: metrics_current }, + ); + } + Ok(jobs) +} + +fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> { + let url = get_metrics_url(job_name, sha); + let mut response = ureq::get(&url).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Cannot fetch metrics from {url}: {}\n{}", + response.status(), + response.body_mut().read_to_string()? + )); + } + let data: JsonRoot = response + .body_mut() + .read_json() + .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; + Ok(data) +} + +fn get_metrics_url(job_name: &str, sha: &str) -> String { + let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" }; + format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") +} + +fn aggregate_test_diffs( + jobs: &HashMap<JobName, JobMetrics>, +) -> anyhow::Result<Vec<AggregatedTestDiffs>> { + let mut job_diffs = vec![]; + + // Aggregate test suites + for (name, metrics) in jobs { + if let Some(parent) = &metrics.parent { + let tests_parent = aggregate_tests(parent); + let tests_current = aggregate_tests(&metrics.current); + let test_diffs = calculate_test_diffs(tests_parent, tests_current); + if !test_diffs.is_empty() { + job_diffs.push((name.clone(), test_diffs)); + } + } + } + + // Aggregate jobs with the same diff, as often the same diff will appear in many jobs + let job_diffs: HashMap<Vec<(Test, TestOutcomeDiff)>, Vec<String>> = + job_diffs.into_iter().fold(HashMap::new(), |mut acc, (job, diffs)| { + acc.entry(diffs).or_default().push(job); + acc + }); + + Ok(job_diffs + .into_iter() + .map(|(test_diffs, jobs)| AggregatedTestDiffs { jobs, test_diffs }) + .collect()) +} + +fn calculate_test_diffs( + reference: TestSuiteData, + current: TestSuiteData, +) -> Vec<(Test, TestOutcomeDiff)> { + let mut diffs = vec![]; + for (test, outcome) in ¤t.tests { + match reference.tests.get(test) { + Some(before) => { + if before != outcome { + diffs.push(( + test.clone(), + TestOutcomeDiff::ChangeOutcome { + before: before.clone(), + after: outcome.clone(), + }, + )); + } + } + None => diffs.push((test.clone(), TestOutcomeDiff::Added(outcome.clone()))), + } + } + for (test, outcome) in &reference.tests { + if !current.tests.contains_key(test) { + diffs.push((test.clone(), TestOutcomeDiff::Missing { before: outcome.clone() })); + } + } + + diffs +} + +/// Represents a difference in the outcome of tests between a base and a current commit. +#[derive(Debug)] +struct AggregatedTestDiffs { + /// All jobs that had the exact same test diffs. + jobs: Vec<String>, + test_diffs: Vec<(Test, TestOutcomeDiff)>, +} + +#[derive(Eq, PartialEq, Hash, Debug)] +enum TestOutcomeDiff { + ChangeOutcome { before: TestOutcome, after: TestOutcome }, + Missing { before: TestOutcome }, + Added(TestOutcome), +} + +/// Aggregates test suite executions from all bootstrap invocations in a given CI job. +#[derive(Default)] +struct TestSuiteData { + tests: HashMap<Test, TestOutcome>, +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +struct Test { + name: String, +} + +/// Extracts all tests from the passed metrics and map them to their outcomes. +fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { + let mut tests = HashMap::new(); + let test_suites = get_test_suites(&metrics); + for suite in test_suites { + for test in &suite.tests { + let test_entry = Test { name: normalize_test_name(&test.name) }; + tests.insert(test_entry, test.outcome.clone()); + } + } + TestSuiteData { tests } +} + +/// Normalizes Windows-style path delimiters to Unix-style paths. +fn normalize_test_name(name: &str) -> String { + name.replace('\\', "/") +} + +/// Prints test changes in Markdown format to stdout. +fn report_test_changes(mut diffs: Vec<AggregatedTestDiffs>) { + println!("## Test differences"); + if diffs.is_empty() { + println!("No test diffs found"); + return; + } + + // Sort diffs in decreasing order by diff count + diffs.sort_by_key(|entry| Reverse(entry.test_diffs.len())); + + fn format_outcome(outcome: &TestOutcome) -> String { + match outcome { + TestOutcome::Passed => "pass".to_string(), + TestOutcome::Failed => "fail".to_string(), + TestOutcome::Ignored { ignore_reason } => { + let reason = match ignore_reason { + Some(reason) => format!(" ({reason})"), + None => String::new(), + }; + format!("ignore{reason}") + } + } + } + + fn format_diff(diff: &TestOutcomeDiff) -> String { + match diff { + TestOutcomeDiff::ChangeOutcome { before, after } => { + format!("{} -> {}", format_outcome(before), format_outcome(after)) + } + TestOutcomeDiff::Missing { before } => { + format!("{} -> [missing]", format_outcome(before)) + } + TestOutcomeDiff::Added(outcome) => { + format!("[missing] -> {}", format_outcome(outcome)) + } + } + } + + let max_diff_count = 10; + let max_job_count = 5; + let max_test_count = 10; + + for diff in diffs.iter().take(max_diff_count) { + let mut jobs = diff.jobs.clone(); + jobs.sort(); + + let jobs = jobs.iter().take(max_job_count).map(|j| format!("`{j}`")).collect::<Vec<_>>(); + + let extra_jobs = diff.jobs.len().saturating_sub(max_job_count); + let suffix = if extra_jobs > 0 { + format!(" (and {extra_jobs} {})", pluralize("other", extra_jobs)) + } else { + String::new() + }; + println!("- {}{suffix}", jobs.join(",")); + + let extra_tests = diff.test_diffs.len().saturating_sub(max_test_count); + for (test, outcome_diff) in diff.test_diffs.iter().take(max_test_count) { + println!(" - {}: {}", test.name, format_diff(&outcome_diff)); + } + if extra_tests > 0 { + println!(" - (and {extra_tests} additional {})", pluralize("tests", extra_tests)); + } + } + + let extra_diffs = diffs.len().saturating_sub(max_diff_count); + if extra_diffs > 0 { + println!("\n(and {extra_diffs} additional {})", pluralize("diff", extra_diffs)); + } +} + +fn pluralize(text: &str, count: usize) -> String { + if count == 1 { text.to_string() } else { format!("{text}s") } +} diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 2386413ed6b..8548602b31c 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -105,17 +105,21 @@ struct TestSuiteRecord { failed: u64, } +fn test_metadata_name(metadata: &TestSuiteMetadata) -> String { + match metadata { + TestSuiteMetadata::CargoPackage { crates, stage, .. } => { + format!("{} (stage {stage})", crates.join(", ")) + } + TestSuiteMetadata::Compiletest { suite, stage, .. } => { + format!("{suite} (stage {stage})") + } + } +} + fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> { let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new(); for suite in suites { - let name = match &suite.metadata { - TestSuiteMetadata::CargoPackage { crates, stage, .. } => { - format!("{} (stage {stage})", crates.join(", ")) - } - TestSuiteMetadata::Compiletest { suite, stage, .. } => { - format!("{suite} (stage {stage})") - } - }; + let name = test_metadata_name(&suite.metadata); let record = records.entry(name).or_default(); for test in &suite.tests { match test.outcome { @@ -134,7 +138,7 @@ fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRec records } -fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { +pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) { for node in nodes { match node { diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 6b88c26e3a2..eba55338ff8 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -591,7 +591,7 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc --host=i686-pc-windows-msvc - --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --target=i686-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 2905e470fab..a6996e39822 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -415,6 +415,10 @@ Compiletest directives like `//@ only-<target>` or `//@ ignore-<target>` are supported in `rmake.rs`, like in UI tests. However, revisions or building auxiliary via directives are not currently supported. +`rmake.rs` and `run-make-support` may *not* use any nightly/unstable features, +as they must be compilable by a stage 0 rustc that may be a beta or even stable +rustc. + #### Quickly check if `rmake.rs` tests can be compiled You can quickly check if `rmake.rs` tests can be compiled without having to diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 84440a5ab78..f78ab151b9c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -162,7 +162,6 @@ target | std | notes [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 56cb5cddeea..bacb9e09f3f 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -7,8 +7,8 @@ publish = false [dependencies] indicatif = { version = "0.17.8", default-features = false } num = "0.4.3" -rand = "0.8.5" -rand_chacha = "0.3" +rand = "0.9.0" +rand_chacha = "0.9.0" rayon = "1" [lib] diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen/fuzz.rs index 7fc999d1671..1d6c5562a14 100644 --- a/src/etc/test-float-parse/src/gen/fuzz.rs +++ b/src/etc/test-float-parse/src/gen/fuzz.rs @@ -6,7 +6,7 @@ use std::ops::Range; use std::sync::Mutex; use rand::Rng; -use rand::distributions::{Distribution, Standard}; +use rand::distr::{Distribution, StandardUniform}; use rand_chacha::ChaCha8Rng; use rand_chacha::rand_core::SeedableRng; @@ -47,7 +47,7 @@ impl<F: Float> Fuzz<F> { impl<F: Float> Generator<F> for Fuzz<F> where - Standard: Distribution<<F as Float>::Int>, + StandardUniform: Distribution<<F as Float>::Int>, { const SHORT_NAME: &'static str = "fuzz"; @@ -74,13 +74,13 @@ where impl<F: Float> Iterator for Fuzz<F> where - Standard: Distribution<<F as Float>::Int>, + StandardUniform: Distribution<<F as Float>::Int>, { type Item = <Self as Generator<F>>::WriteCtx; fn next(&mut self) -> Option<Self::Item> { let _ = self.iter.next()?; - let i: F::Int = self.rng.gen(); + let i: F::Int = self.rng.random(); Some(F::from_bits(i)) } diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen/many_digits.rs index aab8d5d704b..741e11437fe 100644 --- a/src/etc/test-float-parse/src/gen/many_digits.rs +++ b/src/etc/test-float-parse/src/gen/many_digits.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use std::marker::PhantomData; use std::ops::{Range, RangeInclusive}; -use rand::distributions::{Distribution, Uniform}; +use rand::distr::{Distribution, Uniform}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -40,7 +40,7 @@ impl<F: Float> Generator<F> for RandDigits<F> { fn new() -> Self { let rng = ChaCha8Rng::from_seed(SEED); - let range = Uniform::from(0..10); + let range = Uniform::try_from(0..10).unwrap(); Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData } } @@ -55,11 +55,11 @@ impl<F: Float> Iterator for RandDigits<F> { fn next(&mut self) -> Option<Self::Item> { let _ = self.iter.next()?; - let num_digits = self.rng.gen_range(POSSIBLE_NUM_DIGITS); - let has_decimal = self.rng.gen_bool(0.2); - let has_exp = self.rng.gen_bool(0.2); + let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS); + let has_decimal = self.rng.random_bool(0.2); + let has_exp = self.rng.random_bool(0.2); - let dec_pos = if has_decimal { Some(self.rng.gen_range(0..num_digits)) } else { None }; + let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None }; let mut s = String::with_capacity(num_digits); @@ -75,7 +75,7 @@ impl<F: Float> Iterator for RandDigits<F> { } if has_exp { - let exp = self.rng.gen_range(EXP_RANGE); + let exp = self.rng.random_range(EXP_RANGE); write!(s, "e{exp}").unwrap(); } diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs index def66398d9f..e2f84b085c6 100644 --- a/src/etc/test-float-parse/src/lib.rs +++ b/src/etc/test-float-parse/src/lib.rs @@ -10,7 +10,7 @@ use std::sync::OnceLock; use std::sync::atomic::{AtomicU64, Ordering}; use std::{fmt, time}; -use rand::distributions::{Distribution, Standard}; +use rand::distr::{Distribution, StandardUniform}; use rayon::prelude::*; use time::{Duration, Instant}; use traits::{Float, Generator, Int}; @@ -132,7 +132,7 @@ fn register_float<F: Float>(tests: &mut Vec<TestInfo>, cfg: &Config) where RangeInclusive<F::Int>: Iterator<Item = F::Int>, <F::Int as TryFrom<u128>>::Error: std::fmt::Debug, - Standard: Distribution<<F as traits::Float>::Int>, + StandardUniform: Distribution<<F as traits::Float>::Int>, { if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { // Only run exhaustive tests if there is a chance of completion. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f95ae380fa8..719f1f978fe 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -160,7 +160,6 @@ pub(crate) fn new_dcx( HumanEmitter::new(stderr_destination(color_config), fallback_bundle) .sm(source_map.map(|sm| sm as _)) .short_message(short) - .teach(unstable_opts.teach) .diagnostic_width(diagnostic_width) .track_diagnostics(unstable_opts.track_diagnostics) .theme(if let HumanReadableErrorType::Unicode = kind { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3d6e0330fff..88af9a7388c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -96,7 +96,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> .map_err(|error| format!("failed to create args file: {error:?}"))?; // We now put the common arguments into the file we created. - let mut content = vec!["--crate-type=bin".to_string()]; + let mut content = vec![]; for cfg in &options.cfgs { content.push(format!("--cfg={cfg}")); @@ -513,12 +513,18 @@ pub(crate) struct RunnableDocTest { line: usize, edition: Edition, no_run: bool, - is_multiple_tests: bool, + merged_test_code: Option<String>, } impl RunnableDocTest { - fn path_for_merged_doctest(&self) -> PathBuf { - self.test_opts.outdir.path().join(format!("doctest_{}.rs", self.edition)) + fn path_for_merged_doctest_bundle(&self) -> PathBuf { + self.test_opts.outdir.path().join(format!("doctest_bundle_{}.rs", self.edition)) + } + fn path_for_merged_doctest_runner(&self) -> PathBuf { + self.test_opts.outdir.path().join(format!("doctest_runner_{}.rs", self.edition)) + } + fn is_multiple_tests(&self) -> bool { + self.merged_test_code.is_some() } } @@ -537,91 +543,108 @@ fn run_test( let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target); let output_file = doctest.test_opts.outdir.path().join(rust_out); - let rustc_binary = rustdoc_options - .test_builder - .as_deref() - .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); - let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + // Common arguments used for compiling the doctest runner. + // On merged doctests, the compiler is invoked twice: once for the test code itself, + // and once for the runner wrapper (which needs to use `#![feature]` on stable). + let mut compiler_args = vec![]; - compiler.arg(format!("@{}", doctest.global_opts.args_file.display())); + compiler_args.push(format!("@{}", doctest.global_opts.args_file.display())); if let Some(sysroot) = &rustdoc_options.maybe_sysroot { - compiler.arg(format!("--sysroot={}", sysroot.display())); + compiler_args.push(format!("--sysroot={}", sysroot.display())); } - compiler.arg("--edition").arg(doctest.edition.to_string()); - if !doctest.is_multiple_tests { - // Setting these environment variables is unneeded if this is a merged doctest. - compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path); - compiler.env( - "UNSTABLE_RUSTDOC_TEST_LINE", - format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize), - ); - } - compiler.arg("-o").arg(&output_file); + compiler_args.extend_from_slice(&["--edition".to_owned(), doctest.edition.to_string()]); if langstr.test_harness { - compiler.arg("--test"); + compiler_args.push("--test".to_owned()); } if rustdoc_options.json_unused_externs.is_enabled() && !langstr.compile_fail { - compiler.arg("--error-format=json"); - compiler.arg("--json").arg("unused-externs"); - compiler.arg("-W").arg("unused_crate_dependencies"); - compiler.arg("-Z").arg("unstable-options"); + compiler_args.push("--error-format=json".to_owned()); + compiler_args.extend_from_slice(&["--json".to_owned(), "unused-externs".to_owned()]); + compiler_args.extend_from_slice(&["-W".to_owned(), "unused_crate_dependencies".to_owned()]); + compiler_args.extend_from_slice(&["-Z".to_owned(), "unstable-options".to_owned()]); } if doctest.no_run && !langstr.compile_fail && rustdoc_options.persist_doctests.is_none() { // FIXME: why does this code check if it *shouldn't* persist doctests // -- shouldn't it be the negation? - compiler.arg("--emit=metadata"); + compiler_args.push("--emit=metadata".to_owned()); } - compiler.arg("--target").arg(match &rustdoc_options.target { - TargetTuple::TargetTuple(s) => s, - TargetTuple::TargetJson { path_for_rustdoc, .. } => { - path_for_rustdoc.to_str().expect("target path must be valid unicode") - } - }); + compiler_args.extend_from_slice(&[ + "--target".to_owned(), + match &rustdoc_options.target { + TargetTuple::TargetTuple(s) => s.clone(), + TargetTuple::TargetJson { path_for_rustdoc, .. } => { + path_for_rustdoc.to_str().expect("target path must be valid unicode").to_owned() + } + }, + ]); if let ErrorOutputType::HumanReadable { kind, color_config } = rustdoc_options.error_format { let short = kind.short(); let unicode = kind == HumanReadableErrorType::Unicode; if short { - compiler.arg("--error-format").arg("short"); + compiler_args.extend_from_slice(&["--error-format".to_owned(), "short".to_owned()]); } if unicode { - compiler.arg("--error-format").arg("human-unicode"); + compiler_args + .extend_from_slice(&["--error-format".to_owned(), "human-unicode".to_owned()]); } match color_config { ColorConfig::Never => { - compiler.arg("--color").arg("never"); + compiler_args.extend_from_slice(&["--color".to_owned(), "never".to_owned()]); } ColorConfig::Always => { - compiler.arg("--color").arg("always"); + compiler_args.extend_from_slice(&["--color".to_owned(), "always".to_owned()]); } ColorConfig::Auto => { - compiler.arg("--color").arg(if supports_color { "always" } else { "never" }); + compiler_args.extend_from_slice(&[ + "--color".to_owned(), + if supports_color { "always" } else { "never" }.to_owned(), + ]); } } } + let rustc_binary = rustdoc_options + .test_builder + .as_deref() + .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); + let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + + compiler.args(&compiler_args); + // If this is a merged doctest, we need to write it into a file instead of using stdin // because if the size of the merged doctests is too big, it'll simply break stdin. - if doctest.is_multiple_tests { + if doctest.is_multiple_tests() { // It makes the compilation failure much faster if it is for a combined doctest. compiler.arg("--error-format=short"); - let input_file = doctest.path_for_merged_doctest(); + let input_file = doctest.path_for_merged_doctest_bundle(); if std::fs::write(&input_file, &doctest.full_test_code).is_err() { // If we cannot write this file for any reason, we leave. All combined tests will be // tested as standalone tests. return Err(TestFailure::CompileError); } - compiler.arg(input_file); if !rustdoc_options.nocapture { // If `nocapture` is disabled, then we don't display rustc's output when compiling // the merged doctests. compiler.stderr(Stdio::null()); } + // bundled tests are an rlib, loaded by a separate runner executable + compiler + .arg("--crate-type=lib") + .arg("--out-dir") + .arg(doctest.test_opts.outdir.path()) + .arg(input_file); } else { + compiler.arg("--crate-type=bin").arg("-o").arg(&output_file); + // Setting these environment variables is unneeded if this is a merged doctest. + compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path); + compiler.env( + "UNSTABLE_RUSTDOC_TEST_LINE", + format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize), + ); compiler.arg("-"); compiler.stdin(Stdio::piped()); compiler.stderr(Stdio::piped()); @@ -630,8 +653,65 @@ fn run_test( debug!("compiler invocation for doctest: {compiler:?}"); let mut child = compiler.spawn().expect("Failed to spawn rustc process"); - let output = if doctest.is_multiple_tests { + let output = if let Some(merged_test_code) = &doctest.merged_test_code { + // compile-fail tests never get merged, so this should always pass let status = child.wait().expect("Failed to wait"); + + // the actual test runner is a separate component, built with nightly-only features; + // build it now + let runner_input_file = doctest.path_for_merged_doctest_runner(); + + let mut runner_compiler = + wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + // the test runner does not contain any user-written code, so this doesn't allow + // the user to exploit nightly-only features on stable + runner_compiler.env("RUSTC_BOOTSTRAP", "1"); + runner_compiler.args(compiler_args); + runner_compiler.args(&["--crate-type=bin", "-o"]).arg(&output_file); + let mut extern_path = std::ffi::OsString::from(format!( + "--extern=doctest_bundle_{edition}=", + edition = doctest.edition + )); + for extern_str in &rustdoc_options.extern_strs { + if let Some((_cratename, path)) = extern_str.split_once('=') { + // Direct dependencies of the tests themselves are + // indirect dependencies of the test runner. + // They need to be in the library search path. + let dir = Path::new(path) + .parent() + .filter(|x| x.components().count() > 0) + .unwrap_or(Path::new(".")); + runner_compiler.arg("-L").arg(dir); + } + } + let output_bundle_file = doctest + .test_opts + .outdir + .path() + .join(format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition)); + extern_path.push(&output_bundle_file); + runner_compiler.arg(extern_path); + runner_compiler.arg(&runner_input_file); + if std::fs::write(&runner_input_file, &merged_test_code).is_err() { + // If we cannot write this file for any reason, we leave. All combined tests will be + // tested as standalone tests. + return Err(TestFailure::CompileError); + } + if !rustdoc_options.nocapture { + // If `nocapture` is disabled, then we don't display rustc's output when compiling + // the merged doctests. + runner_compiler.stderr(Stdio::null()); + } + runner_compiler.arg("--error-format=short"); + debug!("compiler invocation for doctest runner: {runner_compiler:?}"); + + let status = if !status.success() { + status + } else { + let mut child_runner = runner_compiler.spawn().expect("Failed to spawn rustc process"); + child_runner.wait().expect("Failed to wait") + }; + process::Output { status, stdout: Vec::new(), stderr: Vec::new() } } else { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); @@ -708,7 +788,7 @@ fn run_test( cmd.arg(&output_file); } else { cmd = Command::new(&output_file); - if doctest.is_multiple_tests { + if doctest.is_multiple_tests() { cmd.env("RUSTDOC_DOCTEST_BIN_PATH", &output_file); } } @@ -716,7 +796,7 @@ fn run_test( cmd.current_dir(run_directory); } - let result = if doctest.is_multiple_tests || rustdoc_options.nocapture { + let result = if doctest.is_multiple_tests() || rustdoc_options.nocapture { cmd.status().map(|status| process::Output { status, stdout: Vec::new(), @@ -1003,7 +1083,7 @@ fn doctest_run_fn( line: scraped_test.line, edition: scraped_test.edition(&rustdoc_options), no_run: scraped_test.no_run(&rustdoc_options), - is_multiple_tests: false, + merged_test_code: None, }; let res = run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs); diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 234f40c6c1a..58efa35711a 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -14,6 +14,7 @@ pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet<String>, ids: String, output: String, + output_merged_tests: String, supports_color: bool, nb_tests: usize, } @@ -24,6 +25,7 @@ impl DocTestRunner { crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), + output_merged_tests: String::new(), supports_color: true, nb_tests: 0, } @@ -55,7 +57,8 @@ impl DocTestRunner { scraped_test, ignore, self.nb_tests, - &mut self.output + &mut self.output, + &mut self.output_merged_tests, ), )); self.supports_color &= doctest.supports_color; @@ -78,9 +81,11 @@ impl DocTestRunner { " .to_string(); + let mut code_prefix = String::new(); + for crate_attr in &self.crate_attrs { - code.push_str(crate_attr); - code.push('\n'); + code_prefix.push_str(crate_attr); + code_prefix.push('\n'); } if opts.attrs.is_empty() { @@ -88,15 +93,16 @@ impl DocTestRunner { // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in // that case may cause some tests to pass when they shouldn't have. - code.push_str("#![allow(unused)]\n"); + code_prefix.push_str("#![allow(unused)]\n"); } // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. for attr in &opts.attrs { - code.push_str(&format!("#![{attr}]\n")); + code_prefix.push_str(&format!("#![{attr}]\n")); } code.push_str("extern crate test;\n"); + writeln!(code, "extern crate doctest_bundle_{edition} as doctest_bundle;").unwrap(); let test_args = test_args.iter().fold(String::new(), |mut x, arg| { write!(x, "{arg:?}.to_string(),").unwrap(); @@ -161,12 +167,12 @@ the same process\"); std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), None)) }}", nb_tests = self.nb_tests, - output = self.output, + output = self.output_merged_tests, ids = self.ids, ) .expect("failed to generate test code"); let runnable_test = RunnableDocTest { - full_test_code: code, + full_test_code: format!("{code_prefix}{code}", code = self.output), full_test_line_offset: 0, test_opts: test_options, global_opts: opts.clone(), @@ -174,7 +180,7 @@ std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), N line: 0, edition, no_run: false, - is_multiple_tests: true, + merged_test_code: Some(code), }; let ret = run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {}); @@ -189,14 +195,15 @@ fn generate_mergeable_doctest( ignore: bool, id: usize, output: &mut String, + output_merged_tests: &mut String, ) -> String { let test_id = format!("__doctest_{id}"); if ignore { // We generate nothing else. - writeln!(output, "mod {test_id} {{\n").unwrap(); + writeln!(output, "pub mod {test_id} {{}}\n").unwrap(); } else { - writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) + writeln!(output, "pub mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) .unwrap(); if doctest.has_main_fn { output.push_str(&doctest.everything_else); @@ -216,11 +223,17 @@ fn main() {returns_result} {{ ) .unwrap(); } + writeln!( + output, + "\npub fn __main_fn() -> impl std::process::Termination {{ main() }} \n}}\n" + ) + .unwrap(); } let not_running = ignore || scraped_test.langstr.no_run; writeln!( - output, + output_merged_tests, " +mod {test_id} {{ pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic}, test::StaticTestFn( @@ -242,7 +255,7 @@ test::StaticTestFn( if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{ test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id})) }} else {{ - test::assert_test_result(self::main()) + test::assert_test_result(doctest_bundle::{test_id}::__main_fn()) }} ", ) diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 82385c1c4db..4610e092cdf 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -251,7 +251,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { // If it's a "mod foo {}", we want to look to its documentation page. self.extract_info_from_hir_id(id); } - intravisit::walk_mod(self, m, id); + intravisit::walk_mod(self, m); } fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cd5ca74f8ad..dfc8f3bc7e0 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[ "bpfeb-unknown-none", "bpfel-unknown-none", "i386-apple-ios", - "i586-pc-windows-msvc", "i586-unknown-linux-gnu", "i586-unknown-linux-musl", "i586-unknown-redox", diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 8d1e893cb1a..33ba401d60c 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 39e5e140b7a..fb5d49a1004 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> { impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { if let PlaceBase::Local(id) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index b679fdfadc3..dd7a6f77acf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>( | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), + ExprKind::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => { never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) }, diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 09440c396ee..d0905733ab5 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -99,7 +99,7 @@ where }); if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { match captures.get(l) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => { return None; }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a80977459f2..f51bdc78f8a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index d5c5679c990..dc10de24bc8 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + #[allow(clippy::if_same_then_else)] fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 380cc380ad0..dc85176ebb9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { self.move_common(cmt); } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {} fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 5737a91031d..03b907ebdf4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} @@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index de9f055863c..75b18bc651e 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>( .then_some(()) .and_then(|()| none_captures.get(local_id)) }) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, Some(CaptureKind::Ref(Mutability::Not)) | None => (), } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 76b9bbbd32f..6f6683eb971 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e8..9d8c161873c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Tup({elements})"); self.slice(elements, |e| self.expr(e)); }, + ExprKind::Use(expr, _) => { + bind!(self, expr); + kind!("Use({expr})"); + self.expr(expr); + }, ExprKind::Binary(op, left, right) => { bind!(self, op, left, right); kind!("Binary({op}, {left}, {right})"); @@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }) => { let capture_clause = match capture_clause { CaptureBy::Value { .. } => "Value { .. }", + CaptureBy::Use { .. } => "Use { .. }", CaptureBy::Ref => "Ref", }; diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index aaea8d71efb..4543a20cc2c 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS ExprKind::ConstBlock(_) | ExprKind::Array(_) | ExprKind::Tup(_) + | ExprKind::Use(..) | ExprKind::Lit(_) | ExprKind::Cast(..) | ExprKind::Type(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c47c08285c2..9938e64d242 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> { && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), + (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), @@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Ret(..) | &ExprKind::Struct(..) | &ExprKind::Tup(..) + | &ExprKind::Use(..) | &ExprKind::Type(..) | &ExprKind::Unary(..) | &ExprKind::Yield(..) @@ -1053,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Tup(tup) => { self.hash_exprs(tup); }, + ExprKind::Use(expr, _) => { + self.hash_expr(expr); + }, ExprKind::Unary(lop, le) => { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index d850cc41000..d8969246844 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1129,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CaptureKind { Value, + Use, Ref(Mutability), } impl CaptureKind { @@ -1141,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind { fn bitor(self, rhs: Self) -> Self::Output { match (self, rhs) { (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value, + (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use, (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_)) | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut), (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not), @@ -1220,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { }, ExprKind::Let(let_expr) => { let mutability = match pat_capture_kind(cx, let_expr.pat) { - CaptureKind::Value => Mutability::Not, + CaptureKind::Value | CaptureKind::Use => Mutability::Not, CaptureKind::Ref(m) => m, }; return CaptureKind::Ref(mutability); @@ -1229,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { let mut mutability = Mutability::Not; for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) { match capture { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut, CaptureKind::Ref(Mutability::Not) => (), } @@ -1239,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { _ => break, }, Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, capture @ CaptureKind::Ref(_) => return capture, }, _ => break, @@ -1294,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { UpvarCapture::ByValue => CaptureKind::Value, + UpvarCapture::ByUse => CaptureKind::Use, UpvarCapture::ByRef(kind) => match kind { BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmutable | BorrowKind::Mutable => { @@ -3489,7 +3492,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { + if let DefPathData::TypeNs(Some(s)) = l { path.push(s.to_string()); } if let DefPathData::TypeNs(_) = r { @@ -3500,7 +3503,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3514,7 +3517,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // `super` chain would be too long, just use the absolute path instead once(String::from("crate")) .chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(sym) = el.data { + if let DefPathData::TypeNs(Some(sym)) = el.data { Some(sym.to_string()) } else { None diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 4a9ab17d4a6..24b4f0d9e6d 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -147,6 +147,7 @@ impl<'a> Sugg<'a> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Tup(..) + | ExprKind::Use(..) | ExprKind::Err(_) | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), @@ -217,6 +218,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) @@ -835,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 3bf518f7fe7..a079fd940c0 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -66,6 +66,8 @@ impl MutVarsDelegate { impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { self.update(cmt); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 2ac0efd7e39..63dd00f2de0 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, + ExprKind::Use(expr, _) => { + helper(typeck, true, expr, f)?; + }, ExprKind::Index(borrowed, consumed, _) | ExprKind::Assign(borrowed, consumed, _) | ExprKind::AssignOp(_, borrowed, consumed) => { diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index 885ed3b08fa..da1e74b4a56 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -15,7 +15,7 @@ impl TestCx<'_> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { self.fatal(&format!( - "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \ + "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful \ name, add a doc-comment to the start of the test explaining why it exists and \ move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR \ description ensures that the corresponding ticket is auto-closed upon merge. \ diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 8900752bd4b..073116933bd 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -105,6 +105,11 @@ impl TestCx<'_> { .expect("stage0 rustc is required to run run-make tests"); let mut rustc = Command::new(&stage0_rustc); rustc + // `rmake.rs` **must** be buildable by a stable compiler, it may not use *any* unstable + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via `RUSTC_BOOTSTRAP=-1` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. + .env("RUSTC_BOOTSTRAP", "-1") .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index e611d6e28f8..75167ab5b38 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -1,5 +1,5 @@ error: unsupported operation: `open` not available when isolation is enabled - --> RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC + --> RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC | LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled @@ -7,14 +7,14 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning = note: BACKTRACE: - = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::fs::PLATFORM::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::fs::PLATFORM::File::open_c` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::fs::PLATFORM::File::open` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 85ce38f57d6..c37cf15d40a 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -270,13 +270,13 @@ regexes! { // erase thread caller ids r"call [0-9]+" => "call ID", // erase platform module paths - "sys::pal::[a-z]+::" => "sys::pal::PLATFORM::", + r"\bsys::([a-z_]+)::[a-z]+::" => "sys::$1::PLATFORM::", // Windows file paths r"\\" => "/", // erase Rust stdlib path "[^ \n`]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths - "sys/pal/[a-z]+/" => "sys/pal/PLATFORM/", + r"\bsys/([a-z_]+)/[a-z]+\b" => "sys/$1/PLATFORM", // erase paths into the crate registry r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 15ed03ad5c2..f9beffec750 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -14,5 +14,9 @@ build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" +# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and +# reaches beta. +os_pipe = "1.2.1" + [lib] crate-type = ["lib", "dylib"] diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs index ca6ab3275c4..c0317633873 100644 --- a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs @@ -1,17 +1,15 @@ -use crate::{is_msvc, is_windows, uname}; +use crate::{is_msvc, is_win7, is_windows, uname}; /// `EXTRACFLAGS` pub fn extra_c_flags() -> Vec<&'static str> { if is_windows() { if is_msvc() { - vec![ - "ws2_32.lib", - "userenv.lib", - "advapi32.lib", - "bcrypt.lib", - "ntdll.lib", - "synchronization.lib", - ] + let mut libs = + vec!["ws2_32.lib", "userenv.lib", "bcrypt.lib", "ntdll.lib", "synchronization.lib"]; + if is_win7() { + libs.push("advapi32.lib"); + } + libs } else { vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d40ec9c4116..e0ad3ee9bed 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -40,6 +40,8 @@ pub use bstr; pub use gimli; pub use libc; pub use object; +// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta. +pub use os_pipe; pub use regex; pub use serde_json; pub use similar; @@ -82,7 +84,7 @@ pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. pub use targets::{ - apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, llvm_components_contain, + apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain, target, uname, }; diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index a16fca71d2e..86edbdf750b 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool { target().ends_with("windows-gnu") } +/// Check if target is win7. +#[must_use] +pub fn is_win7() -> bool { + target().contains("win7") +} + /// Check if target uses macOS. #[must_use] pub fn is_darwin() -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 7af31dabe45..2ac1792ba86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,16 +6,15 @@ use base_db::ra_salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - BackendRepr, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, - LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, + Float, Integer, LayoutCalculator, LayoutCalculatorError, + LayoutData, Primitive, ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; -use rustc_hashes::Hash64; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use triomphe::Arc; @@ -23,7 +22,6 @@ use crate::{ consteval::try_const_usize, db::{HirDatabase, InternedClosure}, infer::normalize, - layout::adt::struct_variant_idx, utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, }; @@ -125,10 +123,10 @@ impl<'a> LayoutCx<'a> { } } -// FIXME: move this to the `rustc_abi`. fn layout_of_simd_ty( db: &dyn HirDatabase, id: StructId, + repr_packed: bool, subst: &Substitution, env: Arc<TraitEnvironment>, dl: &TargetDataLayout, @@ -149,33 +147,10 @@ fn layout_of_simd_ty( }; let e_len = try_const_usize(db, &e_len).ok_or(LayoutError::HasErrorConst)? as u64; - - // Compute the ABI of the element type: let e_ly = db.layout_of_ty(e_ty, env)?; - let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { - return Err(LayoutError::Unknown); - }; - // Compute the size and alignment of the vector: - let size = e_ly - .size - .checked_mul(e_len, dl) - .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - let align = dl.llvmlike_vector_align(size); - let size = size.align_to(align.abi); - - Ok(Arc::new(Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() }, - backend_repr: BackendRepr::SimdVector { element: e_abi, count: e_len }, - largest_niche: e_ly.largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::ZERO, - })) + let cx = LayoutCx::new(dl); + Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) } pub fn layout_of_ty_query( @@ -190,13 +165,14 @@ pub fn layout_of_ty_query( let dl = &*target; let cx = LayoutCx::new(dl); let ty = normalize(db, trait_env.clone(), ty); - let result = match ty.kind(Interner) { + let kind = ty.kind(Interner); + let result = match kind { TyKind::Adt(AdtId(def), subst) => { if let hir_def::AdtId::StructId(s) = def { let data = db.struct_data(*s); let repr = data.repr.unwrap_or_default(); if repr.simd() { - return layout_of_simd_ty(db, *s, subst, trait_env, &target); + return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target); } }; return db.layout_of_adt(*def, subst.clone(), trait_env); @@ -216,7 +192,7 @@ pub fn layout_of_ty_query( valid_range: WrappingRange { start: 0, end: 0x10FFFF }, }, ), - chalk_ir::Scalar::Int(i) => scalar( + chalk_ir::Scalar::Int(i) => Layout::scalar(dl, scalar_unit( dl, Primitive::Int( match i { @@ -229,8 +205,8 @@ pub fn layout_of_ty_query( }, true, ), - ), - chalk_ir::Scalar::Uint(i) => scalar( + )), + chalk_ir::Scalar::Uint(i) => Layout::scalar(dl, scalar_unit( dl, Primitive::Int( match i { @@ -243,8 +219,8 @@ pub fn layout_of_ty_query( }, false, ), - ), - chalk_ir::Scalar::Float(f) => scalar( + )), + chalk_ir::Scalar::Float(f) => Layout::scalar(dl, scalar_unit( dl, Primitive::Float(match f { FloatTy::F16 => Float::F16, @@ -252,7 +228,7 @@ pub fn layout_of_ty_query( FloatTy::F64 => Float::F64, FloatTy::F128 => Float::F128, }), - ), + )), }, TyKind::Tuple(len, tys) => { let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; @@ -268,56 +244,16 @@ pub fn layout_of_ty_query( TyKind::Array(element, count) => { let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; let element = db.layout_of_ty(element.clone(), trait_env)?; - let size = element - .size - .checked_mul(count, dl) - .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - - let backend_repr = BackendRepr::Memory { sized: true }; - - let largest_niche = if count != 0 { element.largest_niche } else { None }; - let uninhabited = if count != 0 { element.uninhabited } else { false }; - - Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: element.size, count }, - backend_repr, - largest_niche, - uninhabited, - align: element.align, - size, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: Hash64::ZERO, - } + cx.calc.array_like::<_, _, ()>(&element, Some(count))? } TyKind::Slice(element) => { let element = db.layout_of_ty(element.clone(), trait_env)?; - Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: element.size, count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: element.align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: Hash64::ZERO, - } + cx.calc.array_like::<_, _, ()>(&element, None)? + } + TyKind::Str => { + let element = scalar_unit(dl, Primitive::Int(Integer::I8, false)); + cx.calc.array_like::<_, _, ()>(&Layout::scalar(dl, element), None)? } - TyKind::Str => Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - randomization_seed: Hash64::ZERO, - }, // Potentially-wide pointers. TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => { let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); @@ -355,17 +291,12 @@ pub fn layout_of_ty_query( }; // Effectively a (ptr, meta) tuple. - cx.calc.scalar_pair(data_ptr, metadata) + LayoutData::scalar_pair(dl, data_ptr, metadata) } - TyKind::FnDef(_, _) => layout_of_unit(&cx)?, - TyKind::Never => cx.calc.layout_of_never_type(), - TyKind::Dyn(_) | TyKind::Foreign(_) => { - let mut unit = layout_of_unit(&cx)?; - match &mut unit.backend_repr { - BackendRepr::Memory { sized } => *sized = false, - _ => return Err(LayoutError::Unknown), - } - unit + TyKind::Never => LayoutData::never_type(dl), + TyKind::FnDef(..) | TyKind::Dyn(_) | TyKind::Foreign(_) => { + let sized = matches!(kind, TyKind::FnDef(..)); + LayoutData::unit(dl, sized) } TyKind::Function(_) => { let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space)); @@ -434,16 +365,6 @@ pub fn layout_of_ty_recover( Err(LayoutError::RecursiveTypeWithoutIndirection) } -fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> { - cx.calc - .univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>( - IndexSlice::empty(), - &ReprOptions::default(), - StructKind::AlwaysSized, - ) - .map_err(Into::into) -} - fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { match pointee.kind(Interner) { TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => { @@ -474,9 +395,5 @@ fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) } } -fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout { - Layout::scalar(dl, scalar_unit(dl, value)) -} - #[cfg(test)] mod tests; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 0ba765bd75e..eb4729fab84 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -16,16 +16,12 @@ use triomphe::Arc; use crate::{ db::HirDatabase, lang_items::is_unsafe_cell, - layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx}, + layout::{field_ty, Layout, LayoutError}, Substitution, TraitEnvironment, }; use super::LayoutCx; -pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx { - RustcEnumVariantIdx(0) -} - pub fn layout_of_adt_query( db: &dyn HirDatabase, def: AdtId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 707c4377726..e0dcc01821e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -12,9 +12,6 @@ extern crate ra_ap_rustc_index as rustc_index; #[cfg(feature = "in-rust-tree")] extern crate rustc_abi; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_hashes; - #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_abi as rustc_abi; diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 16b7e7aa709..eff2d2e3ff4 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -137,6 +137,10 @@ pub(crate) fn format_expr( ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) } + ast::ExprKind::Use(_, _) => { + // FIXME: properly implement this + Ok(context.snippet(expr.span()).to_owned()) + } ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr), ast::ExprKind::If(..) | ast::ExprKind::ForLoop { .. } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ba4a4c045f1..fe716c18638 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -513,6 +513,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Become(..) | ast::ExprKind::Yeet(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) | ast::ExprKind::Yield(None) | ast::ExprKind::Underscore => false, diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 9a4d0891b4a..dfdbc0878f2 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -17,6 +17,7 @@ termcolor = "1.1.3" rustc-hash = "2.0.0" fluent-syntax = "0.11.1" similar = "2.5.0" +toml = "0.7.8" [features] build-metrics = ["dep:serde"] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 51e58b4e4fc..5434e708bb7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,11 +1,12 @@ //! Checks the licenses of third-party dependencies. -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::fs::{File, read_dir}; use std::io::Write; use std::path::Path; use build_helper::ci::CiEnv; +use cargo_metadata::semver::Version; use cargo_metadata::{Metadata, Package, PackageId}; #[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"] @@ -446,6 +447,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", + "wit-bindgen-rt@0.33.0", // via wasi "writeable", "yoke", "yoke-derive", @@ -803,7 +805,17 @@ fn check_permitted_dependencies( // Check that the PERMITTED_DEPENDENCIES does not have unused entries. for permitted in permitted_dependencies { - if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) { + fn compare(pkg: &Package, permitted: &str) -> bool { + if let Some((name, version)) = permitted.split_once("@") { + let Ok(version) = Version::parse(version) else { + return false; + }; + pkg.name == name && pkg.version == version + } else { + pkg.name == permitted + } + } + if !deps.iter().any(|dep_id| compare(pkg_from_id(metadata, dep_id), permitted)) { tidy_error!( bad, "could not find allowed package `{permitted}`\n\ @@ -814,14 +826,30 @@ fn check_permitted_dependencies( } // Get in a convenient form. - let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect(); + let permitted_dependencies: HashMap<_, _> = permitted_dependencies + .iter() + .map(|s| { + if let Some((name, version)) = s.split_once('@') { + (name, Version::parse(version).ok()) + } else { + (*s, None) + } + }) + .collect(); for dep in deps { let dep = pkg_from_id(metadata, dep); // If this path is in-tree, we don't require it to be explicitly permitted. - if dep.source.is_some() && !permitted_dependencies.contains(dep.name.as_str()) { - tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); - has_permitted_dep_error = true; + if dep.source.is_some() { + let is_eq = if let Some(version) = permitted_dependencies.get(dep.name.as_str()) { + if let Some(version) = version { version == &dep.version } else { true } + } else { + false + }; + if !is_eq { + tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); + has_permitted_dep_error = true; + } } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 9f6d563166e..66856f5247b 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -87,6 +87,7 @@ pub mod target_policy; pub mod target_specific_tests; pub mod tests_placement; pub mod tests_revision_unpaired_stdout_stderr; +pub mod triagebot; pub mod ui_tests; pub mod unit_tests; pub mod unknown_revision; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 1d8514ef4c9..bc3519142dd 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -144,6 +144,8 @@ fn main() { check!(x_version, &root_path, &cargo); + check!(triagebot, &root_path); + let collected = { drain_handles(&mut handles); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 205d6720718..2237eac200d 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -475,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) { && !trimmed.starts_with("//") && !file.ancestors().any(|a| { (a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists()) - || a.ends_with("library/alloc/tests") + || a.ends_with("library/alloctests") }) && filename != "tests.rs" { diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs new file mode 100644 index 00000000000..7131c16ec30 --- /dev/null +++ b/src/tools/tidy/src/triagebot.rs @@ -0,0 +1,93 @@ +//! Tidy check to ensure paths mentioned in triagebot.toml exist in the project. + +use std::path::Path; + +use toml::Value; + +pub fn check(path: &Path, bad: &mut bool) { + let triagebot_path = path.join("triagebot.toml"); + if !triagebot_path.exists() { + tidy_error!(bad, "triagebot.toml file not found"); + return; + } + + let contents = std::fs::read_to_string(&triagebot_path).unwrap(); + let config: Value = toml::from_str(&contents).unwrap(); + + // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"] + if let Some(Value::Table(mentions)) = config.get("mentions") { + for path_str in mentions.keys() { + // Remove quotes from the path + let clean_path = path_str.trim_matches('"'); + let full_path = path.join(clean_path); + + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [mentions.*] contains path '{}' which doesn't exist", + clean_path + ); + } + } + } else { + tidy_error!( + bad, + "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo." + ); + } + + // Check [assign.owners] sections, i.e. + // [assign.owners] + // "/.github/workflows" = ["infra-ci"] + if let Some(Value::Table(assign)) = config.get("assign") { + if let Some(Value::Table(owners)) = assign.get("owners") { + for path_str in owners.keys() { + // Remove quotes and leading slash from the path + let clean_path = path_str.trim_matches('"').trim_start_matches('/'); + let full_path = path.join(clean_path); + + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [assign.owners] contains path '{}' which doesn't exist", + clean_path + ); + } + } + } else { + tidy_error!( + bad, + "triagebot.toml missing [assign.owners] section, this wrong for rust-lang/rust repo." + ); + } + } + + // Verify that trigger_files in [autolabel."*"] exist in the project, i.e. + // [autolabel."A-rustdoc-search"] + // trigger_files = [ + // "src/librustdoc/html/static/js/search.js", + // "tests/rustdoc-js", + // "tests/rustdoc-js-std", + // ] + if let Some(Value::Table(autolabels)) = config.get("autolabel") { + for (label, content) in autolabels { + if let Some(trigger_files) = content.get("trigger_files").and_then(|v| v.as_array()) { + for file in trigger_files { + if let Some(file_str) = file.as_str() { + let full_path = path.join(file_str); + + // Handle both file and directory paths + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [autolabel.{}] contains trigger_files path '{}' which doesn't exist", + label, + file_str + ); + } + } + } + } + } + } +} diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs index e9ba0f9ba89..a937256a60f 100644 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly/stack-protector/stack-protector-target-support.rs @@ -3,7 +3,7 @@ // //@ add-core-stubs //@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 -//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r35 r36 r37 r38 r39 r40 r41 r42 r43 r44 +//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 //@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 //@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 //@ assembly-output: emit-asm @@ -73,9 +73,6 @@ //@ [r32] needs-llvm-components: arm //@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf //@ [r33] needs-llvm-components: arm - -//@ [r35] compile-flags: --target i586-pc-windows-msvc -//@ [r35] needs-llvm-components: x86 //@ [r36] compile-flags: --target i586-unknown-linux-gnu //@ [r36] needs-llvm-components: x86 //@ [r37] compile-flags: --target i586-unknown-linux-musl @@ -195,7 +192,6 @@ pub fn foo() { // r3: calll @__security_check_cookie // r7: callq __security_check_cookie // r13: bl __security_check_cookie - // r35: calll @__security_check_cookie // cuda doesn't support stack-smash protection // r49-NOT: __security_check_cookie diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs index f895b79ba50..de29b9af502 100644 --- a/tests/assembly/targets/targets-pe.rs +++ b/tests/assembly/targets/targets-pe.rs @@ -25,9 +25,6 @@ //@ revisions: bpfel_unknown_none //@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none //@ [bpfel_unknown_none] needs-llvm-components: bpf -//@ revisions: i586_pc_windows_msvc -//@ [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc -//@ [i586_pc_windows_msvc] needs-llvm-components: x86 //@ revisions: i686_pc_windows_gnu //@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu //@ [i686_pc_windows_gnu] needs-llvm-components: x86 diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs new file mode 100644 index 00000000000..e5978bfc761 --- /dev/null +++ b/tests/codegen/enum/enum-two-variants-match.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ min-llvm-version: 19 (for trunc nuw) +//@ only-x86_64 (because these discriminants are isize) + +#![crate_type = "lib"] + +// CHECK-LABEL: @option_match +#[no_mangle] +pub fn option_match(x: Option<i32>) -> u16 { + // CHECK: %x = alloca [8 x i8] + // CHECK: store i32 %0, ptr %x + // CHECK: %[[TAG:.+]] = load i32, ptr %x + // CHECK-SAME: !range ![[ZERO_ONE_32:[0-9]+]] + // CHECK: %[[DISCR:.+]] = zext i32 %[[TAG]] to i64 + // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1 + // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] + + // CHECK: [[TRUE]]: + // CHECK: store i16 13 + + // CHECK: [[FALSE]]: + // CHECK: store i16 42 + match x { + Some(_) => 13, + None => 42, + } +} + +// CHECK-LABEL: @result_match +#[no_mangle] +pub fn result_match(x: Result<u64, i64>) -> u16 { + // CHECK: %x = alloca [16 x i8] + // CHECK: store i64 %0, ptr %x + // CHECK: %[[DISCR:.+]] = load i64, ptr %x + // CHECK-SAME: !range ![[ZERO_ONE_64:[0-9]+]] + // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1 + // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] + + // CHECK: [[TRUE]]: + // CHECK: store i16 13 + + // CHECK: [[FALSE]]: + // CHECK: store i16 42 + match x { + Err(_) => 13, + Ok(_) => 42, + } +} + +// CHECK: ![[ZERO_ONE_32]] = !{i32 0, i32 2} +// CHECK: ![[ZERO_ONE_64]] = !{i64 0, i64 2} diff --git a/tests/codegen/intrinsics/cold_path2.rs b/tests/codegen/intrinsics/cold_path2.rs index 1e7e0478f4f..54ee473e620 100644 --- a/tests/codegen/intrinsics/cold_path2.rs +++ b/tests/codegen/intrinsics/cold_path2.rs @@ -26,7 +26,8 @@ pub fn test(x: Option<bool>) { } // CHECK-LABEL: @test( - // CHECK: br i1 %1, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %0, 2 + // CHECK: br i1 %[[IS_NONE]], label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] // CHECK: bb1: // CHECK: path_a // CHECK: bb2: diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index ff297b27065..4849b88c09c 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -10,6 +10,7 @@ use std::intrinsics::mir::*; use std::intrinsics::{transmute, transmute_unchecked}; use std::mem::MaybeUninit; +use std::num::NonZero; // FIXME(LLVM18REMOVED): `trunc nuw` doesn't exist in LLVM 18, so once we no // longer support it the optional flag checks can be changed to required. @@ -470,3 +471,27 @@ pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 { // CHECK: ret i64 %[[VAL]] transmute(x) } + +#[repr(transparent)] +struct Level1(std::num::NonZero<u32>); +#[repr(transparent)] +struct Level2(Level1); +#[repr(transparent)] +struct Level3(Level2); + +// CHECK-LABEL: @repeatedly_transparent_transmute +// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]]) +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn repeatedly_transparent_transmute(x: NonZero<u32>) -> Level3 { + // CHECK: start + // CHECK-NEXT: ret i32 %[[ARG]] + mir! { + { + let A = CastTransmute::<NonZero<u32>, Level1>(x); + let B = CastTransmute::<Level1, Level2>(A); + RET = CastTransmute::<Level2, Level3>(B); + Return() + } + } +} diff --git a/tests/codegen/issues/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs deleted file mode 100644 index afb0dc42f44..00000000000 --- a/tests/codegen/issues/auxiliary/static_dllimport_aux.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::sync::atomic::{AtomicPtr, Ordering}; - -#[inline(always)] -pub fn memrchr() { - fn detect() {} - - static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ()); - - unsafe { - let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst); - std::mem::transmute::<*mut (), fn()>(fun)() - } -} diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index 048b69d207b..7fb850ca253 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Copt-level=3 //@ revisions: host x86-64-v3 +//@ min-llvm-version: 20 // This particular CPU regressed in #131563 //@[x86-64-v3] only-x86_64 diff --git a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs index fdb8f06df80..fbea4ee8979 100644 --- a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs +++ b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs @@ -3,6 +3,11 @@ #![crate_type = "lib"] +// The bug here was that it was loading and storing the whole value. +// It's ok for it to load the discriminant, +// to preserve the UB from `unreachable_unchecked`, +// but it better only store the constant discriminant of `B`. + pub enum State { A([u8; 753]), B([u8; 753]), @@ -11,9 +16,27 @@ pub enum State { // CHECK-LABEL: @update #[no_mangle] pub unsafe fn update(s: *mut State) { - // CHECK-NEXT: start: - // CHECK-NEXT: store i8 - // CHECK-NEXT: ret + // CHECK-NOT: alloca + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} + + // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1 + // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1 + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} + + // CHECK: store i8 1, ptr %s, align 1 + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} let State::A(v) = s.read() else { std::hint::unreachable_unchecked() }; s.write(State::B(v)); } diff --git a/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs deleted file mode 100644 index 4023412f23c..00000000000 --- a/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C lto=thin -C prefer-dynamic=no -//@ only-windows -//@ aux-build:static_dllimport_aux.rs - -// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with -// dllimport because lld does not fix the symbol names for us. - -extern crate static_dllimport_aux; - -// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} = -// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr - -pub fn main() { - static_dllimport_aux::memrchr(); -} diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs index 73bdbc0e1a8..5d54444f994 100644 --- a/tests/codegen/target-feature-inline-closure.rs +++ b/tests/codegen/target-feature-inline-closure.rs @@ -12,7 +12,7 @@ use std::arch::x86_64::*; #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx")] fn with_avx(x: __m256) -> __m256 { - // CHECK: fadd + // CHECK: fadd <8 x float> let add = { #[inline(always)] |x, y| unsafe { _mm256_add_ps(x, y) } @@ -24,14 +24,10 @@ fn with_avx(x: __m256) -> __m256 { #[no_mangle] #[cfg(target_arch = "x86_64")] unsafe fn without_avx(x: __m256) -> __m256 { - // CHECK-NOT: fadd + // CHECK-NOT: fadd <8 x float> let add = { #[inline(always)] |x, y| unsafe { _mm256_add_ps(x, y) } }; add(x, x) } - -// Don't allow the above CHECK-NOT to accidentally match a commit hash in the -// compiler version. -// CHECK-LABEL: rustc version diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs index 751d7ca9311..ca15e510173 100644 --- a/tests/codegen/try_question_mark_nop.rs +++ b/tests/codegen/try_question_mark_nop.rs @@ -16,8 +16,8 @@ use std::ptr::NonNull; #[no_mangle] pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> { // CHECK: start: - // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1 - // TWENTY-NEXT: %.2 = select i1 %trunc, i32 %1, i32 undef + // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 + // TWENTY-NEXT: %.2 = select i1 %[[IS_SOME]], i32 %1, i32 undef // CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1 // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %.2, 1 @@ -32,8 +32,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> { #[no_mangle] pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> { // CHECK: start: - // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1 - // TWENTY-NEXT: %.1 = select i1 %trunc, i32 %1, i32 undef + // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 + // TWENTY-NEXT: %.1 = select i1 %[[IS_SOME]], i32 %1, i32 undef // CHECK-NEXT: insertvalue { i32, i32 } // CHECK-NEXT: insertvalue { i32, i32 } // CHECK-NEXT: ret { i32, i32 } diff --git a/tests/crashes/133426.rs b/tests/crashes/133426.rs deleted file mode 100644 index 307a94c0f6c..00000000000 --- a/tests/crashes/133426.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133426 - -fn a( - _: impl Iterator< - Item = [(); { - match *todo!() { ! }; - }], - >, -) { -} - -fn b(_: impl Iterator<Item = { match 0 { ! } }>) {} diff --git a/tests/crashes/136138.rs b/tests/crashes/136138.rs new file mode 100644 index 00000000000..c3893dc9c8e --- /dev/null +++ b/tests/crashes/136138.rs @@ -0,0 +1,7 @@ +//@ known-bug: #136138 +#![feature(min_generic_const_args)] +struct U; +struct S<const N: U>() +where + S<{ U }>:; +fn main() {} diff --git a/tests/crashes/136175-2.rs b/tests/crashes/136175-2.rs new file mode 100644 index 00000000000..28f8ff7fd1c --- /dev/null +++ b/tests/crashes/136175-2.rs @@ -0,0 +1,13 @@ +//@ known-bug: #136175 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Trait {} + +struct A<T>(T) +where + [(); std::mem::offset_of!((T,), 0)]:; + +fn main() { + let x: A<dyn Trait>; +} diff --git a/tests/crashes/136175.rs b/tests/crashes/136175.rs new file mode 100644 index 00000000000..0b5f2fdaa92 --- /dev/null +++ b/tests/crashes/136175.rs @@ -0,0 +1,13 @@ +//@ known-bug: #136175 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Trait {} + +struct A<T>(T) +where + [(); size_of::<T>()]:; + +fn main() { + let x: A<dyn Trait>; +} diff --git a/tests/crashes/136188.rs b/tests/crashes/136188.rs new file mode 100644 index 00000000000..a701fc4c0b7 --- /dev/null +++ b/tests/crashes/136188.rs @@ -0,0 +1,9 @@ +//@ known-bug: #136188 +//@ compile-flags: --crate-type=lib -Znext-solver +#![feature(type_alias_impl_trait)] + +type Opaque = Box<impl Sized>; + +fn define() -> Opaque { Box::new(()) } + +impl Copy for Opaque {} diff --git a/tests/crashes/136286.rs b/tests/crashes/136286.rs new file mode 100644 index 00000000000..f0ea14bd167 --- /dev/null +++ b/tests/crashes/136286.rs @@ -0,0 +1,7 @@ +//@ known-bug: #136286 +//@ compile-flags: --edition=2024 + +#![feature(async_fn_in_dyn_trait)] +trait A { + async fn b(self: A); +} diff --git a/tests/crashes/136379.rs b/tests/crashes/136379.rs new file mode 100644 index 00000000000..077b373e3b5 --- /dev/null +++ b/tests/crashes/136379.rs @@ -0,0 +1,11 @@ +//@ known-bug: #136379 +#![feature(min_generic_const_args)] +pub struct S(); + +impl S { + pub fn f() -> [u8; S] { + [] + } +} + +pub fn main() {} diff --git a/tests/crashes/136381.rs b/tests/crashes/136381.rs new file mode 100644 index 00000000000..13ccc14a2c5 --- /dev/null +++ b/tests/crashes/136381.rs @@ -0,0 +1,18 @@ +//@ known-bug: #136381 +//@ compile-flags: -Zvalidate-mir -Zmir-enable-passes=+GVN +#![feature(trait_upcasting)] + +trait A {} +trait B: A { + fn c(&self); +} +impl B for i32 { + fn c(self) { + todo!(); + } +} + +fn main() { + let baz: &dyn B = &1; + let bar: &dyn A = baz; +} diff --git a/tests/crashes/136416.rs b/tests/crashes/136416.rs new file mode 100644 index 00000000000..b233422af86 --- /dev/null +++ b/tests/crashes/136416.rs @@ -0,0 +1,6 @@ +//@ known-bug: #136416 +#![feature(generic_const_exprs)] +struct State<const S : usize = {}> where[(); S] :; + +struct Foo; +struct State2<const S: usize = Foo> where [(); S]:; diff --git a/tests/crashes/136442.rs b/tests/crashes/136442.rs new file mode 100644 index 00000000000..0436debd565 --- /dev/null +++ b/tests/crashes/136442.rs @@ -0,0 +1,9 @@ +//@ known-bug: #136442 +//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+Inline -Zmir-enable-passes=+JumpThreading --crate-type lib +pub fn problem_thingy(items: &mut impl Iterator<Item = str>) { + let mut peeker = items.peekable(); + match peeker.peek() { + Some(_) => (), + None => return (), + } +} diff --git a/tests/crashes/136661.rs b/tests/crashes/136661.rs new file mode 100644 index 00000000000..76161a566f4 --- /dev/null +++ b/tests/crashes/136661.rs @@ -0,0 +1,25 @@ +//@ known-bug: #136661 + +#![allow(unused)] + +trait Supertrait<T> {} + +trait Other { + fn method(&self) {} +} + +impl WithAssoc for &'static () { + type As = (); +} + +trait WithAssoc { + type As; +} + +trait Trait<P: WithAssoc>: Supertrait<P::As> { + fn method(&self) {} +} + +fn hrtb<T: for<'a> Trait<&'a ()>>() {} + +pub fn main() {} diff --git a/tests/crashes/136666.rs b/tests/crashes/136666.rs new file mode 100644 index 00000000000..5cfed65fdf9 --- /dev/null +++ b/tests/crashes/136666.rs @@ -0,0 +1,36 @@ +//@ known-bug: #136666 +// Needed so that rust can infer that the A in what() is &() +trait IsRef<T> {} +struct Dummy; +impl<'a> IsRef<&'a ()> for Dummy {} + +trait WithLifetime { + type Output<'a>; +} +impl<'t> WithLifetime for &'t () { + type Output<'a> = &'a (); +} + +// Needed to prevent the two Foo impls from overlapping +struct Wrap<A>(A); + +trait Unimplemented {} + +trait Foo {} +impl<T> Foo for T where T: Unimplemented {} +impl<A> Foo for Wrap<A> +where + Dummy: IsRef<A>, + for<'a> A: WithLifetime<Output<'a> = A>, +{ +} + +fn what<A>() +where + Wrap<A>: Foo, +{ +} + +fn main() { + what(); +} diff --git a/tests/crashes/136678.rs b/tests/crashes/136678.rs new file mode 100644 index 00000000000..e7d7de23bfe --- /dev/null +++ b/tests/crashes/136678.rs @@ -0,0 +1,18 @@ +//@ known-bug: #136678 +#![feature(inherent_associated_types)] +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct B<const A: usize>; + +struct Test<const A: usize>; + +impl<const A: usize> Test<A> { + type B = B<{ A }>; + + fn test(a: Self::B) -> Self::B { + a + } +} + +pub fn main() {} diff --git a/tests/crashes/136766.rs b/tests/crashes/136766.rs new file mode 100644 index 00000000000..01fa07a05ae --- /dev/null +++ b/tests/crashes/136766.rs @@ -0,0 +1,6 @@ +//@ known-bug: #136766 +#![feature(generic_const_exprs)] +trait A<const B: bool>{} +impl A<true> for () {} +fn c<const D: usize>(E: [u8; D * D]) where() : A<D>{} +fn main() { c } diff --git a/tests/crashes/136859.rs b/tests/crashes/136859.rs new file mode 100644 index 00000000000..2c926eea5e2 --- /dev/null +++ b/tests/crashes/136859.rs @@ -0,0 +1,27 @@ +//@ known-bug: #136859 +#![feature(generic_const_exprs)] + +trait If<const COND: bool> {} +impl If<true> for () {} + +trait IsZero<const N: u8> { + type Answer; +} + +struct True; +struct False; + +impl<const N: u8> IsZero<N> for () +where (): If<{N == 0}> { + type Msg = True; +} + +trait Foobar<const N: u8> {} + +impl<const N: u8> Foobar<N> for () +where (): IsZero<N, Answer = True> {} + +impl<const N: u8> Foobar<{{ N }}> for () +where (): IsZero<N, Answer = False> {} + +fn main() {} diff --git a/tests/crashes/136894.rs b/tests/crashes/136894.rs new file mode 100644 index 00000000000..26bbb78717e --- /dev/null +++ b/tests/crashes/136894.rs @@ -0,0 +1,8 @@ +//@ known-bug: #136894 +#![feature(generic_const_exprs)] +#![crate_type = "lib"] +#![allow(incomplete_features, dead_code)] + +struct X<T>([(); f::<T>()]) where [(); f::<T>()]:; + +const fn f<T>() -> usize { panic!() } diff --git a/tests/crashes/137049.rs b/tests/crashes/137049.rs new file mode 100644 index 00000000000..a7132e4fa17 --- /dev/null +++ b/tests/crashes/137049.rs @@ -0,0 +1,29 @@ +//@ known-bug: #137049 +//@ compile-flags: --crate-type=lib +#![feature(type_alias_impl_trait)] + +use std::marker::PhantomData; + +trait Project1 { + type Assoc1; +} + +impl<T> Project1 for T { + type Assoc1 = (); +} + +trait Project2 { + type Assoc2; +} + +impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> { + type Assoc2 = (); +} + +type Alias<T> = impl Project2; + +fn constrain<T>() -> Alias<T> { + PhantomData::<T> +} + +struct AdtConstructor<T: Project1>(<Alias<T> as Project2>::Assoc2); diff --git a/tests/crashes/137084.rs b/tests/crashes/137084.rs new file mode 100644 index 00000000000..0f248c21206 --- /dev/null +++ b/tests/crashes/137084.rs @@ -0,0 +1,6 @@ +//@ known-bug: #137084 +#![feature(min_generic_const_args)] +fn a<const b: i32>() {} +fn d(e: &String) { + a::<d> +} diff --git a/tests/crashes/137187.rs b/tests/crashes/137187.rs new file mode 100644 index 00000000000..05cfb2b10e1 --- /dev/null +++ b/tests/crashes/137187.rs @@ -0,0 +1,9 @@ +//@ known-bug: #137187 +use std::ops::Add; +trait A where + *const Self: Add, +{ + const fn b(c: *const Self) -> <*const Self as Add>::Output { + c + c + } +} diff --git a/tests/crashes/137188.rs b/tests/crashes/137188.rs new file mode 100644 index 00000000000..fdd098d300f --- /dev/null +++ b/tests/crashes/137188.rs @@ -0,0 +1,6 @@ +//@ known-bug: #137188 +#![feature(min_generic_const_args)] +trait Trait {} +impl Trait for [(); N] {} +fn N<T>() {} +pub fn main() {} diff --git a/tests/crashes/137190-1.rs b/tests/crashes/137190-1.rs new file mode 100644 index 00000000000..bdfe883b712 --- /dev/null +++ b/tests/crashes/137190-1.rs @@ -0,0 +1,10 @@ +//@ known-bug: #137190 +//@ compile-flags: -Zmir-opt-level=2 -Zvalidate-mir +trait A { + fn b(&self); +} +trait C: A {} +impl C for () {} +fn main() { + (&() as &dyn C as &dyn A).b(); +} diff --git a/tests/crashes/137190-2.rs b/tests/crashes/137190-2.rs new file mode 100644 index 00000000000..0c68b5aa4a5 --- /dev/null +++ b/tests/crashes/137190-2.rs @@ -0,0 +1,18 @@ +//@ known-bug: #137190 +trait Supertrait<T> { + fn method(&self) {} +} + +trait Trait<P>: Supertrait<()> {} + +impl<P> Trait<P> for () {} + +const fn upcast<P>(x: &dyn Trait<P>) -> &dyn Supertrait<()> { + x +} + +const fn foo() -> &'static dyn Supertrait<()> { + upcast::<()>(&()) +} + +const _: &'static dyn Supertrait<()> = foo(); diff --git a/tests/crashes/137190-3.rs b/tests/crashes/137190-3.rs new file mode 100644 index 00000000000..88ae88e11bc --- /dev/null +++ b/tests/crashes/137190-3.rs @@ -0,0 +1,10 @@ +//@ known-bug: #137190 +trait Supertrait { + fn method(&self) {} +} + +trait Trait: Supertrait {} + +impl Trait for () {} + +const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait; diff --git a/tests/crashes/137260.rs b/tests/crashes/137260.rs new file mode 100644 index 00000000000..f1fa8a660dc --- /dev/null +++ b/tests/crashes/137260.rs @@ -0,0 +1,11 @@ +//@ known-bug: #137260 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Iter<const N: usize = { 1 + true }> {} + +fn needs_iter<const N: usize, T: Iter<N>>() {} + +fn test() { + needs_iter::<1, dyn Iter<()>>(); +} diff --git a/tests/crashes/137287.rs b/tests/crashes/137287.rs new file mode 100644 index 00000000000..59fdf568d36 --- /dev/null +++ b/tests/crashes/137287.rs @@ -0,0 +1,29 @@ +//@ known-bug: #137287 + +mod defining_scope { + use super::*; + pub type Alias<T> = impl Sized; + + pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> { + x + } +} + +struct Container<T: Trait<U>, U> { + x: <T as Trait<U>>::Assoc, +} + +trait Trait<T> { + type Assoc; +} + +impl<T> Trait<T> for T { + type Assoc = Box<u32>; +} +impl<T> Trait<T> for defining_scope::Alias<T> { + type Assoc = usize; +} + +fn main() { + let x: Box<u32> = defining_scope::cast::<()>(Container { x: 0 }).x; +} diff --git a/tests/crashes/137467-1.rs b/tests/crashes/137467-1.rs new file mode 100644 index 00000000000..1d62cba59a7 --- /dev/null +++ b/tests/crashes/137467-1.rs @@ -0,0 +1,17 @@ +//@ known-bug: #137467 +//@ compile-flags: --edition=2021 +enum Camera { + Normal { base_transform: i32 }, + Volume { transform: i32 }, +} + +fn draw_ui(camera: &mut Camera) { + || { + let (Camera::Normal { + base_transform: _transform, + } + | Camera::Volume { + transform: _transform, + }) = camera; + }; +} diff --git a/tests/crashes/137467-2.rs b/tests/crashes/137467-2.rs new file mode 100644 index 00000000000..151d6a0767f --- /dev/null +++ b/tests/crashes/137467-2.rs @@ -0,0 +1,18 @@ +//@ known-bug: #137467 +//@ compile-flags: --edition=2021 + +enum Camera { + Normal { base_transform: i32 }, + Volume { transform: i32 }, +} + +fn draw_ui(camera: &mut Camera) { + || { + let (Camera::Normal { + base_transform: _, + } + | Camera::Volume { + transform: _, + }) = camera; + }; +} diff --git a/tests/crashes/137467-3.rs b/tests/crashes/137467-3.rs new file mode 100644 index 00000000000..2140fe044a7 --- /dev/null +++ b/tests/crashes/137467-3.rs @@ -0,0 +1,8 @@ +//@ known-bug: #137467 +//@ compile-flags: --edition=2021 + +fn meow(x: (u32, u32, u32)) { + let f = || { + let ((0, a, _) | (_, _, a)) = x; + }; +} diff --git a/tests/crashes/137468.rs b/tests/crashes/137468.rs new file mode 100644 index 00000000000..cceb0502bd2 --- /dev/null +++ b/tests/crashes/137468.rs @@ -0,0 +1,16 @@ +//@ known-bug: #137468 +//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+GVN -Zvalidate-mir +trait Supertrait<T> {} + +trait Identity { + type Selff; +} + +trait Trait<P>: Supertrait<()> + Supertrait<<P as Identity>::Selff> {} + +impl<P> Trait<P> for () {} + +fn main() { + let x: &dyn Trait<()> = &(); + let x: &dyn Supertrait<()> = x; +} diff --git a/tests/crashes/137514.rs b/tests/crashes/137514.rs new file mode 100644 index 00000000000..7ae5f29e36e --- /dev/null +++ b/tests/crashes/137514.rs @@ -0,0 +1,9 @@ +//@ known-bug: #137514 +//@ needs-rustc-debug-assertions +#![feature(generic_const_exprs)] + +trait Bar<const N: usize> {} + +trait BB = Bar<{ 1i32 + 1 }>; + +fn foo(x: &dyn BB) {} diff --git a/tests/crashes/137580.rs b/tests/crashes/137580.rs new file mode 100644 index 00000000000..246c80ef556 --- /dev/null +++ b/tests/crashes/137580.rs @@ -0,0 +1,4 @@ +//@ known-bug: #137580 +fn main() { + println!("%65536$", 1); +} diff --git a/tests/crashes/137582.rs b/tests/crashes/137582.rs new file mode 100644 index 00000000000..e21b6c9578b --- /dev/null +++ b/tests/crashes/137582.rs @@ -0,0 +1,16 @@ +//@ known-bug: #137582 +#![feature(adt_const_params)] + +mod lib { + pub type Matrix = [&'static u32]; + + const EMPTY_MATRIX: Matrix = [[0; 4]; 4]; + + pub struct Walk<const CURRENT: usize, const REMAINING: Matrix> { + _p: (), + } + + impl<const CURRENT: usize> Walk<CURRENT, EMPTY_MATRIX> {} +} + +fn main() {} diff --git a/tests/crashes/137706.rs b/tests/crashes/137706.rs new file mode 100644 index 00000000000..0b46f9c237a --- /dev/null +++ b/tests/crashes/137706.rs @@ -0,0 +1,7 @@ +//@ known-bug: #137706 +//@ needs-rustc-debug-assertions +trait A { + fn b() -> impl IntoIterator<Item = ()>; +} + +impl A<()> for dyn A {} diff --git a/tests/crashes/137751.rs b/tests/crashes/137751.rs new file mode 100644 index 00000000000..85ae3acd53d --- /dev/null +++ b/tests/crashes/137751.rs @@ -0,0 +1,6 @@ +//@ known-bug: #137751 +//@ compile-flags: --edition=2021 -Znext-solver=globally +async fn test() { + Box::pin(test()).await; +} +fn main() {} diff --git a/tests/crashes/137813.rs b/tests/crashes/137813.rs new file mode 100644 index 00000000000..5d205ee5331 --- /dev/null +++ b/tests/crashes/137813.rs @@ -0,0 +1,18 @@ +//@ known-bug: #137813 +trait AssocConst { + const A: u8; +} + +impl<T> AssocConst for (T,) { + const A: u8 = 0; +} + +trait Trait {} + +impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {} + +fn foo() +where + (): Trait, +{ +} diff --git a/tests/crashes/137865.rs b/tests/crashes/137865.rs new file mode 100644 index 00000000000..7ecd8c734d3 --- /dev/null +++ b/tests/crashes/137865.rs @@ -0,0 +1,5 @@ +//@ known-bug: #137865 +trait Foo { + type Assoc<const N: Self>; + fn foo() -> Self::Assoc<3>; +} diff --git a/tests/crashes/137874.rs b/tests/crashes/137874.rs new file mode 100644 index 00000000000..44718809024 --- /dev/null +++ b/tests/crashes/137874.rs @@ -0,0 +1,4 @@ +//@ known-bug: #137874 +fn a() { + match b { deref !(0c) }; +} diff --git a/tests/crashes/137888.rs b/tests/crashes/137888.rs new file mode 100644 index 00000000000..6c13ae5fa91 --- /dev/null +++ b/tests/crashes/137888.rs @@ -0,0 +1,11 @@ +//@ known-bug: #137888 +#![feature(generic_const_exprs)] +macro_rules! empty { + () => (); +} +fn bar<const N: i32>() -> [(); { + empty! {}; + N + }] { +} +fn main() {} diff --git a/tests/crashes/137895.rs b/tests/crashes/137895.rs new file mode 100644 index 00000000000..bb624d2e9fa --- /dev/null +++ b/tests/crashes/137895.rs @@ -0,0 +1,6 @@ +//@ known-bug: #137895 +trait A { + fn b() -> impl ?Sized + 'a; +} + +impl A for dyn A {} diff --git a/tests/crashes/137916.rs b/tests/crashes/137916.rs new file mode 100644 index 00000000000..3d6b0e0fbab --- /dev/null +++ b/tests/crashes/137916.rs @@ -0,0 +1,13 @@ +//@ known-bug: #137916 +//@ compile-flags: --edition=2021 +use std::ptr::null; + +async fn a() -> Box<dyn Send> { + Box::new(async { + let non_send = null::<()>(); + &non_send; + async {}.await + }) +} + +fn main() {} diff --git a/tests/crashes/138008.rs b/tests/crashes/138008.rs new file mode 100644 index 00000000000..4645b8c9d56 --- /dev/null +++ b/tests/crashes/138008.rs @@ -0,0 +1,8 @@ +//@ known-bug: #138008 +//@compile-flags: --crate-type=lib -Copt-level=0 +#![feature(repr_simd)] +const C: usize = 16; + +#[repr(simd)] +pub struct Foo([u8; C]); +pub unsafe fn foo(a: Foo) {} diff --git a/tests/crashes/138009.rs b/tests/crashes/138009.rs new file mode 100644 index 00000000000..a1b890823e7 --- /dev/null +++ b/tests/crashes/138009.rs @@ -0,0 +1,6 @@ +//@ known-bug: #138009 +#![feature(min_generic_const_args)] +#[repr(simd)] +struct T([isize; N]); + +static X: T = T(); diff --git a/tests/crashes/138048.rs b/tests/crashes/138048.rs new file mode 100644 index 00000000000..fd59f46c752 --- /dev/null +++ b/tests/crashes/138048.rs @@ -0,0 +1,8 @@ +//@ known-bug: #138048 +struct Foo; + +impl<'b> Foo { + fn bar<const V: u8>() { + let V; + } +} diff --git a/tests/crashes/138088.rs b/tests/crashes/138088.rs new file mode 100644 index 00000000000..25496d804fe --- /dev/null +++ b/tests/crashes/138088.rs @@ -0,0 +1,5 @@ +//@ known-bug: #138088 +#![feature(min_generic_const_args)] +trait Bar { + fn x(&self) -> [i32; Bar::x]; +} diff --git a/tests/crashes/138089.rs b/tests/crashes/138089.rs new file mode 100644 index 00000000000..acf27072bdd --- /dev/null +++ b/tests/crashes/138089.rs @@ -0,0 +1,13 @@ +//@ known-bug: #138089 +#![feature(generic_const_exprs)] +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct OnDiskDirEntry<'a> {} + +impl<'a> OnDiskDirEntry<'a> { + const LFN_FRAGMENT_LEN: i64 = 2; + + fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] { + loop {} + } +} diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs new file mode 100644 index 00000000000..f400c02de8d --- /dev/null +++ b/tests/crashes/138131.rs @@ -0,0 +1,12 @@ +//@ known-bug: #138131 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct Foo<'a> { + x: &'a (), +} + +impl<'a> Foo<'a> { + fn foo(_: [u8; Foo::X]) {} +} + +fn main() {} diff --git a/tests/crashes/138132.rs b/tests/crashes/138132.rs new file mode 100644 index 00000000000..3e31117c526 --- /dev/null +++ b/tests/crashes/138132.rs @@ -0,0 +1,10 @@ +//@ known-bug: #138132 +#![feature(min_generic_const_args)] +struct b(Box<[u8; c]>); +impl b { + fn d(self) { + self.0.e() + } +} +struct c<'a>(&'a u8); +fn main() {} diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs new file mode 100644 index 00000000000..98003bd6dae --- /dev/null +++ b/tests/crashes/138166.rs @@ -0,0 +1,8 @@ +//@ known-bug: #138166 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct a(Box<[u8; Box::b]>); +impl a { + fn c(self) { self.0.d() } +} +fn main() {} diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs index 54d13b62f4a..3e54b576fd4 100644 --- a/tests/run-make/broken-pipe-no-ice/rmake.rs +++ b/tests/run-make/broken-pipe-no-ice/rmake.rs @@ -11,12 +11,12 @@ // Internal Compiler Error strangely, but it doesn't even go through normal diagnostic infra. Very // strange. -#![feature(anonymous_pipe)] - use std::io::Read; use std::process::{Command, Stdio}; -use run_make_support::env_var; +// FIXME(#137532): replace `os_pipe` dependency with std `anonymous_pipe` once that stabilizes and +// reaches beta. +use run_make_support::{env_var, os_pipe}; #[derive(Debug, PartialEq)] enum Binary { @@ -25,7 +25,7 @@ enum Binary { } fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { - let (reader, writer) = std::io::pipe().unwrap(); + let (reader, writer) = os_pipe::pipe().unwrap(); drop(reader); // close read-end cmd.stdout(writer).stderr(Stdio::piped()); diff --git a/tests/run-make/cross-lang-lto/rmake.rs b/tests/run-make/cross-lang-lto/rmake.rs index dc376b561e4..50d37460d8d 100644 --- a/tests/run-make/cross-lang-lto/rmake.rs +++ b/tests/run-make/cross-lang-lto/rmake.rs @@ -3,8 +3,6 @@ // -Clinker-plugin-lto. // See https://github.com/rust-lang/rust/pull/50000 -#![feature(path_file_prefix)] - use std::path::PathBuf; use run_make_support::{ @@ -92,10 +90,17 @@ fn check_bitcode(instructions: LibBuild) { llvm_ar().extract().arg(&instructions.output).run(); } - for object in shallow_find_files(cwd(), |path| { - has_prefix(path, instructions.output.file_prefix().unwrap().to_str().unwrap()) + let objects = shallow_find_files(cwd(), |path| { + let mut output_path = instructions.output.clone(); + output_path.set_extension(""); + has_prefix(path, output_path.file_name().unwrap().to_str().unwrap()) && has_extension(path, "o") - }) { + }); + assert!(!objects.is_empty()); + println!("objects: {:#?}", objects); + + for object in objects { + println!("reading bitcode: {}", object.display()); // All generated object files should be LLVM bitcode files - this will fail otherwise. llvm_bcanalyzer().input(object).run(); } diff --git a/tests/run-make/doctests-merge/rmake.rs b/tests/run-make/doctests-merge/rmake.rs index a25da7403e2..a88b050c50f 100644 --- a/tests/run-make/doctests-merge/rmake.rs +++ b/tests/run-make/doctests-merge/rmake.rs @@ -8,7 +8,6 @@ fn test_and_compare(input_file: &str, stdout_file: &str, edition: &str, dep: &Pa let output = cmd .input(input_file) .arg("--test") - .arg("-Zunstable-options") .edition(edition) .arg("--test-args=--test-threads=1") .extern_("foo", dep.display().to_string()) diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index f210b7c737b..228cfb0864e 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -1,12 +1,9 @@ -#![feature(rustc_private)] - -#[cfg(unix)] -extern crate libc; - #[cfg(unix)] use std::os::unix::fs::PermissionsExt; use std::path::Path; +#[cfg(unix)] +use run_make_support::libc; use run_make_support::{aux_build, rfs}; fn main() { diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 15eb186717f..8227c51516f 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -87,14 +87,15 @@ fn main() { while let Some((_, entry)) = cursor.next_dfs().unwrap() { match entry.tag() { gimli::constants::DW_TAG_variant if !is_old_llvm => { - let value = match entry - .attr(gimli::constants::DW_AT_discr_value) - .unwrap() - .unwrap() - .value() - { + let Some(value) = entry.attr(gimli::constants::DW_AT_discr_value).unwrap() + else { + // `std` enums might have variants without `DW_AT_discr_value`. + continue; + }; + let value = match value.value() { AttributeValue::Block(value) => value.to_slice().unwrap().to_vec(), - value => panic!("unexpected DW_AT_discr_value of {value:?}"), + // `std` has non-repr128 enums which don't use `AttributeValue::Block`. + value => continue, }; // The `DW_TAG_member` that is a child of `DW_TAG_variant` will contain the // variant's name. diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs new file mode 100644 index 00000000000..badf124bdde --- /dev/null +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +#[export_name = "altered"] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs new file mode 100644 index 00000000000..c5bb9dcc8f6 --- /dev/null +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +#![no_std] + +// The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 +// is still `#[export_name = ..]` without the `unsafe` attribute wrapper. + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +#[unsafe(export_name = "altered")] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs new file mode 100644 index 00000000000..dca73abc76a --- /dev/null +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -0,0 +1,9 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[must_use]"]' +#[must_use] +pub fn example() -> impl Iterator<Item = i64> {} + +//@ is "$.index[*][?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +#[must_use = "does nothing if you do not use it"] +pub fn explicit_message() -> impl Iterator<Item = i64> {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs new file mode 100644 index 00000000000..258542086ec --- /dev/null +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +#[no_mangle] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs new file mode 100644 index 00000000000..4c01082d045 --- /dev/null +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +#![no_std] + +// The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 +// is still `#[no_mangle]` without the `unsafe` attribute wrapper. + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +#[unsafe(no_mangle)] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs new file mode 100644 index 00000000000..5d738fc0560 --- /dev/null +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -0,0 +1,19 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +#[non_exhaustive] +pub enum MyEnum { + First, +} + +pub enum NonExhaustiveVariant { + //@ is "$.index[*][?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + #[non_exhaustive] + Variant(i64), +} + +//@ is "$.index[*][?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +#[non_exhaustive] +pub struct MyStruct { + pub x: i64, +} diff --git a/tests/rustdoc-ui/diagnostic-width.stderr b/tests/rustdoc-ui/diagnostic-width.stderr index d8c4934a576..94fc2343faf 100644 --- a/tests/rustdoc-ui/diagnostic-width.stderr +++ b/tests/rustdoc-ui/diagnostic-width.stderr @@ -8,8 +8,8 @@ LL | ... a http://link.com note: the lint level is defined here --> $DIR/diagnostic-width.rs:2:9 | -LL | ...ny(rustdoc::bare_url... - | ^^^^^^^^^^^^^^^^^^ +LL | ...ny(ru...are_urls)] + | ^^...^^^^^^^^ help: use an automatic link instead | LL | /// This is a long line that contains a <http://link.com> diff --git a/tests/rustdoc-ui/doctest/doctest-output.rs b/tests/rustdoc-ui/doctest/doctest-output.rs index fb4ab068000..04bd1813b4c 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.rs +++ b/tests/rustdoc-ui/doctest/doctest-output.rs @@ -2,7 +2,7 @@ //@[edition2015]edition:2015 //@[edition2015]aux-build:extern_macros.rs //@[edition2015]compile-flags:--test --test-args=--test-threads=1 -//@[edition2024]edition:2015 +//@[edition2024]edition:2024 //@[edition2024]aux-build:extern_macros.rs //@[edition2024]compile-flags:--test --test-args=--test-threads=1 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout new file mode 100644 index 00000000000..ce767fb8443 --- /dev/null +++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout @@ -0,0 +1,28 @@ + +running 1 test +test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED + +failures: + +---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ---- +error[E0432]: unresolved import `test` + --> $DIR/failed-doctest-test-crate.rs:15:5 + | +LL | use test::*; + | ^^^^ use of unresolved module or unlinked crate `test` + | +help: you might be missing a crate named `test`, add it to your project and import it in your code + | +LL + extern crate test; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. +Couldn't compile the test. + +failures: + $DIR/failed-doctest-test-crate.rs - m (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout new file mode 100644 index 00000000000..80642e93bbd --- /dev/null +++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout @@ -0,0 +1,25 @@ + +running 1 test +test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED + +failures: + +---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ---- +error[E0432]: unresolved import `test` + --> $DIR/failed-doctest-test-crate.rs:15:5 + | +LL | use test::*; + | ^^^^ use of unresolved module or unlinked crate `test` + | + = help: you might be missing a crate named `test` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. +Couldn't compile the test. + +failures: + $DIR/failed-doctest-test-crate.rs - m (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs new file mode 100644 index 00000000000..6966d3df11c --- /dev/null +++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs @@ -0,0 +1,17 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ revisions: edition2015 edition2024 +//@[edition2015]edition:2015 +//@[edition2024]edition:2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +/// <https://github.com/rust-lang/rust/pull/137899#discussion_r1976743383> +/// +/// ```rust +/// use test::*; +/// ``` +pub mod m {} diff --git a/tests/ui-fulldeps/hash-stable-is-unstable.rs b/tests/ui-fulldeps/hash-stable-is-unstable.rs index dc778695287..a4b8533eb04 100644 --- a/tests/ui-fulldeps/hash-stable-is-unstable.rs +++ b/tests/ui-fulldeps/hash-stable-is-unstable.rs @@ -1,4 +1,3 @@ -//@ ignore-stage1 FIXME: this line can be removed once these new error messages are in stage 0 rustc //@ compile-flags: -Zdeduplicate-diagnostics=yes extern crate rustc_data_structures; //~^ use of unstable library feature `rustc_private` diff --git a/tests/ui-fulldeps/hash-stable-is-unstable.stderr b/tests/ui-fulldeps/hash-stable-is-unstable.stderr index 8d809175875..e7740d744b4 100644 --- a/tests/ui-fulldeps/hash-stable-is-unstable.stderr +++ b/tests/ui-fulldeps/hash-stable-is-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/hash-stable-is-unstable.rs:3:1 + --> $DIR/hash-stable-is-unstable.rs:2:1 | LL | extern crate rustc_data_structures; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | extern crate rustc_data_structures; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/hash-stable-is-unstable.rs:7:1 + --> $DIR/hash-stable-is-unstable.rs:6:1 | LL | extern crate rustc_macros; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | extern crate rustc_macros; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/hash-stable-is-unstable.rs:11:1 + --> $DIR/hash-stable-is-unstable.rs:10:1 | LL | extern crate rustc_query_system; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | extern crate rustc_query_system; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/hash-stable-is-unstable.rs:16:5 + --> $DIR/hash-stable-is-unstable.rs:15:5 | LL | use rustc_macros::HashStable; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | use rustc_macros::HashStable; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/hash-stable-is-unstable.rs:21:10 + --> $DIR/hash-stable-is-unstable.rs:20:10 | LL | #[derive(HashStable)] | ^^^^^^^^^^ diff --git a/tests/ui-fulldeps/pathless-extern-unstable.rs b/tests/ui-fulldeps/pathless-extern-unstable.rs index 27272135696..b5ba4082e9d 100644 --- a/tests/ui-fulldeps/pathless-extern-unstable.rs +++ b/tests/ui-fulldeps/pathless-extern-unstable.rs @@ -1,4 +1,3 @@ -//@ ignore-stage1 FIXME: this line can be removed once these new error messages are in stage 0 rustc //@ edition:2018 //@ compile-flags:--extern rustc_middle diff --git a/tests/ui-fulldeps/pathless-extern-unstable.stderr b/tests/ui-fulldeps/pathless-extern-unstable.stderr index a78b69f4d20..779c3773a9b 100644 --- a/tests/ui-fulldeps/pathless-extern-unstable.stderr +++ b/tests/ui-fulldeps/pathless-extern-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/pathless-extern-unstable.rs:7:9 + --> $DIR/pathless-extern-unstable.rs:6:9 | LL | pub use rustc_middle; | ^^^^^^^^^^^^ diff --git a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs new file mode 100644 index 00000000000..b7636d116ec --- /dev/null +++ b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs @@ -0,0 +1,26 @@ +//@ revisions: emit_mir instrument cfi + +// Make sure we don't try to emit MIR for it. +//@[emit_mir] compile-flags: --emit=mir + +// Make sure we don't try to instrument it. +//@[instrument] compile-flags: -Cinstrument-coverage -Zno-profiler-runtime +//@[instrument] only-linux + +// Make sure we don't try to CFI encode it. +//@[cfi] compile-flags: -Zsanitizer=cfi -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Clink-dead-code=true +//@[cfi] needs-sanitizer-cfi +//@[cfi] no-prefer-dynamic +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@[cfi] only-linux + +//@ build-pass +//@ needs-asm-support + +use std::arch::global_asm; + +fn foo() {} + +global_asm!("/* {} */", sym foo); + +fn main() {} diff --git a/tests/ui/asm/global-asm-with-error.rs b/tests/ui/asm/global-asm-with-error.rs new file mode 100644 index 00000000000..c2253e3cb87 --- /dev/null +++ b/tests/ui/asm/global-asm-with-error.rs @@ -0,0 +1,11 @@ +// Ensure that we don't ICE when constructing the fake MIR body for a global +// asm when the body has errors. See #137470. + +//@ needs-asm-support + +use std::arch::global_asm; + +global_asm!("/* {} */", sym a); +//~^ ERROR cannot find value `a` in this scope + +fn main() {} diff --git a/tests/ui/asm/global-asm-with-error.stderr b/tests/ui/asm/global-asm-with-error.stderr new file mode 100644 index 00000000000..3b76bfd1948 --- /dev/null +++ b/tests/ui/asm/global-asm-with-error.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `a` in this scope + --> $DIR/global-asm-with-error.rs:8:29 + | +LL | global_asm!("/* {} */", sym a); + | ^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr index 4ca6ef89819..aa22a453744 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr @@ -3,6 +3,9 @@ error[E0733]: recursion in an async fn requires boxing | LL | async fn second(self) { | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | self.first().await.second().await; + | --------------------------------- recursive call here | = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future diff --git a/tests/ui/auto-traits/ungated-impl.rs b/tests/ui/auto-traits/ungated-impl.rs new file mode 100644 index 00000000000..d46b4b01af9 --- /dev/null +++ b/tests/ui/auto-traits/ungated-impl.rs @@ -0,0 +1,7 @@ +auto trait MyTrait {} +//~^ ERROR auto traits are experimental and possibly buggy + +impl<T> !MyTrait for *mut T {} +//~^ ERROR negative trait bounds are not fully implemented + +fn main() {} diff --git a/tests/ui/auto-traits/ungated-impl.stderr b/tests/ui/auto-traits/ungated-impl.stderr new file mode 100644 index 00000000000..9d10d46a902 --- /dev/null +++ b/tests/ui/auto-traits/ungated-impl.stderr @@ -0,0 +1,23 @@ +error[E0658]: auto traits are experimental and possibly buggy + --> $DIR/ungated-impl.rs:1:1 + | +LL | auto trait MyTrait {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information + = help: add `#![feature(auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: negative trait bounds are not fully implemented; use marker types for now + --> $DIR/ungated-impl.rs:4:9 + | +LL | impl<T> !MyTrait for *mut T {} + | ^^^^^^^^ + | + = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information + = help: add `#![feature(negative_impls)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs new file mode 100644 index 00000000000..cfc0a97989d --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.rs @@ -0,0 +1,36 @@ +// Combination of `ptr-to-trait-obj-wrap.rs` and `ptr-to-trait-obj-add-auto.rs`. +// +// Checks that you *can't* add auto traits to trait object in pointer casts involving wrapping said +// traits structures. + +trait A {} + +struct W<T: ?Sized>(T); +struct X<T: ?Sized>(T); + +fn unwrap(a: *const W<dyn A>) -> *const (dyn A + Send) { + a as _ + //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast +} + +fn unwrap_nested(a: *const W<W<dyn A>>) -> *const W<dyn A + Send> { + a as _ + //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast +} + +fn rewrap(a: *const W<dyn A>) -> *const X<dyn A + Send> { + a as _ + //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast +} + +fn rewrap_nested(a: *const W<W<dyn A>>) -> *const W<X<dyn A + Send>> { + a as _ + //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast +} + +fn wrap(a: *const dyn A) -> *const W<dyn A + Send> { + a as _ + //~^ error: cannot add auto trait `Send` to dyn bound via pointer cast +} + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr new file mode 100644 index 00000000000..42cdbc34ee8 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-add-auto.stderr @@ -0,0 +1,48 @@ +error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast + --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:12:5 + | +LL | a as _ + | ^^^^^^ unsupported cast + | + = note: this could allow UB elsewhere + = help: use `transmute` if you're sure this is sound + +error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast + --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:17:5 + | +LL | a as _ + | ^^^^^^ unsupported cast + | + = note: this could allow UB elsewhere + = help: use `transmute` if you're sure this is sound + +error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast + --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:22:5 + | +LL | a as _ + | ^^^^^^ unsupported cast + | + = note: this could allow UB elsewhere + = help: use `transmute` if you're sure this is sound + +error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast + --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:27:5 + | +LL | a as _ + | ^^^^^^ unsupported cast + | + = note: this could allow UB elsewhere + = help: use `transmute` if you're sure this is sound + +error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast + --> $DIR/ptr-to-trait-obj-wrap-add-auto.rs:32:5 + | +LL | a as _ + | ^^^^^^ unsupported cast + | + = note: this could allow UB elsewhere + = help: use `transmute` if you're sure this is sound + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0804`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs new file mode 100644 index 00000000000..ebe7a06a7a1 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.rs @@ -0,0 +1,36 @@ +// Combination of `ptr-to-trait-obj-different-args.rs` and `ptr-to-trait-obj-wrap.rs`. +// +// Checks that you *can't* change type arguments of trait objects in pointer casts involving +// wrapping said traits structures. + +trait A<T> {} + +struct W<T: ?Sized>(T); +struct X<T: ?Sized>(T); + +fn unwrap<F, G>(a: *const W<dyn A<F>>) -> *const dyn A<G> { + a as _ + //~^ error casting `*const W<(dyn A<F> + 'static)>` as `*const dyn A<G>` is invalid +} + +fn unwrap_nested<F, G>(a: *const W<W<dyn A<F>>>) -> *const W<dyn A<G>> { + a as _ + //~^ error casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<dyn A<G>>` is invalid +} + +fn rewrap<F, G>(a: *const W<dyn A<F>>) -> *const X<dyn A<G>> { + a as _ + //~^ error: casting `*const W<(dyn A<F> + 'static)>` as `*const X<dyn A<G>>` is invalid +} + +fn rewrap_nested<F, G>(a: *const W<W<dyn A<F>>>) -> *const W<X<dyn A<G>>> { + a as _ + //~^ error: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<X<dyn A<G>>>` is invalid +} + +fn wrap<F, G>(a: *const dyn A<F>) -> *const W<dyn A<G>> { + a as _ + //~^ error: casting `*const (dyn A<F> + 'static)` as `*const W<dyn A<G>>` is invalid +} + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr new file mode 100644 index 00000000000..4f85b208d05 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-args.stderr @@ -0,0 +1,43 @@ +error[E0606]: casting `*const W<(dyn A<F> + 'static)>` as `*const dyn A<G>` is invalid + --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:12:5 + | +LL | a as _ + | ^^^^^^ + | + = note: the trait objects may have different vtables + +error[E0606]: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<dyn A<G>>` is invalid + --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:17:5 + | +LL | a as _ + | ^^^^^^ + | + = note: the trait objects may have different vtables + +error[E0606]: casting `*const W<(dyn A<F> + 'static)>` as `*const X<dyn A<G>>` is invalid + --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:22:5 + | +LL | a as _ + | ^^^^^^ + | + = note: the trait objects may have different vtables + +error[E0606]: casting `*const W<W<(dyn A<F> + 'static)>>` as `*const W<X<dyn A<G>>>` is invalid + --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:27:5 + | +LL | a as _ + | ^^^^^^ + | + = note: the trait objects may have different vtables + +error[E0606]: casting `*const (dyn A<F> + 'static)` as `*const W<dyn A<G>>` is invalid + --> $DIR/ptr-to-trait-obj-wrap-different-args.rs:32:5 + | +LL | a as _ + | ^^^^^^ + | + = note: the trait objects may have different vtables + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs new file mode 100644 index 00000000000..b0941277d01 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.rs @@ -0,0 +1,41 @@ +// Combination of `ptr-to-trait-obj-different-regions-misc.rs` and `ptr-to-trait-obj-wrap.rs`. +// +// Checks that you *can't* change lifetime arguments of trait objects in pointer casts involving +// wrapping said traits structures. + +trait A<'a> {} + +struct W<T: ?Sized>(T); +struct X<T: ?Sized>(T); + +fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> { + a as _ + //~^ error + //~| error +} + +fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> { + a as _ + //~^ error + //~| error +} + +fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> { + a as _ + //~^ error: lifetime may not live long enough + //~| error: lifetime may not live long enough +} + +fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> { + a as _ + //~^ error: lifetime may not live long enough + //~| error: lifetime may not live long enough +} + +fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> { + a as _ + //~^ error: lifetime may not live long enough + //~| error: lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr new file mode 100644 index 00000000000..17a0ca3c34f --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-different-regions.stderr @@ -0,0 +1,140 @@ +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5 + | +LL | fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:12:5 + | +LL | fn unwrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const dyn A<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +help: `'b` and `'a` must be the same: replace one with the other + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5 + | +LL | fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:18:5 + | +LL | fn unwrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +help: `'b` and `'a` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5 + | +LL | fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:24:5 + | +LL | fn rewrap<'a, 'b>(a: *const W<dyn A<'a>>) -> *const X<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +help: `'b` and `'a` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5 + | +LL | fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:30:5 + | +LL | fn rewrap_nested<'a, 'b>(a: *const W<W<dyn A<'a>>>) -> *const W<X<dyn A<'b>>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +help: `'b` and `'a` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5 + | +LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-wrap-different-regions.rs:36:5 + | +LL | fn wrap<'a, 'b>(a: *const dyn A<'a>) -> *const W<dyn A<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | a as _ + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +help: `'b` and `'a` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap.rs b/tests/ui/cast/ptr-to-trait-obj-wrap.rs new file mode 100644 index 00000000000..6f9f6bddb99 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap.rs @@ -0,0 +1,33 @@ +// Checks that various casts of pointers to trait objects wrapped in structures +// work. Note that the metadata doesn't change when a DST is wrapped in a +// structure, so these casts *are* fine. +// +// `unwrap` and `unwrap_nested` currently don't work due to a compiler limitation. +//@ check-pass + +trait A {} + +struct W<T: ?Sized>(T); +struct X<T: ?Sized>(T); + +fn unwrap(a: *const W<dyn A>) -> *const dyn A { + a as _ +} + +fn unwrap_nested(a: *const W<W<dyn A>>) -> *const W<dyn A> { + a as _ +} + +fn rewrap(a: *const W<dyn A>) -> *const X<dyn A> { + a as _ +} + +fn rewrap_nested(a: *const W<W<dyn A>>) -> *const W<X<dyn A>> { + a as _ +} + +fn wrap(a: *const dyn A) -> *const W<dyn A> { + a as _ +} + +fn main() {} diff --git a/tests/ui/codemap_tests/tab_2.stderr b/tests/ui/codemap_tests/tab_2.stderr index b22c7b42665..4f9a937155d 100644 --- a/tests/ui/codemap_tests/tab_2.stderr +++ b/tests/ui/codemap_tests/tab_2.stderr @@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string LL | """; | ___________________^ LL | | } - | |_^ + | |__^ error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index e1c6861c510..87c8b04452b 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, const_vec_string_slice)] +#![feature(const_trait_impl)] struct Foo<'a> { bar: &'a mut Vec<usize>, diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr new file mode 100644 index 00000000000..252b17912de --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.long.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]` + ╭▸ $DIR/long-span.rs:7:5056 + │ +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0]; + │ ┬───────────────────────────…────────────────────── ━ ────────────────────────────…────────────────────── [{integer}; 1680] + │ │ + ╰╴ [{integer}; 1680] + +error[E0308]: mismatched types + ╭▸ $DIR/long-span.rs:9:15 + │ +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0]; + ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr new file mode 100644 index 00000000000..2e77c368922 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.longest.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]` + --> $DIR/long-span.rs:7:5056 + | +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + | -----------------------------------------...----------------------------------- ^ -----------------------------------------...----------------------------------- [{integer}; 1680] + | | + | [{integer}; 1680] + +error[E0308]: mismatched types + --> $DIR/long-span.rs:9:15 + | +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.rs b/tests/ui/diagnostic-width/long-span.rs new file mode 100644 index 00000000000..a3103379e93 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.rs @@ -0,0 +1,11 @@ +//@ revisions: shortest short long longest +//@[shortest] compile-flags: --diagnostic-width=4 +//@[short] compile-flags: --diagnostic-width=12 -Zunstable-options --json=diagnostic-unicode +//@[long] compile-flags: --diagnostic-width=80 -Zunstable-options --json=diagnostic-unicode +//@[longest] compile-flags: --diagnostic-width=120 +// ignore-tidy-linelength +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; +//~^ ERROR E0369 +const D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; +//~^ ERROR E0308 +fn main() {} diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr new file mode 100644 index 00000000000..b4803e31aaa --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.short.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]` + ╭▸ $DIR/long-span.rs:7:5056 + │ +LL │ …u8 = [0, 0, 0…0] + [0, 0, 0…0]; + │ ┬───────…── ━ ────────…── [{integer}; 1680] + │ │ + ╰╴ [{integer}; 1680] + +error[E0308]: mismatched types + ╭▸ $DIR/long-span.rs:9:15 + │ +LL │ …u8 = [0, 0, 0…0]; + ╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr new file mode 100644 index 00000000000..1de1a4acd92 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.shortest.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]` + --> $DIR/long-span.rs:7:5056 + | +LL | ... = [0, 0, 0...0] + [0, 0, 0...0]; + | --------...-- ^ --------...-- [{integer}; 1680] + | | + | [{integer}; 1680] + +error[E0308]: mismatched types + --> $DIR/long-span.rs:9:15 + | +LL | ... = [0, 0, 0...0]; + | ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr index 4d8afb6f3ad..60ce0d9a148 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr @@ -1,11 +1,41 @@ error[E0369]: cannot add `&str` to `&str` - --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 + --> $DIR/non-1-width-unicode-multiline-label.rs:7:237 | -LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - | -------------- ^ -------------- &str - | | | - | | `+` cannot be used to concatenate two `&str` strings - | &str +LL | ...👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:9:384 + | +LL | ...👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:11:260 + | +LL | ...࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str | = note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference @@ -13,6 +43,21 @@ help: create an owned `String` from a string reference LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; | +++++++++++ -error: aborting due to 1 previous error +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:13:219 + | +LL | ...xxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs index e630db8ba42..6b9b27f6297 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs @@ -4,6 +4,12 @@ fn main() { let unicode_is_fun = "‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥"; + let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` + let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; //[ascii]~^ ERROR cannot add `&str` to `&str` + let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` } diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr index ed8ce770bb7..15b5dd9d7e2 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr @@ -1,11 +1,41 @@ error[E0369]: cannot add `&str` to `&str` - ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:237 │ -LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - │ ┬───────────── ┯ ────────────── &str - │ │ │ - │ │ `+` cannot be used to concatenate two `&str` strings - │ &str +LL │ …👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:9:384 + │ +LL │ …👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:11:260 + │ +LL │ …࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str │ ╰ note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference @@ -13,6 +43,21 @@ help: create an owned `String` from a string reference LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; ╰╴ +++++++++++ -error: aborting due to 1 previous error +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:13:219 + │ +LL │ …xxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr index da3d8d31892..5408825d8cd 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr @@ -1,10 +1,10 @@ error[E0308]: mismatched types --> $DIR/non-whitespace-trimming-unicode.rs:4:415 | -LL | ...♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄... - | -- ^^ expected `()`, found integer - | | - | expected due to this +LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼... + | -- ^^ expected `()`, found integer + | | + | expected due to this error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/tabs-trimming.stderr b/tests/ui/diagnostic-width/tabs-trimming.stderr index 85103fbf6f5..a896345bd70 100644 --- a/tests/ui/diagnostic-width/tabs-trimming.stderr +++ b/tests/ui/diagnostic-width/tabs-trimming.stderr @@ -1,20 +1,20 @@ error[E0408]: variable `v` is not bound in all patterns --> $DIR/tabs-trimming.rs:9:16 | -LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... - | - ^ ^ pattern doesn't bind `v` - | | | - | | pattern doesn't bind `v` - | variable not in all patterns +LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... + | - ^ ^ pattern doesn't bind `v` + | | | + | | pattern doesn't bind `v` + | variable not in all patterns error[E0381]: used binding `v` is possibly-uninitialized --> $DIR/tabs-trimming.rs:9:67 | -LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... - | - ^ `v` used here but it is possibly-uninitialized - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized +LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... + | - ^ `v` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized | = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 905e1249d97..152a6f3a41e 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -44,22 +44,22 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index af5cc515bb2..53f1b827f9c 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -44,34 +44,34 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30 | LL | if local_passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 diff --git a/tests/ui/ergonomic-clones/async/basic.rs b/tests/ui/ergonomic-clones/async/basic.rs new file mode 100644 index 00000000000..ad2bfd97cd1 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/basic.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ edition:2018 + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::future::Future; + +fn ergonomic_clone_async_closures() -> impl Future<Output = String> { + let s = String::from("hi"); + + async use { + s + } +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/async/edition-2015.rs b/tests/ui/ergonomic-clones/async/edition-2015.rs new file mode 100644 index 00000000000..d3b2071b9f9 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.rs @@ -0,0 +1,7 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + async use {}; + //~^ ERROR `async use` blocks are only allowed in Rust 2018 or later +} diff --git a/tests/ui/ergonomic-clones/async/edition-2015.stderr b/tests/ui/ergonomic-clones/async/edition-2015.stderr new file mode 100644 index 00000000000..b218e6b242e --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.stderr @@ -0,0 +1,8 @@ +error: `async use` blocks are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:5:5 + | +LL | async use {}; + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/ergonomic-clones/async/local-type.rs b/tests/ui/ergonomic-clones/async/local-type.rs new file mode 100644 index 00000000000..e891686b550 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/local-type.rs @@ -0,0 +1,10 @@ +// Check that using the parameter name in its type does not ICE. +//@ edition:2018 + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let _ = async use |x: x| x; //~ ERROR expected type + let _ = async use |x: bool| -> x { x }; //~ ERROR expected type +} diff --git a/tests/ui/ergonomic-clones/async/local-type.stderr b/tests/ui/ergonomic-clones/async/local-type.stderr new file mode 100644 index 00000000000..fd832fbc8d2 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/local-type.stderr @@ -0,0 +1,15 @@ +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:8:27 + | +LL | let _ = async use |x: x| x; + | ^ not a type + +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:9:36 + | +LL | let _ = async use |x: bool| -> x { x }; + | ^ not a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/ergonomic-clones/closure/basic.rs b/tests/ui/ergonomic-clones/closure/basic.rs new file mode 100644 index 00000000000..01d3b08ffa2 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/basic.rs @@ -0,0 +1,58 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; +use std::future::Future; + +fn ergonomic_clone_closure_no_captures() -> i32 { + let cl = use || { + 1 + }; + cl() +} + +fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + let cl = use || { + s + }; + cl() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + let f1 = use || { + f + }; + + let f2 = use || { + f + }; + + f +} + +fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + let i1 = use || { + i + }; + + let i2 = use || { + i + }; + + i +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/const-closure.rs b/tests/ui/ergonomic-clones/closure/const-closure.rs new file mode 100644 index 00000000000..6b4de824df9 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/const-closure.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![feature(const_closures)] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +const fn foo() { + let cl = const use || {}; +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/expect-region.rs b/tests/ui/ergonomic-clones/closure/expect-region.rs new file mode 100644 index 00000000000..cbb13e56a18 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/expect-region.rs @@ -0,0 +1,25 @@ +#![feature(ergonomic_clones)] +#![allow(warnings)] + +fn closure_expecting_bound<F>(_: F) +where + F: FnOnce(&u32), +{ +} + +fn expect_bound_supply_named<'x>() { + let mut f: Option<&u32> = None; + + // Here we give a type annotation that `x` should be free. We get + // an error because of that. + closure_expecting_bound(use |x: &'x u32| { + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + + // Borrowck doesn't get a chance to run, but if it did it should error + // here. + f = Some(x); + }); +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/expect-region.stderr b/tests/ui/ergonomic-clones/closure/expect-region.stderr new file mode 100644 index 00000000000..4df1df1378b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/expect-region.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/expect-region.rs:15:34 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(use |x: &'x u32| { + | ^ - let's call the lifetime of this reference `'1` + | | + | requires that `'1` must outlive `'x` + +error: lifetime may not live long enough + --> $DIR/expect-region.rs:15:34 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(use |x: &'x u32| { + | ^ requires that `'x` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/ergonomic-clones/closure/fn-once.rs b/tests/ui/ergonomic-clones/closure/fn-once.rs new file mode 100644 index 00000000000..24060f3ed3b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/fn-once.rs @@ -0,0 +1,14 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn get_closure() -> Box<dyn Fn() -> Vec<u8>> { + let vec = vec![1u8, 2u8]; + + let closure = use || { //~ ERROR expected a closure + vec + }; + + Box::new(closure) +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/fn-once.stderr b/tests/ui/ergonomic-clones/closure/fn-once.stderr new file mode 100644 index 00000000000..40f1200695c --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/fn-once.stderr @@ -0,0 +1,16 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/fn-once.rs:7:19 + | +LL | let closure = use || { + | ^^^^^^ this closure implements `FnOnce`, not `Fn` +LL | vec + | --- closure is `FnOnce` because it moves the variable `vec` out of its environment +... +LL | Box::new(closure) + | ----------------- the requirement to implement `Fn` derives from here + | + = note: required for the cast from `Box<{closure@$DIR/fn-once.rs:7:19: 7:25}>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0525`. diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed new file mode 100644 index 00000000000..1e570632452 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed @@ -0,0 +1,16 @@ +//@ run-rustfix + +// Point at the captured immutable outer variable + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn foo(mut f: Box<dyn FnMut()>) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(use || y = !y) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable +} diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs new file mode 100644 index 00000000000..59aa61f581d --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs @@ -0,0 +1,16 @@ +//@ run-rustfix + +// Point at the captured immutable outer variable + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn foo(mut f: Box<dyn FnMut()>) { + f(); +} + +fn main() { + let y = true; + foo(Box::new(use || y = !y) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable +} diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr new file mode 100644 index 00000000000..f7c742d33fd --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr @@ -0,0 +1,14 @@ +error[E0594]: cannot assign to `y`, as it is not declared as mutable + --> $DIR/immutable-outer-variable.rs:14:25 + | +LL | foo(Box::new(use || y = !y) as Box<_>); + | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut y = true; + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/ergonomic-clones/closure/local-type.rs b/tests/ui/ergonomic-clones/closure/local-type.rs new file mode 100644 index 00000000000..b2f99efa1e6 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/local-type.rs @@ -0,0 +1,9 @@ +// Check that using the parameter name in its type does not ICE. + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let _ = use |x: x| x; //~ ERROR expected type + let _ = use |x: bool| -> x { x }; //~ ERROR expected type +} diff --git a/tests/ui/ergonomic-clones/closure/local-type.stderr b/tests/ui/ergonomic-clones/closure/local-type.stderr new file mode 100644 index 00000000000..5a42ae63afa --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/local-type.stderr @@ -0,0 +1,15 @@ +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:7:21 + | +LL | let _ = use |x: x| x; + | ^ not a type + +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:8:30 + | +LL | let _ = use |x: bool| -> x { x }; + | ^ not a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/ergonomic-clones/closure/mutation.rs b/tests/ui/ergonomic-clones/closure/mutation.rs new file mode 100644 index 00000000000..ef05fffd479 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation.rs @@ -0,0 +1,12 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let mut my_var = false; + let mut callback = use || { + my_var = true; + }; + callback(); +} diff --git a/tests/ui/ergonomic-clones/closure/mutation2.rs b/tests/ui/ergonomic-clones/closure/mutation2.rs new file mode 100644 index 00000000000..1cb5b8a7ec3 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation2.rs @@ -0,0 +1,11 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let mut my_var = false; + let callback = use || { + my_var = true; + }; + callback(); + //~^ ERROR cannot borrow `callback` as mutable, as it is not declared as mutable [E0596] +} diff --git a/tests/ui/ergonomic-clones/closure/mutation2.stderr b/tests/ui/ergonomic-clones/closure/mutation2.stderr new file mode 100644 index 00000000000..3ff33cf7017 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation2.stderr @@ -0,0 +1,17 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/mutation2.rs:9:5 + | +LL | my_var = true; + | ------ calling `callback` requires mutable binding due to possible mutation of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut callback = use || { + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/ergonomic-clones/closure/nested.rs b/tests/ui/ergonomic-clones/closure/nested.rs new file mode 100644 index 00000000000..fc364fb594b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/nested.rs @@ -0,0 +1,21 @@ +//@ run-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn work(_: Box<Foo>) {} +fn foo<F:FnOnce()>(_: F) {} + +pub fn main() { + let a = Box::new(Foo); + foo(use || { foo(use || { work(a) }) }); + let x = use || { use || { Foo } }; + let _y = x(); +} diff --git a/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs new file mode 100644 index 00000000000..a8267ac5359 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs @@ -0,0 +1,19 @@ +//@ run-pass +// Testing guarantees provided by once functions. + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::sync::Arc; + +fn foo<F: FnOnce()>(blk: F) { + blk(); +} + +pub fn main() { + let x = Arc::new(true); + foo(use || { + assert!(*x); + drop(x); + }); +} diff --git a/tests/ui/ergonomic-clones/closure/parse.rs b/tests/ui/ergonomic-clones/closure/parse.rs new file mode 100644 index 00000000000..0b3bfae0608 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/parse.rs @@ -0,0 +1,22 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn parse1() { + || use { + //~^ ERROR expected one of `async`, `|`, or `||`, found `{` + }; +} + +fn parse2() { + move use || { + //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `use` + }; +} + +fn parse3() { + use move || { + //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `move` + }; +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/parse.stderr b/tests/ui/ergonomic-clones/closure/parse.stderr new file mode 100644 index 00000000000..c37cb71394b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/parse.stderr @@ -0,0 +1,28 @@ +error: expected one of `async`, `|`, or `||`, found `{` + --> $DIR/parse.rs:5:12 + | +LL | || use { + | -- ^ expected one of `async`, `|`, or `||` + | | + | while parsing the body of this closure + | +help: you might have meant to open the body of the closure, instead of enclosing the closure in a block + | +LL ~ fn parse1() +LL ~ || { use { + | + +error: expected one of `async`, `|`, or `||`, found keyword `use` + --> $DIR/parse.rs:11:10 + | +LL | move use || { + | ^^^ expected one of `async`, `|`, or `||` + +error: expected one of `async`, `|`, or `||`, found keyword `move` + --> $DIR/parse.rs:17:9 + | +LL | use move || { + | ^^^^ expected one of `async`, `|`, or `||` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.rs b/tests/ui/ergonomic-clones/closure/print-verbose.rs new file mode 100644 index 00000000000..e80d0d4b649 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print-verbose.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Zverbose-internals + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn to_fn_once<F: FnOnce()>(f: F) -> F { + f +} + +fn f<T: std::fmt::Display>(y: T) { + struct Foo<U: std::fmt::Display> { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(use || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.stderr b/tests/ui/ergonomic-clones/closure/print-verbose.stderr new file mode 100644 index 00000000000..283405c79d6 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print-verbose.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/print-verbose.rs:22:5 + | +LL | let c = to_fn_once(use || { + | - move occurs because `c` has type `{f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)}`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/print-verbose.rs:21:5 + | +LL | c(); + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/print.rs b/tests/ui/ergonomic-clones/closure/print.rs new file mode 100644 index 00000000000..c24a4cc5094 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print.rs @@ -0,0 +1,26 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn to_fn_once<F: FnOnce()>(f: F) -> F { + f +} + +fn f<T: std::fmt::Display>(y: T) { + struct Foo<U: std::fmt::Display> { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(use || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/tests/ui/ergonomic-clones/closure/print.stderr b/tests/ui/ergonomic-clones/closure/print.stderr new file mode 100644 index 00000000000..5f48059ebff --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/print.rs:20:5 + | +LL | let c = to_fn_once(use || { + | - move occurs because `c` has type `{closure@$DIR/print.rs:15:24: 15:30}`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/print.rs:19:5 + | +LL | c(); + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/with-binders.rs b/tests/ui/ergonomic-clones/closure/with-binders.rs new file mode 100644 index 00000000000..4260c252d9d --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/with-binders.rs @@ -0,0 +1,10 @@ +//@ edition:2021 +//@ check-pass + +#![feature(closure_lifetime_binder)] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + for<'a> use || -> () {}; +} diff --git a/tests/ui/ergonomic-clones/dotuse/basic.rs b/tests/ui/ergonomic-clones/dotuse/basic.rs new file mode 100644 index 00000000000..8f962f079df --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/basic.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +fn basic_test(x: i32) -> i32 { + x.use.use.abs() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn do_not_move_test(x: Foo) -> Foo { + let s = x.use; + x +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse/parse.rs b/tests/ui/ergonomic-clones/dotuse/parse.rs new file mode 100644 index 00000000000..37ef5c37029 --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/parse.rs @@ -0,0 +1,39 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn parse1() { + 1.use!; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + } + +fn parse2() { + 1.use!(2); + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + } + +fn parse3() { + 1.use 2; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + } + +fn parse4() { + 1.use? 2; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + } + +fn parse5() { + 1.use(); + //~^ ERROR: incorrect use of `use` +} + +fn parse6() { + 1.use(2); + //~^ ERROR: expected function, found `{integer}` [E0618] +} + +fn parse7() { + 1.use { 2 }; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse/parse.stderr b/tests/ui/ergonomic-clones/dotuse/parse.stderr new file mode 100644 index 00000000000..4b7a92534ed --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/parse.stderr @@ -0,0 +1,53 @@ +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + --> $DIR/parse.rs:5:10 + | +LL | 1.use!; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + --> $DIR/parse.rs:10:10 + | +LL | 1.use!(2); + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + --> $DIR/parse.rs:15:11 + | +LL | 1.use 2; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + --> $DIR/parse.rs:20:12 + | +LL | 1.use? 2; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: incorrect use of `use` + --> $DIR/parse.rs:25:10 + | +LL | 1.use(); + | ^^ + | +help: `use` is not a method call, try removing the parentheses + | +LL - 1.use(); +LL + 1.use; + | + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/parse.rs:35:11 + | +LL | 1.use { 2 }; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error[E0618]: expected function, found `{integer}` + --> $DIR/parse.rs:30:5 + | +LL | 1.use(2); + | ^^^^^--- + | | + | call expression requires function + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0618`. diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs new file mode 100644 index 00000000000..c2e44064cfa --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs @@ -0,0 +1,32 @@ +use std::clone::UseCloned; +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +fn ergonomic_clone(x: i32) -> i32 { + x.use + //~^ ERROR ergonomic clones are experimental [E0658] +} + +#[derive(Clone)] +struct Foo; + +fn foo<T: UseCloned>() {} +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +impl UseCloned for Foo {} +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +fn ergonomic_closure_clone() { + let f1 = Foo; + + let f2 = use || { + //~^ ERROR ergonomic clones are experimental [E0658] + f1 + }; + + let f3 = use || { + //~^ ERROR ergonomic clones are experimental [E0658] + f1 + }; +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr new file mode 100644 index 00000000000..cf92f2f28df --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr @@ -0,0 +1,63 @@ +error[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:5:7 + | +LL | x.use + | ^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:21:14 + | +LL | let f2 = use || { + | ^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:26:14 + | +LL | let f3 = use || { + | ^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:1:5 + | +LL | use std::clone::UseCloned; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:12:11 + | +LL | fn foo<T: UseCloned>() {} + | ^^^^^^^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:15:6 + | +LL | impl UseCloned for Foo {} + | ^^^^^^^^^ + | + = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/issues/issue-44078.stderr b/tests/ui/issues/issue-44078.stderr index 41106b29aad..3e12de34e11 100644 --- a/tests/ui/issues/issue-44078.stderr +++ b/tests/ui/issues/issue-44078.stderr @@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string LL | "😊""; | _________^ LL | | } - | |_^ + | |__^ error: aborting due to 1 previous error diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs index 2daac12d7ac..c8a4a222cc6 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.rs +++ b/tests/ui/layout/post-mono-layout-cycle-2.rs @@ -1,4 +1,4 @@ -//@ build-fail +//@ check-fail //@ edition: 2021 use std::future::Future; diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr index d8c51deffe3..f04e01071d7 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.stderr +++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr @@ -12,12 +12,6 @@ LL | Blah::iter(self, iterator).await | = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future -note: the above error was encountered while instantiating `fn Wrap::<()>::ice` - --> $DIR/post-mono-layout-cycle-2.rs:54:9 - | -LL | t.ice(); - | ^^^^^^^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/lexer/unterminated-nested-comment.stderr b/tests/ui/lexer/unterminated-nested-comment.stderr index 78b72ce1fe4..9117b689c94 100644 --- a/tests/ui/lexer/unterminated-nested-comment.stderr +++ b/tests/ui/lexer/unterminated-nested-comment.stderr @@ -12,7 +12,7 @@ LL | | /* | | | | | ...as last nested comment starts here, maybe you want to close this instead? LL | | */ - | |_-^ + | |_--^ | | | ...and last nested comment terminates here. diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs index 20999df9844..db23dcd5e5e 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs @@ -1,10 +1,10 @@ //@ check-pass -// this test checks that the `dead_code` lint is *NOT* being emited +// this test checks that the `dead_code` lint is *NOT* being emitted // for `foo` as `foo` is being used by `main`, and so the `#[expect]` // is unfulfilled // -// it also checks that the `dead_code` lint is also *NOT* emited +// it also checks that the `dead_code` lint is also *NOT* emitted // for `bar` as it's suppresed by the `#[expect]` on `bar` #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs index 08103b23387..c4476e43e1f 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs @@ -1,7 +1,7 @@ //@ check-pass // this test makes sure that the `unfulfilled_lint_expectations` lint -// is being emited for `foo` as foo is not dead code, it's pub +// is being emitted for `foo` as foo is not dead code, it's pub #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs index f2625f0781f..ea2e81261d1 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs @@ -2,7 +2,7 @@ //@ revisions: allow expect // this test checks that no matter if we put #[allow(dead_code)] -// or #[expect(dead_code)], no warning is being emited +// or #[expect(dead_code)], no warning is being emitted #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/lint-incoherent-auto-trait-objects.rs b/tests/ui/lint/lint-incoherent-auto-trait-objects.rs index d53b5144760..d34e6658435 100644 --- a/tests/ui/lint/lint-incoherent-auto-trait-objects.rs +++ b/tests/ui/lint/lint-incoherent-auto-trait-objects.rs @@ -4,16 +4,13 @@ impl Foo for dyn Send {} impl Foo for dyn Send + Send {} //~^ ERROR conflicting implementations -//~| hard error impl Foo for dyn Send + Sync {} impl Foo for dyn Sync + Send {} //~^ ERROR conflicting implementations -//~| hard error impl Foo for dyn Send + Sync + Send {} //~^ ERROR conflicting implementations -//~| hard error fn main() {} diff --git a/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr b/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr index 553ab3869b3..28e8f74672d 100644 --- a/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr +++ b/tests/ui/lint/lint-incoherent-auto-trait-objects.stderr @@ -1,4 +1,4 @@ -error: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)`: (E0119) +error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)` --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1 | LL | impl Foo for dyn Send {} @@ -6,76 +6,25 @@ LL | impl Foo for dyn Send {} LL | LL | impl Foo for dyn Send + Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - = note: `#[deny(order_dependent_trait_objects)]` on by default -error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1 +error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)` + --> $DIR/lint-incoherent-auto-trait-objects.rs:10:1 | LL | impl Foo for dyn Send + Sync {} | ---------------------------- first implementation here LL | LL | impl Foo for dyn Sync + Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> -error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1 +error[E0119]: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)` + --> $DIR/lint-incoherent-auto-trait-objects.rs:13:1 | -LL | impl Foo for dyn Sync + Send {} +LL | impl Foo for dyn Send + Sync {} | ---------------------------- first implementation here ... LL | impl Foo for dyn Send + Sync + Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> error: aborting due to 3 previous errors -Future incompatibility report: Future breakage diagnostic: -error: conflicting implementations of trait `Foo` for type `(dyn Send + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1 - | -LL | impl Foo for dyn Send {} - | --------------------- first implementation here -LL | -LL | impl Foo for dyn Send + Send {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - = note: `#[deny(order_dependent_trait_objects)]` on by default - -Future breakage diagnostic: -error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1 - | -LL | impl Foo for dyn Send + Sync {} - | ---------------------------- first implementation here -LL | -LL | impl Foo for dyn Sync + Send {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - = note: `#[deny(order_dependent_trait_objects)]` on by default - -Future breakage diagnostic: -error: conflicting implementations of trait `Foo` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1 - | -LL | impl Foo for dyn Sync + Send {} - | ---------------------------- first implementation here -... -LL | impl Foo for dyn Send + Sync + Send {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - = note: `#[deny(order_dependent_trait_objects)]` on by default - +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/lint/unused/must-use-ops.rs b/tests/ui/lint/unused/must-use-ops.rs index f61cf0fcfcb..5085dbb58c1 100644 --- a/tests/ui/lint/unused/must-use-ops.rs +++ b/tests/ui/lint/unused/must-use-ops.rs @@ -6,7 +6,7 @@ #![feature(never_type)] fn deref_never(x: &!) { - // Don't lint for uninhabited typess + // Don't lint for uninhabited types *x; } diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs new file mode 100644 index 00000000000..fc3b51b40a5 --- /dev/null +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs @@ -0,0 +1,20 @@ +//! Test for the crash in #133426, caused by an empty symbol being used for a +//! type name. + +#![allow(incomplete_features)] +#![feature(never_patterns)] + +fn a( + _: impl Iterator< + Item = [(); { + match *todo!() { ! }; //~ ERROR type `!` cannot be dereferenced + }], + >, +) { +} + +fn b(_: impl Iterator<Item = { match 0 { ! } }>) {} +//~^ ERROR associated const equality is incomplete +//~| ERROR expected type, found constant + +fn main() {} diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr new file mode 100644 index 00000000000..555d8eec6ba --- /dev/null +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr @@ -0,0 +1,31 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/no-name-for-DefPath-issue-133426.rs:16:23 + | +LL | fn b(_: impl Iterator<Item = { match 0 { ! } }>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0614]: type `!` cannot be dereferenced + --> $DIR/no-name-for-DefPath-issue-133426.rs:10:19 + | +LL | match *todo!() { ! }; + | ^^^^^^^^ can't be dereferenced + +error: expected type, found constant + --> $DIR/no-name-for-DefPath-issue-133426.rs:16:30 + | +LL | fn b(_: impl Iterator<Item = { match 0 { ! } }>) {} + | ---- ^^^^^^^^^^^^^^^^^ unexpected constant + | | + | expected a type because of this associated type + | +note: the associated type is defined here + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0614, E0658. +For more information about an error, try `rustc --explain E0614`. diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr index 17ee8197ac8..be028816e0f 100644 --- a/tests/ui/macros/not-utf8.stderr +++ b/tests/ui/macros/not-utf8.stderr @@ -7,7 +7,7 @@ LL | include!("not-utf8.bin"); note: byte `193` is not valid utf-8 --> $DIR/not-utf8.bin:1:1 | -LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�... +LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�␜␇� | ^ = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/same-sequence-span.stderr b/tests/ui/macros/same-sequence-span.stderr index ff32ef94386..34df201f5a5 100644 --- a/tests/ui/macros/same-sequence-span.stderr +++ b/tests/ui/macros/same-sequence-span.stderr @@ -18,7 +18,7 @@ error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fra --> $DIR/same-sequence-span.rs:19:1 | LL | | macro_rules! manual_foo { - | |_________________________________^ not allowed after `expr` fragments + | |__________________________^not allowed after `expr` fragments ... LL | proc_macro_sequence::make_foo!(); | ^------------------------------- diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs index 2fde37ce6ac..b08c830bfc7 100644 --- a/tests/ui/parser/block-no-opening-brace.rs +++ b/tests/ui/parser/block-no-opening-brace.rs @@ -30,7 +30,7 @@ fn in_try() { // FIXME(#80931) fn in_async() { async - let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` + let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let` } // FIXME(#78168) diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index b65de4eac3f..f51ee92626f 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try` LL | try | ^^^ expected expression -error: expected one of `move`, `|`, or `||`, found keyword `let` +error: expected one of `move`, `use`, `|`, or `||`, found keyword `let` --> $DIR/block-no-opening-brace.rs:33:9 | LL | async - | - expected one of `move`, `|`, or `||` + | - expected one of `move`, `use`, `|`, or `||` LL | let x = 0; | ^^^ unexpected token diff --git a/tests/ui/parser/byte-string-literals.stderr b/tests/ui/parser/byte-string-literals.stderr index 08633742557..3e589258d41 100644 --- a/tests/ui/parser/byte-string-literals.stderr +++ b/tests/ui/parser/byte-string-literals.stderr @@ -44,7 +44,7 @@ error[E0766]: unterminated double quote byte string LL | b"a | ______^ LL | | } - | |_^ + | |__^ error: aborting due to 6 previous errors diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr index a002d54dc91..2507326fb28 100644 --- a/tests/ui/parser/misspelled-keywords/async-move.stderr +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `|`, or `||`, found `Move` +error: expected one of `move`, `use`, `|`, or `||`, found `Move` --> $DIR/async-move.rs:4:11 | LL | async Move {} - | ^^^^ expected one of `move`, `|`, or `||` + | ^^^^ expected one of `move`, `use`, `|`, or `||` | help: write keyword `move` in lowercase | diff --git a/tests/ui/parser/raw/too-many-hash.stderr b/tests/ui/parser/raw/too-many-hash.stderr index 1c46b5385cd..6b3854eb4a2 100644 --- a/tests/ui/parser/raw/too-many-hash.stderr +++ b/tests/ui/parser/raw/too-many-hash.stderr @@ -1,8 +1,8 @@ error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256 --> $DIR/too-many-hash.rs:4:19 | -LL | ... = r################################################################################################################################################################################################################################################################"very raw"##############################################################################################################################################################################################################################################################... - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... = r####################################################...#######################################; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs index 10af39b7007..1f5004ad099 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.rs +++ b/tests/ui/parser/recover/recover-quantified-closure.rs @@ -7,6 +7,6 @@ fn main() { enum Foo { Bar } fn foo(x: impl Iterator<Item = Foo>) { for <Foo>::Bar in x {} - //~^ ERROR expected one of `move`, `static`, `|` + //~^ ERROR expected one of `move`, `static`, `use`, `|` //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr index 6e03bbb5869..48dea071ae6 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.stderr +++ b/tests/ui/parser/recover/recover-quantified-closure.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `static`, `|`, or `||`, found `::` +error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::` --> $DIR/recover-quantified-closure.rs:9:14 | LL | for <Foo>::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^ expected one of `move`, `static`, `use`, `|`, or `||` error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5 diff --git a/tests/ui/parser/unbalanced-doublequote.stderr b/tests/ui/parser/unbalanced-doublequote.stderr index 9fdad87a86c..d40b982da7c 100644 --- a/tests/ui/parser/unbalanced-doublequote.stderr +++ b/tests/ui/parser/unbalanced-doublequote.stderr @@ -3,7 +3,7 @@ error[E0765]: unterminated double quote string | LL | / " LL | | } - | |_^ + | |__^ error: aborting due to 1 previous error diff --git a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs index d7ade7f0e96..009cc66f3f7 100644 --- a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs +++ b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs @@ -5,7 +5,7 @@ #![deny(exported_private_dependencies)] // Ensure the libbar.rlib is loaded first. If the command line parameter `--extern foo` does not -// exist, previus version would fail to compile +// exist, previous version would fail to compile #![crate_type = "rlib"] extern crate bar; extern crate foo; diff --git a/tests/ui/repr/repr-empty-packed.rs b/tests/ui/repr/repr-empty-packed.rs new file mode 100644 index 00000000000..6e390a12b15 --- /dev/null +++ b/tests/ui/repr/repr-empty-packed.rs @@ -0,0 +1,9 @@ +//@ compile-flags: --crate-type=lib +#![deny(unused_attributes)] + +#[repr()] //~ ERROR unused attribute +#[repr(packed)] //~ ERROR attribute should be applied to a struct or union +pub enum Foo { + Bar, + Baz(i32), +} diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr new file mode 100644 index 00000000000..c824c2998b4 --- /dev/null +++ b/tests/ui/repr/repr-empty-packed.stderr @@ -0,0 +1,27 @@ +error: unused attribute + --> $DIR/repr-empty-packed.rs:4:1 + | +LL | #[repr()] + | ^^^^^^^^^ help: remove this attribute + | + = note: attribute `repr` with an empty list has no effect +note: the lint level is defined here + --> $DIR/repr-empty-packed.rs:2:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error[E0517]: attribute should be applied to a struct or union + --> $DIR/repr-empty-packed.rs:5:8 + | +LL | #[repr(packed)] + | ^^^^^^ +LL | / pub enum Foo { +LL | | Bar, +LL | | Baz(i32), +LL | | } + | |_- not a struct or union + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0517`. diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr index 0f3b06147c4..fde3a719e67 100644 --- a/tests/ui/rust-2024/reserved-guarded-strings.stderr +++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr @@ -241,7 +241,7 @@ LL | demo2!(#"foo"## #); error: invalid string literal --> $DIR/reserved-guarded-strings.rs:71:12 | -LL | ...n!(####################################################################################################################################################################################################################################################################"foo... +LL | ...n!(####################################################################################################################################################################################################################################################################"foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: unprefixed guarded string literals are reserved for future use since Rust 2024 diff --git a/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs new file mode 100644 index 00000000000..9963b5be4f2 --- /dev/null +++ b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs @@ -0,0 +1,30 @@ +//@ edition:2021 +trait Trait {} + +struct Foo1 { + a: Trait, + //~^ ERROR expected a type, found a trait + b: u32, +} + +struct Foo2 { + a: i32, + b: Trait, + //~^ ERROR expected a type, found a trait +} + + +enum Enum1 { + A(Trait), + //~^ ERROR expected a type, found a trait + B(u32), +} + +enum Enum2 { + A(u32), + B(Trait), + //~^ ERROR expected a type, found a trait +} + + +fn main() {} diff --git a/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr new file mode 100644 index 00000000000..433196919ca --- /dev/null +++ b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr @@ -0,0 +1,51 @@ +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:5:8 + | +LL | a: Trait, + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ struct Foo1<T: Trait> { +LL ~ a: T, + | + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:12:8 + | +LL | b: Trait, + | ^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | b: dyn Trait, + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:18:7 + | +LL | A(Trait), + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ enum Enum1<T: Trait> { +LL ~ A(T), + | + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:25:7 + | +LL | B(Trait), + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ enum Enum2<T: Trait> { +LL | A(u32), +LL ~ B(T), + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/traits/issue-33140-hack-boundaries.rs b/tests/ui/traits/issue-33140-hack-boundaries.rs index d091162fced..06786dcc8fe 100644 --- a/tests/ui/traits/issue-33140-hack-boundaries.rs +++ b/tests/ui/traits/issue-33140-hack-boundaries.rs @@ -1,5 +1,4 @@ #![feature(negative_impls)] -#![allow(order_dependent_trait_objects)] // Check that the issue #33140 hack does not allow unintended things. @@ -8,6 +7,7 @@ trait Trait0 {} impl Trait0 for dyn Send {} impl Trait0 for dyn Send {} +//~^ ERROR: E0119 // Problem 1: associated types trait Trait1 { diff --git a/tests/ui/traits/issue-33140-hack-boundaries.stderr b/tests/ui/traits/issue-33140-hack-boundaries.stderr index d9c4efbb721..ed3ae2b3167 100644 --- a/tests/ui/traits/issue-33140-hack-boundaries.stderr +++ b/tests/ui/traits/issue-33140-hack-boundaries.stderr @@ -1,3 +1,11 @@ +error[E0119]: conflicting implementations of trait `Trait0` for type `(dyn Send + 'static)` + --> $DIR/issue-33140-hack-boundaries.rs:9:1 + | +LL | impl Trait0 for dyn Send {} + | ------------------------ first implementation here +LL | impl Trait0 for dyn Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)` + error[E0119]: conflicting implementations of trait `Trait1` for type `(dyn Send + 'static)` --> $DIR/issue-33140-hack-boundaries.rs:18:1 | @@ -62,19 +70,7 @@ LL | impl Trait5 for dyn Send {} LL | impl Trait5 for dyn Send where u32: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0119, E0751. For more information about an error, try `rustc --explain E0119`. -Future incompatibility report: Future breakage diagnostic: -warning: conflicting implementations of trait `Trait0` for type `(dyn Send + 'static)`: (E0119) - --> $DIR/issue-33140-hack-boundaries.rs:10:1 - | -LL | impl Trait0 for dyn Send {} - | ------------------------ first implementation here -LL | impl Trait0 for dyn Send {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.rs b/tests/ui/traits/object/issue-33140-traitobject-crate.rs index 00ef6430d63..ff7cd30644b 100644 --- a/tests/ui/traits/object/issue-33140-traitobject-crate.rs +++ b/tests/ui/traits/object/issue-33140-traitobject-crate.rs @@ -1,6 +1,3 @@ -//@ check-pass - -#![warn(order_dependent_trait_objects)] #![allow(dyn_drop)] // Check that traitobject 0.1.0 compiles @@ -84,15 +81,12 @@ unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send + Sync { } unsafe impl Trait for dyn (::std::marker::Send) + Send { } unsafe impl Trait for dyn (::std::marker::Send) + Sync { } unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } -//~^ WARNING conflicting implementations of trait `Trait` for type -//~| WARNING this was previously accepted by the compiler but is being phased out +//~^ ERROR conflicting implementations of trait `Trait` for type unsafe impl Trait for dyn (::std::marker::Sync) + Send { } -//~^ WARNING conflicting implementations of trait `Trait` for type -//~| WARNING this was previously accepted by the compiler but is being phased out +//~^ ERROR conflicting implementations of trait `Trait` for type unsafe impl Trait for dyn (::std::marker::Sync) + Sync { } unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } -//~^ WARNING conflicting implementations of trait `Trait` for type -//~| WARNING this was previously accepted by the compiler but is being phased out +//~^ ERROR conflicting implementations of trait `Trait` for type unsafe impl Trait for dyn (::std::ops::Drop) + Send { } unsafe impl Trait for dyn (::std::ops::Drop) + Sync { } unsafe impl Trait for dyn (::std::ops::Drop) + Send + Sync { } diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr index 525401f9d69..a01c7990db3 100644 --- a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr +++ b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr @@ -1,95 +1,29 @@ -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:86:1 +error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)` + --> $DIR/issue-33140-traitobject-crate.rs:83:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } | ------------------------------------------------------ first implementation here LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> -note: the lint level is defined here - --> $DIR/issue-33140-traitobject-crate.rs:3:9 - | -LL | #![warn(order_dependent_trait_objects)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:89:1 - | -LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } - | ------------------------------------------------------------- first implementation here -... -LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:93:1 - | -LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } - | ------------------------------------------------------ first implementation here -... -LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> - -warning: 3 warnings emitted -Future incompatibility report: Future breakage diagnostic: -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:86:1 +error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)` + --> $DIR/issue-33140-traitobject-crate.rs:85:1 | LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } | ------------------------------------------------------ first implementation here -LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> -note: the lint level is defined here - --> $DIR/issue-33140-traitobject-crate.rs:3:9 - | -LL | #![warn(order_dependent_trait_objects)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:89:1 - | -LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } - | ------------------------------------------------------------- first implementation here ... LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> -note: the lint level is defined here - --> $DIR/issue-33140-traitobject-crate.rs:3:9 - | -LL | #![warn(order_dependent_trait_objects)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) - --> $DIR/issue-33140-traitobject-crate.rs:93:1 +error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)` + --> $DIR/issue-33140-traitobject-crate.rs:88:1 | -LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } +LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } | ------------------------------------------------------ first implementation here ... LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> -note: the lint level is defined here - --> $DIR/issue-33140-traitobject-crate.rs:3:9 - | -LL | #![warn(order_dependent_trait_objects)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/triagebot.toml b/triagebot.toml index 7114c7ab27b..e4231b2966b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -18,6 +18,7 @@ allow-unauthenticated = [ "WG-*", "-Z*", "beta-nominated", + "CI-spurious-*", "const-hack", "llvm-*", "needs-fcp", @@ -252,7 +253,6 @@ trigger_files = [ "compiler/rustc_passes/src/check_attr.rs", "compiler/rustc_attr_parsing", "compiler/rustc_attr_data_structures", - "compiler/rustc_attr_validation", ] [autolabel."T-rustdoc-frontend"] @@ -316,7 +316,6 @@ trigger_files = [ "library/panic_unwind", "library/std", "library/stdarch", - "library/term", "library/test", ] exclude_labels = [ @@ -331,7 +330,7 @@ trigger_files = [ [autolabel."O-apple"] trigger_files = [ "library/std/src/os/darwin", - "library/std/src/sys/pal/unix/thread_parking/darwin.rs", + "library/std/src/sys/sync/thread_parking/darwin.rs", "compiler/rustc_target/src/spec/base/apple", ] @@ -408,7 +407,8 @@ trigger_files = [ [autolabel."O-wasm"] trigger_files = [ "library/std/src/sys/pal/wasm", - "library/std/src/os/wasm" + "library/std/src/os/wasi", + "library/std/src/os/wasip2" ] [autolabel."O-windows"] @@ -499,7 +499,6 @@ trigger_files = [ "CONTRIBUTING.md", "INSTALL.md", "REUSE.toml", - ".reuse", ".mailmap", ".git-blame-ignore-revs", ".editorconfig" @@ -524,7 +523,6 @@ exclude_labels = [ [autolabel."WG-trait-system-refactor"] trigger_files = [ - "compiler/rustc_middle/src/traits/solve", "compiler/rustc_next_trait_solver", "compiler/rustc_trait_selection/src/solve", "compiler/rustc_type_ir/src/solve", @@ -794,7 +792,7 @@ cc = ["@Nadrieril"] message = "Some changes occurred in cfg and check-cfg configuration" cc = ["@Urgau"] -[mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"] +[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"] message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] @@ -960,7 +958,7 @@ If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/util [mentions."src/bootstrap/src/core/build_steps/llvm.rs"] message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." -[mentions."test/crashes"] +[mentions."tests/crashes"] message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, please move into the corresponding `ui` subdir and add 'Fixes #<issueNr>' to the PR description to autoclose the issue upon merge." [mentions."tests/rustdoc-json"] @@ -1074,8 +1072,6 @@ cc = ["@jdonszelmann"] cc = ["@jdonszelmann"] [mentions."compiler/rustc_attr_data_structures"] cc = ["@jdonszelmann"] -[mentions."compiler/rustc_attr_validation"] -cc = ["@jdonszelmann"] [assign] warn_non_default_branch.enable = true @@ -1264,7 +1260,6 @@ project-exploit-mitigations = [ "/compiler/rustc_middle/src/traits" = ["compiler", "types"] "/compiler/rustc_middle/src/ty" = ["compiler", "types"] "/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"] -"/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"] "/compiler/rustc_mir_build/src/builder" = ["compiler", "mir"] "/compiler/rustc_mir_transform" = ["compiler", "mir", "mir-opt"] "/compiler/rustc_smir" = ["project-stable-mir"] |
