From 13426f444746f028e7f2bfa7420fd769b67be191 Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Thu, 22 Jun 2023 21:11:10 +0200 Subject: [PATCH 001/106] Add illumos aarch64 target Signed-off-by: Till Wegmueller --- .../src/spec/aarch64_unknown_illumos.rs | 19 +++++++++++++++++++ compiler/rustc_target/src/spec/mod.rs | 1 + src/doc/rustc/src/platform-support.md | 1 + 3 files changed, 21 insertions(+) create mode 100644 compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs new file mode 100644 index 000000000000..25ce3c77c6f1 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs @@ -0,0 +1,19 @@ +use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target}; + +pub fn target() -> Target { + let mut base = super::illumos_base::opts(); + base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-std=c99"]); + base.cpu = "aarch64".into(); + base.max_atomic_width = Some(128); + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; + + Target { + // LLVM does not currently have a separate illumos target, + // so we still pass Solaris to it + llvm_target: "aarch64-unknown-solaris2.11".into(), + pointer_width: 64, + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + arch: "aarch64".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index dbce2f30f939..a2215f26df96 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1586,6 +1586,7 @@ supported_targets! { ("sparcv9-sun-solaris", sparcv9_sun_solaris), ("x86_64-unknown-illumos", x86_64_unknown_illumos), + ("aarch64-unknown-illumos", aarch64_unknown_illumos), ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), ("i686-pc-windows-gnu", i686_pc_windows_gnu), diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 3671fdd3fd2b..b4b2060d4874 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -229,6 +229,7 @@ target | std | host | notes [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit +`aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD From 5af05f8dfdf0873381806eb470ae3d1f7bcc06b2 Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Mon, 4 Dec 2023 12:48:57 -0800 Subject: [PATCH 002/106] Update target to be in line with recent target refactors Signed-off-by: Till Wegmueller --- .../src/spec/{ => targets}/aarch64_unknown_illumos.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename compiler/rustc_target/src/spec/{ => targets}/aarch64_unknown_illumos.rs (84%) diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs similarity index 84% rename from compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs rename to compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs index 25ce3c77c6f1..f4e4ac51ae72 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs @@ -1,7 +1,7 @@ -use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target}; +use crate::spec::{base, Cc, LinkerFlavor, SanitizerSet, Target}; pub fn target() -> Target { - let mut base = super::illumos_base::opts(); + let mut base = base::illumos::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-std=c99"]); base.cpu = "aarch64".into(); base.max_atomic_width = Some(128); From 6959818ec2472295e46e1cbe7526e42698cff849 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 16 Dec 2023 01:37:00 -0800 Subject: [PATCH 003/106] Hoist fn absent --- compiler/rustc_abi/src/layout.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5252472261f3..e73170c01f83 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -11,6 +11,24 @@ use crate::{ Variants, WrappingRange, }; +// A variant is absent if it's uninhabited and only has ZST fields. +// Present uninhabited variants only require space for their fields, +// but *not* an encoding of the discriminant (e.g., a tag value). +// See issue #49298 for more details on the need to leave space +// for non-ZST uninhabited data (mostly partial initialization). +fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice) -> bool +where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug, +{ + let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); + // We cannot ignore alignment; that might lead us to entirely discard a variant and + // produce an enum that is less aligned than it should be! + let is_1zst = fields.iter().all(|f| f.is_1zst()); + uninhabited && is_1zst +} + pub trait LayoutCalculator { type TargetDataLayoutRef: Borrow; @@ -168,18 +186,6 @@ pub trait LayoutCalculator { Scalar::Initialized { value, valid_range: WrappingRange::full(size) } }; - // A variant is absent if it's uninhabited and only has ZST fields. - // Present uninhabited variants only require space for their fields, - // but *not* an encoding of the discriminant (e.g., a tag value). - // See issue #49298 for more details on the need to leave space - // for non-ZST uninhabited data (mostly partial initialization). - let absent = |fields: &IndexSlice| { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); - // We cannot ignore alignment; that might lead us to entirely discard a variant and - // produce an enum that is less aligned than it should be! - let is_1zst = fields.iter().all(|f| f.is_1zst()); - uninhabited && is_1zst - }; let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() From f116bc6e27042123ed25a43303615ba7d54a2f8e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 16 Dec 2023 01:43:40 -0800 Subject: [PATCH 004/106] Manually inline scalar_unit --- compiler/rustc_abi/src/layout.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index e73170c01f83..9f84c1aeaaf1 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -180,12 +180,6 @@ pub trait LayoutCalculator { let dl = self.current_data_layout(); let dl = dl.borrow(); - let scalar_unit = |value: Primitive| { - let size = value.size(dl); - assert!(size.bits() <= 128); - Scalar::Initialized { value, valid_range: WrappingRange::full(size) } - }; - let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() @@ -678,7 +672,9 @@ pub trait LayoutCalculator { } if let Some((prim, offset)) = common_prim { let prim_scalar = if common_prim_initialized_in_all_variants { - scalar_unit(prim) + let size = prim.size(dl); + assert!(size.bits() <= 128); + Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } } else { // Common prim might be uninit. Scalar::Union { value: prim } From b525f76bb50438ce5748635799c63421944b57c5 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 16 Dec 2023 01:44:13 -0800 Subject: [PATCH 005/106] Extract fn layout_of_enum --- compiler/rustc_abi/src/layout.rs | 972 ++++++++++++++++--------------- 1 file changed, 496 insertions(+), 476 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 9f84c1aeaaf1..102bef9f6de3 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -291,482 +291,15 @@ pub trait LayoutCalculator { // structs. (We have also handled univariant enums // that allow representation optimization.) assert!(is_enum); - - // Until we've decided whether to use the tagged or - // niche filling LayoutS, we don't want to intern the - // variant layouts, so we can't store them in the - // overall LayoutS. Store the overall LayoutS - // and the variant LayoutSs here until then. - struct TmpLayout { - layout: LayoutS, - variants: IndexVec>, - } - - let calculate_niche_filling_layout = || -> Option> { - if dont_niche_optimize_enum { - return None; - } - - if variants.len() < 2 { - return None; - } - - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; - - let mut variant_layouts = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = self.univariant(dl, v, repr, StructKind::AlwaysSized)?; - st.variants = Variants::Single { index: j }; - - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - - Some(st) - }) - .collect::>>()?; - - let largest_variant_index = variant_layouts - .iter_enumerated() - .max_by_key(|(_i, layout)| layout.size.bytes()) - .map(|(i, _layout)| i)?; - - let all_indices = variants.indices(); - let needs_disc = - |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); - let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() - ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); - - let count = - (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; - - // Find the field with the largest niche - let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index] - .iter() - .enumerate() - .filter_map(|(j, field)| Some((j, field.largest_niche?))) - .max_by_key(|(_, niche)| niche.available(dl)) - .and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?; - let niche_offset = - niche.offset + variant_layouts[largest_variant_index].fields.offset(field_index); - let niche_size = niche.value.size(dl); - let size = variant_layouts[largest_variant_index].size.align_to(align.abi); - - let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { - if i == largest_variant_index { - return true; - } - - layout.largest_niche = None; - - if layout.size <= niche_offset { - // This variant will fit before the niche. - return true; - } - - // Determine if it'll fit after the niche. - let this_align = layout.align.abi; - let this_offset = (niche_offset + niche_size).align_to(this_align); - - if this_offset + layout.size > size { - return false; - } - - // It'll fit, but we need to make some adjustments. - match layout.fields { - FieldsShape::Arbitrary { ref mut offsets, .. } => { - for offset in offsets.iter_mut() { - *offset += this_offset; - } - } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - panic!("Layout of fields should be Arbitrary for variants") - } - } - - // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; - } - layout.size += this_offset; - - true - }); - - if !all_variants_fit { - return None; - } - - let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); - - let others_zst = variant_layouts - .iter_enumerated() - .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); - let same_size = size == variant_layouts[largest_variant_index].size; - let same_align = align == variant_layouts[largest_variant_index].align; - - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited - } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { - // When the total alignment and size match, we can use the - // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { - // Only the niche is guaranteed to be initialised, - // so use union layouts for the other primitive. - if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) - } else { - Abi::ScalarPair(first.to_union(), niche_scalar) - } - } - _ => Abi::Aggregate { sized: true }, - } - } else { - Abi::Aggregate { sized: true } - }; - - let layout = LayoutS { - variants: Variants::Multiple { - tag: niche_scalar, - tag_encoding: TagEncoding::Niche { - untagged_variant: largest_variant_index, - niche_variants, - niche_start, - }, - tag_field: 0, - variants: IndexVec::new(), - }, - fields: FieldsShape::Arbitrary { - offsets: [niche_offset].into(), - memory_index: [0].into(), - }, - abi, - largest_niche, - size, - align, - max_repr_align, - unadjusted_abi_align, - }; - - Some(TmpLayout { layout, variants: variant_layouts }) - }; - - let niche_filling_layout = calculate_niche_filling_layout(); - - let (mut min, mut max) = (i128::MAX, i128::MIN); - let discr_type = repr.discr_type(); - let bits = Integer::from_attr(dl, discr_type).size().bits(); - for (i, mut val) in discriminants { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { - continue; - } - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - val = (val << (128 - bits)) >> (128 - bits); - } - if val < min { - min = val; - } - if val > max { - max = val; - } - } - // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::MAX, i128::MIN) { - min = 0; - max = 0; - } - assert!(min <= max, "discriminant range is {min}...{max}"); - let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); - - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; - - let mut size = Size::ZERO; - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256).unwrap(); - assert_eq!(Integer::for_align(dl, start_align), None); - - // repr(C) on an enum tells us to make a (tag, union) layout, - // so we need to grow the prefix alignment to be at least - // the alignment of the union. (This value is used both for - // determining the alignment of the overall enum, and the - // determining the alignment of the payload after the tag.) - let mut prefix_align = min_ity.align(dl).abi; - if repr.c() { - for fields in variants { - for field in fields { - prefix_align = prefix_align.max(field.align.abi); - } - } - } - - // Create the set of structs that represent each variant. - let mut layout_variants = variants - .iter_enumerated() - .map(|(i, field_layouts)| { - let mut st = self.univariant( - dl, - field_layouts, - repr, - StructKind::Prefixed(min_ity.size(), prefix_align), - )?; - st.variants = Variants::Single { index: i }; - // Find the first field we can't move later - // to make room for a larger discriminant. - for field_idx in st.fields.index_by_increasing_offset() { - let field = &field_layouts[FieldIdx::new(field_idx)]; - if !field.is_1zst() { - start_align = start_align.min(field.align.abi); - break; - } - } - size = cmp::max(size, st.size); - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - Some(st) - }) - .collect::>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); - - // FIXME(oli-obk): deduplicate and harden these checks - if size.bytes() >= dl.obj_size_bound() { - return None; - } - - let typeck_ity = Integer::from_attr(dl, repr.discr_type()); - if typeck_ity < min_ity { - // It is a bug if Layout decided on a greater discriminant size than typeck for - // some reason at this point (based on values discriminant can take on). Mostly - // because this discriminant will be loaded, and then stored into variable of - // type calculated by typeck. Consider such case (a bug): typeck decided on - // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in codegen, in order - // to store this 16-bit discriminant into 8-bit sized temporary some of the - // space necessary to represent would have to be discarded (or layout is wrong - // on thinking it needs 16 bits) - panic!( - "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})" - ); - // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in codegen. - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about its contents and - // won't be so conservative. - - // Use the initial field alignment - let mut ity = if repr.c() || repr.int.is_some() { - min_ity - } else { - Integer::for_align(dl, start_align).unwrap_or(min_ity) - }; - - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = min_ity.size(); - let new_ity_size = ity.size(); - for variant in &mut layout_variants { - match variant.fields { - FieldsShape::Arbitrary { ref mut offsets, .. } => { - for i in offsets { - if *i <= old_ity_size { - assert_eq!(*i, old_ity_size); - *i = new_ity_size; - } - } - // We might be making the struct larger. - if variant.size <= old_ity_size { - variant.size = new_ity_size; - } - } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - panic!("encountered a non-arbitrary layout during enum layout") - } - } - } - } - - let tag_mask = ity.size().unsigned_int_max(); - let tag = Scalar::Initialized { - value: Primitive::Int(ity, signed), - valid_range: WrappingRange { - start: (min as u128 & tag_mask), - end: (max as u128 & tag_mask), - }, - }; - let mut abi = Abi::Aggregate { sized: true }; - - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } else if tag.size(dl) == size { - // Make sure we only use scalar layout when the enum is entirely its - // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); - } else { - // Try to use a ScalarPair for all tagged enums. - // That's possible only if we can find a common primitive type for all variants. - let mut common_prim = None; - let mut common_prim_initialized_in_all_variants = true; - for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { - let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { - panic!("encountered a non-arbitrary layout during enum layout"); - }; - // We skip *all* ZST here and later check if we are good in terms of alignment. - // This lets us handle some cases involving aligned ZST. - let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); - let (field, offset) = match (fields.next(), fields.next()) { - (None, None) => { - common_prim_initialized_in_all_variants = false; - continue; - } - (Some(pair), None) => pair, - _ => { - common_prim = None; - break; - } - }; - let prim = match field.abi { - Abi::Scalar(scalar) => { - common_prim_initialized_in_all_variants &= - matches!(scalar, Scalar::Initialized { .. }); - scalar.primitive() - } - _ => { - common_prim = None; - break; - } - }; - if let Some(pair) = common_prim { - // This is pretty conservative. We could go fancier - // by conflating things like i32 and u32, or even - // realising that (u8, u8) could just cohabit with - // u16 or even u32. - if pair != (prim, offset) { - common_prim = None; - break; - } - } else { - common_prim = Some((prim, offset)); - } - } - if let Some((prim, offset)) = common_prim { - let prim_scalar = if common_prim_initialized_in_all_variants { - let size = prim.size(dl); - assert!(size.bits() <= 128); - Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } - } else { - // Common prim might be uninit. - Scalar::Union { value: prim } - }; - let pair = self.scalar_pair::(tag, prim_scalar); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index.raw, [0, 1]); - offsets - } - _ => panic!("encountered a non-arbitrary layout during enum layout"), - }; - if pair_offsets[FieldIdx::new(0)] == Size::ZERO - && pair_offsets[FieldIdx::new(1)] == *offset - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - } - - // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the - // variants to ensure they are consistent. This is because a downcast is - // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - for variant in &mut layout_variants { - // We only do this for variants with fields; the others are not accessed anyway. - // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; - // Also need to bump up the size and alignment, so that the entire value fits - // in here. - variant.size = cmp::max(variant.size, size); - variant.align.abi = cmp::max(variant.align.abi, align.abi); - } - } - } - - let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - - let tagged_layout = LayoutS { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: 0, - variants: IndexVec::new(), - }, - fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO].into(), - memory_index: [0].into(), - }, - largest_niche, - abi, - align, - size, - max_repr_align, - unadjusted_abi_align, - }; - - let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; - - let mut best_layout = match (tagged_layout, niche_filling_layout) { - (tl, Some(nl)) => { - // Pick the smaller layout; otherwise, - // pick the layout with the larger niche; otherwise, - // pick tagged as it has simpler codegen. - use cmp::Ordering::*; - let niche_size = |tmp_l: &TmpLayout| { - tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) - }; - match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { - (Greater, _) => nl, - (Equal, Less) => nl, - _ => tl, - } - } - (tl, None) => tl, - }; - - // Now we can intern the variant layouts and store them in the enum layout. - best_layout.layout.variants = match best_layout.layout.variants { - Variants::Multiple { tag, tag_encoding, tag_field, .. } => { - Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } - } - Variants::Single { .. } => { - panic!("encountered a single-variant enum during multi-variant layout") - } - }; - Some(best_layout.layout) + layout_of_enum( + self, + repr, + variants, + discr_range_of_repr, + discriminants, + dont_niche_optimize_enum, + dl, + ) } fn layout_of_union< @@ -874,6 +407,493 @@ pub trait LayoutCalculator { } } +fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( + layout_calc: &LC, + repr: &ReprOptions, + variants: &IndexSlice>, + discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), + discriminants: impl Iterator, + dont_niche_optimize_enum: bool, + dl: &TargetDataLayout, +) -> Option> +where + LC: LayoutCalculator + ?Sized, + F: Deref> + fmt::Debug, +{ + // Until we've decided whether to use the tagged or + // niche filling LayoutS, we don't want to intern the + // variant layouts, so we can't store them in the + // overall LayoutS. Store the overall LayoutS + // and the variant LayoutSs here until then. + struct TmpLayout { + layout: LayoutS, + variants: IndexVec>, + } + + let calculate_niche_filling_layout = || -> Option> { + if dont_niche_optimize_enum { + return None; + } + + if variants.len() < 2 { + return None; + } + + let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; + let mut unadjusted_abi_align = align.abi; + + let mut variant_layouts = variants + .iter_enumerated() + .map(|(j, v)| { + let mut st = layout_calc.univariant(dl, v, repr, StructKind::AlwaysSized)?; + st.variants = Variants::Single { index: j }; + + align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); + + Some(st) + }) + .collect::>>()?; + + let largest_variant_index = variant_layouts + .iter_enumerated() + .max_by_key(|(_i, layout)| layout.size.bytes()) + .map(|(i, _layout)| i)?; + + let all_indices = variants.indices(); + let needs_disc = + |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); + let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() + ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); + + let count = + (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; + + // Find the field with the largest niche + let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index] + .iter() + .enumerate() + .filter_map(|(j, field)| Some((j, field.largest_niche?))) + .max_by_key(|(_, niche)| niche.available(dl)) + .and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?; + let niche_offset = + niche.offset + variant_layouts[largest_variant_index].fields.offset(field_index); + let niche_size = niche.value.size(dl); + let size = variant_layouts[largest_variant_index].size.align_to(align.abi); + + let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { + if i == largest_variant_index { + return true; + } + + layout.largest_niche = None; + + if layout.size <= niche_offset { + // This variant will fit before the niche. + return true; + } + + // Determine if it'll fit after the niche. + let this_align = layout.align.abi; + let this_offset = (niche_offset + niche_size).align_to(this_align); + + if this_offset + layout.size > size { + return false; + } + + // It'll fit, but we need to make some adjustments. + match layout.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for offset in offsets.iter_mut() { + *offset += this_offset; + } + } + FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { + panic!("Layout of fields should be Arbitrary for variants") + } + } + + // It can't be a Scalar or ScalarPair because the offset isn't 0. + if !layout.abi.is_uninhabited() { + layout.abi = Abi::Aggregate { sized: true }; + } + layout.size += this_offset; + + true + }); + + if !all_variants_fit { + return None; + } + + let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); + + let others_zst = variant_layouts + .iter_enumerated() + .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); + let same_size = size == variant_layouts[largest_variant_index].size; + let same_align = align == variant_layouts[largest_variant_index].align; + + let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { + Abi::Uninhabited + } else if same_size && same_align && others_zst { + match variant_layouts[largest_variant_index].abi { + // When the total alignment and size match, we can use the + // same ABI as the scalar variant with the reserved niche. + Abi::Scalar(_) => Abi::Scalar(niche_scalar), + Abi::ScalarPair(first, second) => { + // Only the niche is guaranteed to be initialised, + // so use union layouts for the other primitive. + if niche_offset == Size::ZERO { + Abi::ScalarPair(niche_scalar, second.to_union()) + } else { + Abi::ScalarPair(first.to_union(), niche_scalar) + } + } + _ => Abi::Aggregate { sized: true }, + } + } else { + Abi::Aggregate { sized: true } + }; + + let layout = LayoutS { + variants: Variants::Multiple { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { + untagged_variant: largest_variant_index, + niche_variants, + niche_start, + }, + tag_field: 0, + variants: IndexVec::new(), + }, + fields: FieldsShape::Arbitrary { + offsets: [niche_offset].into(), + memory_index: [0].into(), + }, + abi, + largest_niche, + size, + align, + max_repr_align, + unadjusted_abi_align, + }; + + Some(TmpLayout { layout, variants: variant_layouts }) + }; + + let niche_filling_layout = calculate_niche_filling_layout(); + + let (mut min, mut max) = (i128::MAX, i128::MIN); + let discr_type = repr.discr_type(); + let bits = Integer::from_attr(dl, discr_type).size().bits(); + for (i, mut val) in discriminants { + if variants[i].iter().any(|f| f.abi.is_uninhabited()) { + continue; + } + if discr_type.is_signed() { + // sign extend the raw representation to be an i128 + val = (val << (128 - bits)) >> (128 - bits); + } + if val < min { + min = val; + } + if val > max { + max = val; + } + } + // We might have no inhabited variants, so pretend there's at least one. + if (min, max) == (i128::MAX, i128::MIN) { + min = 0; + max = 0; + } + assert!(min <= max, "discriminant range is {min}...{max}"); + let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); + + let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; + let mut unadjusted_abi_align = align.abi; + + let mut size = Size::ZERO; + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256).unwrap(); + assert_eq!(Integer::for_align(dl, start_align), None); + + // repr(C) on an enum tells us to make a (tag, union) layout, + // so we need to grow the prefix alignment to be at least + // the alignment of the union. (This value is used both for + // determining the alignment of the overall enum, and the + // determining the alignment of the payload after the tag.) + let mut prefix_align = min_ity.align(dl).abi; + if repr.c() { + for fields in variants { + for field in fields { + prefix_align = prefix_align.max(field.align.abi); + } + } + } + + // Create the set of structs that represent each variant. + let mut layout_variants = variants + .iter_enumerated() + .map(|(i, field_layouts)| { + let mut st = layout_calc.univariant( + dl, + field_layouts, + repr, + StructKind::Prefixed(min_ity.size(), prefix_align), + )?; + st.variants = Variants::Single { index: i }; + // Find the first field we can't move later + // to make room for a larger discriminant. + for field_idx in st.fields.index_by_increasing_offset() { + let field = &field_layouts[FieldIdx::new(field_idx)]; + if !field.is_1zst() { + start_align = start_align.min(field.align.abi); + break; + } + } + size = cmp::max(size, st.size); + align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); + Some(st) + }) + .collect::>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.align_to(align.abi); + + // FIXME(oli-obk): deduplicate and harden these checks + if size.bytes() >= dl.obj_size_bound() { + return None; + } + + let typeck_ity = Integer::from_attr(dl, repr.discr_type()); + if typeck_ity < min_ity { + // It is a bug if Layout decided on a greater discriminant size than typeck for + // some reason at this point (based on values discriminant can take on). Mostly + // because this discriminant will be loaded, and then stored into variable of + // type calculated by typeck. Consider such case (a bug): typeck decided on + // byte-sized discriminant, but layout thinks we need a 16-bit to store all + // discriminant values. That would be a bug, because then, in codegen, in order + // to store this 16-bit discriminant into 8-bit sized temporary some of the + // space necessary to represent would have to be discarded (or layout is wrong + // on thinking it needs 16 bits) + panic!( + "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})" + ); + // However, it is fine to make discr type however large (as an optimisation) + // after this point – we’ll just truncate the value we load in codegen. + } + + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about its contents and + // won't be so conservative. + + // Use the initial field alignment + let mut ity = if repr.c() || repr.int.is_some() { + min_ity + } else { + Integer::for_align(dl, start_align).unwrap_or(min_ity) + }; + + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = min_ity.size(); + let new_ity_size = ity.size(); + for variant in &mut layout_variants { + match variant.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for i in offsets { + if *i <= old_ity_size { + assert_eq!(*i, old_ity_size); + *i = new_ity_size; + } + } + // We might be making the struct larger. + if variant.size <= old_ity_size { + variant.size = new_ity_size; + } + } + FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { + panic!("encountered a non-arbitrary layout during enum layout") + } + } + } + } + + let tag_mask = ity.size().unsigned_int_max(); + let tag = Scalar::Initialized { + value: Primitive::Int(ity, signed), + valid_range: WrappingRange { + start: (min as u128 & tag_mask), + end: (max as u128 & tag_mask), + }, + }; + let mut abi = Abi::Aggregate { sized: true }; + + if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { + abi = Abi::Uninhabited; + } else if tag.size(dl) == size { + // Make sure we only use scalar layout when the enum is entirely its + // own tag (i.e. it has no padding nor any non-ZST variant fields). + abi = Abi::Scalar(tag); + } else { + // Try to use a ScalarPair for all tagged enums. + // That's possible only if we can find a common primitive type for all variants. + let mut common_prim = None; + let mut common_prim_initialized_in_all_variants = true; + for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { + let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { + panic!("encountered a non-arbitrary layout during enum layout"); + }; + // We skip *all* ZST here and later check if we are good in terms of alignment. + // This lets us handle some cases involving aligned ZST. + let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); + let (field, offset) = match (fields.next(), fields.next()) { + (None, None) => { + common_prim_initialized_in_all_variants = false; + continue; + } + (Some(pair), None) => pair, + _ => { + common_prim = None; + break; + } + }; + let prim = match field.abi { + Abi::Scalar(scalar) => { + common_prim_initialized_in_all_variants &= + matches!(scalar, Scalar::Initialized { .. }); + scalar.primitive() + } + _ => { + common_prim = None; + break; + } + }; + if let Some(pair) = common_prim { + // This is pretty conservative. We could go fancier + // by conflating things like i32 and u32, or even + // realising that (u8, u8) could just cohabit with + // u16 or even u32. + if pair != (prim, offset) { + common_prim = None; + break; + } + } else { + common_prim = Some((prim, offset)); + } + } + if let Some((prim, offset)) = common_prim { + let prim_scalar = if common_prim_initialized_in_all_variants { + let size = prim.size(dl); + assert!(size.bits() <= 128); + Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } + } else { + // Common prim might be uninit. + Scalar::Union { value: prim } + }; + let pair = layout_calc.scalar_pair::(tag, prim_scalar); + let pair_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index.raw, [0, 1]); + offsets + } + _ => panic!("encountered a non-arbitrary layout during enum layout"), + }; + if pair_offsets[FieldIdx::new(0)] == Size::ZERO + && pair_offsets[FieldIdx::new(1)] == *offset + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; + } + } + } + + // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the + // variants to ensure they are consistent. This is because a downcast is + // semantically a NOP, and thus should not affect layout. + if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + for variant in &mut layout_variants { + // We only do this for variants with fields; the others are not accessed anyway. + // Also do not overwrite any already existing "clever" ABIs. + if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { + variant.abi = abi; + // Also need to bump up the size and alignment, so that the entire value fits + // in here. + variant.size = cmp::max(variant.size, size); + variant.align.abi = cmp::max(variant.align.abi, align.abi); + } + } + } + + let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); + + let tagged_layout = LayoutS { + variants: Variants::Multiple { + tag, + tag_encoding: TagEncoding::Direct, + tag_field: 0, + variants: IndexVec::new(), + }, + fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() }, + largest_niche, + abi, + align, + size, + max_repr_align, + unadjusted_abi_align, + }; + + let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; + + let mut best_layout = match (tagged_layout, niche_filling_layout) { + (tl, Some(nl)) => { + // Pick the smaller layout; otherwise, + // pick the layout with the larger niche; otherwise, + // pick tagged as it has simpler codegen. + use cmp::Ordering::*; + let niche_size = |tmp_l: &TmpLayout| { + tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + }; + match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { + (Greater, _) => nl, + (Equal, Less) => nl, + _ => tl, + } + } + (tl, None) => tl, + }; + + // Now we can intern the variant layouts and store them in the enum layout. + best_layout.layout.variants = match best_layout.layout.variants { + Variants::Multiple { tag, tag_encoding, tag_field, .. } => { + Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } + } + Variants::Single { .. } => { + panic!("encountered a single-variant enum during multi-variant layout") + } + }; + Some(best_layout.layout) +} + /// Determines towards which end of a struct layout optimizations will try to place the best niches. enum NicheBias { Start, From 8facfb23c6f6c8f338b80d21b0f01223684f0e44 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 16 Dec 2023 01:56:55 -0800 Subject: [PATCH 006/106] Extract fn layout_of_struct --- compiler/rustc_abi/src/layout.rs | 232 +++++++++++++++++-------------- 1 file changed, 130 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 102bef9f6de3..ec3ab828b719 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -197,109 +197,37 @@ pub trait LayoutCalculator { None => VariantIdx::new(0), }; - let is_struct = !is_enum || - // Only one variant is present. - (present_second.is_none() && - // Representation optimizations are allowed. - !repr.inhibit_enum_layout_opt()); - if is_struct { - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - - let v = present_first; - let kind = if is_enum || variants[v].is_empty() || always_sized { - StructKind::AlwaysSized - } else { - StructKind::MaybeUnsized - }; - - let mut st = self.univariant(dl, &variants[v], repr, kind)?; - st.variants = Variants::Single { index: v }; - - if is_unsafe_cell { - let hide_niches = |scalar: &mut _| match scalar { - Scalar::Initialized { value, valid_range } => { - *valid_range = WrappingRange::full(value.size(dl)) - } - // Already doesn't have any niches - Scalar::Union { .. } => {} - }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { - hide_niches(a); - hide_niches(b); - } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} - } - st.largest_niche = None; - return Some(st); - } - - let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - // Enlarging validity ranges would result in missed - // optimizations, *not* wrongly assuming the inner - // value is valid. e.g. unions already enlarge validity ranges, - // because the values may be uninitialized. - // - // Because of that we only check that the start and end - // of the range is representable with this scalar type. - - let max_value = scalar.size(dl).unsigned_int_max(); - if let Bound::Included(start) = start { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(start <= max_value, "{start} > {max_value}"); - scalar.valid_range_mut().start = start; - } - if let Bound::Included(end) = end { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(end <= max_value, "{end} > {max_value}"); - scalar.valid_range_mut().end = end; - } - - // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); - } - } - None => st.largest_niche = Some(niche), - } - } - } - _ => assert!( - start == Bound::Unbounded && end == Bound::Unbounded, - "nonscalar layout for layout_scalar_valid_range type: {st:#?}", - ), - } - - return Some(st); + // take the struct path if it is an actual struct + if !is_enum || + // or for optimizing univariant enums + (present_second.is_none() && !repr.inhibit_enum_layout_opt()) + { + layout_of_struct( + self, + repr, + variants, + is_enum, + is_unsafe_cell, + scalar_valid_range, + always_sized, + dl, + present_first, + ) + } else { + // At this point, we have handled all unions and + // structs. (We have also handled univariant enums + // that allow representation optimization.) + assert!(is_enum); + layout_of_enum( + self, + repr, + variants, + discr_range_of_repr, + discriminants, + dont_niche_optimize_enum, + dl, + ) } - - // At this point, we have handled all unions and - // structs. (We have also handled univariant enums - // that allow representation optimization.) - assert!(is_enum); - layout_of_enum( - self, - repr, - variants, - discr_range_of_repr, - discriminants, - dont_niche_optimize_enum, - dl, - ) } fn layout_of_union< @@ -407,6 +335,106 @@ pub trait LayoutCalculator { } } +/// single-variant enums are just structs, if you think about it +fn layout_of_struct<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( + layout_calc: &LC, + repr: &ReprOptions, + variants: &IndexSlice>, + is_enum: bool, + is_unsafe_cell: bool, + scalar_valid_range: (Bound, Bound), + always_sized: bool, + dl: &TargetDataLayout, + present_first: VariantIdx, +) -> Option> +where + LC: LayoutCalculator + ?Sized, + F: Deref> + fmt::Debug, +{ + // Struct, or univariant enum equivalent to a struct. + // (Typechecking will reject discriminant-sizing attrs.) + + let v = present_first; + let kind = if is_enum || variants[v].is_empty() || always_sized { + StructKind::AlwaysSized + } else { + StructKind::MaybeUnsized + }; + + let mut st = layout_calc.univariant(dl, &variants[v], repr, kind)?; + st.variants = Variants::Single { index: v }; + + if is_unsafe_cell { + let hide_niches = |scalar: &mut _| match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + }; + match &mut st.abi { + Abi::Uninhabited => {} + Abi::Scalar(scalar) => hide_niches(scalar), + Abi::ScalarPair(a, b) => { + hide_niches(a); + hide_niches(b); + } + Abi::Vector { element, count: _ } => hide_niches(element), + Abi::Aggregate { sized: _ } => {} + } + st.largest_niche = None; + return Some(st); + } + + let (start, end) = scalar_valid_range; + match st.abi { + Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + // Enlarging validity ranges would result in missed + // optimizations, *not* wrongly assuming the inner + // value is valid. e.g. unions already enlarge validity ranges, + // because the values may be uninitialized. + // + // Because of that we only check that the start and end + // of the range is representable with this scalar type. + + let max_value = scalar.size(dl).unsigned_int_max(); + if let Bound::Included(start) = start { + // FIXME(eddyb) this might be incorrect - it doesn't + // account for wrap-around (end < start) ranges. + assert!(start <= max_value, "{start} > {max_value}"); + scalar.valid_range_mut().start = start; + } + if let Bound::Included(end) = end { + // FIXME(eddyb) this might be incorrect - it doesn't + // account for wrap-around (end < start) ranges. + assert!(end <= max_value, "{end} > {max_value}"); + scalar.valid_range_mut().end = end; + } + + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); + } + } + None => st.largest_niche = Some(niche), + } + } + } + _ => assert!( + start == Bound::Unbounded && end == Bound::Unbounded, + "nonscalar layout for layout_scalar_valid_range type: {st:#?}", + ), + } + + Some(st) +} + fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( layout_calc: &LC, repr: &ReprOptions, From 9f7d0e91b528a19a9516df0f647a0191808e7227 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 11 Dec 2023 13:03:35 +0000 Subject: [PATCH 007/106] use Vec for region constraints --- .../src/infer/lexical_region_resolve/mod.rs | 12 ++++++++--- .../infer/region_constraints/leak_check.rs | 8 +++---- .../src/infer/region_constraints/mod.rs | 21 +++++++------------ .../src/traits/auto_trait.rs | 2 +- src/librustdoc/clean/auto_trait.rs | 2 +- .../higher-ranked-lifetime-error.stderr | 4 ++-- .../trait-bounds/hrtb-perfect-forwarding.rs | 2 +- .../hrtb-perfect-forwarding.stderr | 14 +++++++++---- tests/ui/lifetimes/issue-79187-2.stderr | 18 ++++++++++++---- 9 files changed, 50 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index b6e86e2b676d..08e6d35a5f59 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -137,6 +137,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ) -> LexicalRegionResolutions<'tcx> { let mut var_data = self.construct_var_data(); + // Deduplicating constraints is shown to have a positive perf impact. + self.data.constraints.sort_by_key(|(constraint, _)| *constraint); + self.data.constraints.dedup_by_key(|(constraint, _)| *constraint); + if cfg!(debug_assertions) { self.dump_constraints(); } @@ -183,7 +187,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values); // Tracks the changed region vids. let mut changes = Vec::new(); - for constraint in self.data.constraints.keys() { + for (constraint, _) in &self.data.constraints { match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); @@ -678,7 +682,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let dummy_source = graph.add_node(()); let dummy_sink = graph.add_node(()); - for constraint in self.data.constraints.keys() { + for (constraint, _) in &self.data.constraints { match *constraint { Constraint::VarSubVar(a_id, b_id) => { graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint); @@ -885,9 +889,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => { + let constraint_idx = + this.constraints.binary_search_by(|(c, _)| c.cmp(&edge.data)).unwrap(); state.result.push(RegionAndOrigin { region, - origin: this.constraints.get(&edge.data).unwrap().clone(), + origin: this.constraints[constraint_idx].1.clone(), }); } diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index e06596df7b94..b2bcbbf2e53b 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -416,8 +416,8 @@ impl<'tcx> MiniGraph<'tcx> { region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot) { match undo_entry { - AddConstraint(constraint) => { - each_constraint(constraint); + &AddConstraint(i) => { + each_constraint(®ion_constraints.data().constraints[i].0); } &AddVerify(i) => span_bug!( region_constraints.data().verifys[i].origin.span(), @@ -430,8 +430,8 @@ impl<'tcx> MiniGraph<'tcx> { region_constraints .data() .constraints - .keys() - .for_each(|constraint| each_constraint(constraint)); + .iter() + .for_each(|(constraint, _)| each_constraint(constraint)); } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 5c043b1d3dd6..c06adf085aa2 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -20,7 +20,6 @@ use rustc_middle::ty::{ReBound, ReVar}; use rustc_middle::ty::{Region, RegionVid}; use rustc_span::Span; -use std::collections::BTreeMap; use std::ops::Range; use std::{cmp, fmt, mem}; @@ -90,7 +89,7 @@ pub type VarInfos = IndexVec; pub struct RegionConstraintData<'tcx> { /// Constraints of the form `A <= B`, where either `A` or `B` can /// be a region variable (or neither, as it happens). - pub constraints: BTreeMap, SubregionOrigin<'tcx>>, + pub constraints: Vec<(Constraint<'tcx>, SubregionOrigin<'tcx>)>, /// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that /// `R0` must be equal to one of the regions `R1..Rn`. These occur @@ -273,7 +272,7 @@ pub(crate) enum UndoLog<'tcx> { AddVar(RegionVid), /// We added the given `constraint`. - AddConstraint(Constraint<'tcx>), + AddConstraint(usize), /// We added the given `verify`. AddVerify(usize), @@ -319,8 +318,9 @@ impl<'tcx> RegionConstraintStorage<'tcx> { self.var_infos.pop().unwrap(); assert_eq!(self.var_infos.len(), vid.index()); } - AddConstraint(ref constraint) => { - self.data.constraints.remove(constraint); + AddConstraint(index) => { + self.data.constraints.pop().unwrap(); + assert_eq!(self.data.constraints.len(), index); } AddVerify(index) => { self.data.verifys.pop(); @@ -443,14 +443,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // cannot add constraints once regions are resolved debug!("RegionConstraintCollector: add_constraint({:?})", constraint); - // never overwrite an existing (constraint, origin) - only insert one if it isn't - // present in the map yet. This prevents origins from outside the snapshot being - // replaced with "less informative" origins e.g., during calls to `can_eq` - let undo_log = &mut self.undo_log; - self.storage.data.constraints.entry(constraint).or_insert_with(|| { - undo_log.push(AddConstraint(constraint)); - origin - }); + let index = self.storage.data.constraints.len(); + self.storage.data.constraints.push((constraint, origin)); + self.undo_log.push(AddConstraint(index)); } fn add_verify(&mut self, verify: Verify<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 13a09917c033..c6d029ddb650 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -477,7 +477,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let mut vid_map: FxHashMap, RegionDeps<'cx>> = FxHashMap::default(); let mut finished_map = FxHashMap::default(); - for constraint in regions.constraints.keys() { + for (constraint, _) in ®ions.constraints { match constraint { &Constraint::VarSubVar(r1, r2) => { { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index e692f4ef72ea..9de547ba6dce 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -195,7 +195,7 @@ where // into a map. Each RegionTarget (either a RegionVid or a Region) maps // to its smaller and larger regions. Note that 'larger' regions correspond // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region). - for constraint in regions.constraints.keys() { + for (constraint, _) in ®ions.constraints { match *constraint { Constraint::VarSubVar(r1, r2) => { { diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr index d0892fd8b095..c25e731d9627 100644 --- a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr +++ b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | assert_all::<_, &String>(id); | ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected reference `&String` - found reference `&String` + = note: expected trait `for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>` + found trait `for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs index d45fa183c0c4..07befeff43cb 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs @@ -41,7 +41,7 @@ where // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. foo_hrtb_bar_not(&mut t); - //~^ ERROR implementation of `Bar` is not general enough + //~^ ERROR mismatched types //~^^ ERROR lifetime may not live long enough } diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 727b9e6bec8e..14a80630f408 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr @@ -53,14 +53,19 @@ note: due to current limitations in the borrow checker, this implies a `'static` LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, | ^^^^^^^^^^^^^^^^^^^^^^ -error: implementation of `Bar` is not general enough +error[E0308]: mismatched types --> $DIR/hrtb-perfect-forwarding.rs:43:5 | LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... - = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` + = note: expected trait `for<'a> >` + found trait `for<'a> >` +note: the lifetime requirement is introduced here + --> $DIR/hrtb-perfect-forwarding.rs:37:8 + | +LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, + | ^^^^^^^^^^^^^^^^^^^^^^ warning: function cannot return without recursing --> $DIR/hrtb-perfect-forwarding.rs:48:1 @@ -77,3 +82,4 @@ LL | foo_hrtb_bar_hrtb(&mut t); error: aborting due to 2 previous errors; 4 warnings emitted +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index e8115bb6b064..0b7593f01c61 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -54,8 +54,13 @@ error[E0308]: mismatched types LL | take_foo(|a: &i32| a); | ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected reference `&_` - found reference `&_` + = note: expected trait `for<'a> <{closure@$DIR/issue-79187-2.rs:11:14: 11:23} as FnOnce<(&'a i32,)>>` + found trait `for<'a> <{closure@$DIR/issue-79187-2.rs:11:14: 11:23} as FnOnce<(&'a i32,)>>` +note: this closure does not fulfill the lifetime requirements + --> $DIR/issue-79187-2.rs:11:14 + | +LL | take_foo(|a: &i32| a); + | ^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-79187-2.rs:5:21 | @@ -68,8 +73,13 @@ error[E0308]: mismatched types LL | take_foo(|a: &i32| -> &i32 { a }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected reference `&_` - found reference `&_` + = note: expected trait `for<'a> <{closure@$DIR/issue-79187-2.rs:14:14: 14:31} as FnOnce<(&'a i32,)>>` + found trait `for<'a> <{closure@$DIR/issue-79187-2.rs:14:14: 14:31} as FnOnce<(&'a i32,)>>` +note: this closure does not fulfill the lifetime requirements + --> $DIR/issue-79187-2.rs:14:14 + | +LL | take_foo(|a: &i32| -> &i32 { a }); + | ^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-79187-2.rs:5:21 | From 8c215e7841c486f5f460d541bbc1773933266475 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sun, 17 Dec 2023 06:08:24 +0000 Subject: [PATCH 008/106] fix diagnostic regresssion --- .../src/diagnostics/bound_region_errors.rs | 19 ++++++++++++------- .../trait-bounds/hrtb-perfect-forwarding.rs | 2 +- .../hrtb-perfect-forwarding.stderr | 14 ++++---------- tests/ui/lifetimes/issue-79187-2.stderr | 18 ++++-------------- 4 files changed, 21 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 924e68fa91da..60dbf7dc055b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -408,13 +408,18 @@ fn try_extract_error_from_region_constraints<'tcx>( mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, ) -> Option> { + let placeholder_universe = match placeholder_region.kind() { + ty::RePlaceholder(p) => p.universe, + ty::ReVar(vid) => universe_of_region(vid), + _ => ty::UniverseIndex::ROOT, + }; let matches = |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) { (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, _ => a_region == b_region, }; - let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| { - match *constraint { + let mut check = + |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { Constraint::RegSubReg(sub, sup) if ((exact && sup == placeholder_region) || (!exact && matches(sup, placeholder_region))) @@ -422,16 +427,16 @@ fn try_extract_error_from_region_constraints<'tcx>( { Some((sub, cause.clone())) } - // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) - if ((exact && sup == placeholder_region) - || (!exact && matches(sup, placeholder_region))) => + if (exact + && sup == placeholder_region + && !universe_of_region(vid).can_name(placeholder_universe)) + || (!exact && matches(sup, placeholder_region)) => { Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) } _ => None, - } - }; + }; let mut info = region_constraints .constraints .iter() diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs index 07befeff43cb..d45fa183c0c4 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.rs @@ -41,7 +41,7 @@ where // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. foo_hrtb_bar_not(&mut t); - //~^ ERROR mismatched types + //~^ ERROR implementation of `Bar` is not general enough //~^^ ERROR lifetime may not live long enough } diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 14a80630f408..727b9e6bec8e 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr @@ -53,19 +53,14 @@ note: due to current limitations in the borrow checker, this implies a `'static` LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types +error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 | LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | - = note: expected trait `for<'a> >` - found trait `for<'a> >` -note: the lifetime requirement is introduced here - --> $DIR/hrtb-perfect-forwarding.rs:37:8 - | -LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` warning: function cannot return without recursing --> $DIR/hrtb-perfect-forwarding.rs:48:1 @@ -82,4 +77,3 @@ LL | foo_hrtb_bar_hrtb(&mut t); error: aborting due to 2 previous errors; 4 warnings emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 0b7593f01c61..e8115bb6b064 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -54,13 +54,8 @@ error[E0308]: mismatched types LL | take_foo(|a: &i32| a); | ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> <{closure@$DIR/issue-79187-2.rs:11:14: 11:23} as FnOnce<(&'a i32,)>>` - found trait `for<'a> <{closure@$DIR/issue-79187-2.rs:11:14: 11:23} as FnOnce<(&'a i32,)>>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-79187-2.rs:11:14 - | -LL | take_foo(|a: &i32| a); - | ^^^^^^^^^ + = note: expected reference `&_` + found reference `&_` note: the lifetime requirement is introduced here --> $DIR/issue-79187-2.rs:5:21 | @@ -73,13 +68,8 @@ error[E0308]: mismatched types LL | take_foo(|a: &i32| -> &i32 { a }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> <{closure@$DIR/issue-79187-2.rs:14:14: 14:31} as FnOnce<(&'a i32,)>>` - found trait `for<'a> <{closure@$DIR/issue-79187-2.rs:14:14: 14:31} as FnOnce<(&'a i32,)>>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-79187-2.rs:14:14 - | -LL | take_foo(|a: &i32| -> &i32 { a }); - | ^^^^^^^^^^^^^^^^^ + = note: expected reference `&_` + found reference `&_` note: the lifetime requirement is introduced here --> $DIR/issue-79187-2.rs:5:21 | From cea683c08f775f980e5e8de408ea3b47235329c7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 14:00:17 +1100 Subject: [PATCH 009/106] Use `.into_diagnostic()` less. This commit replaces this pattern: ``` err.into_diagnostic(dcx) ``` with this pattern: ``` dcx.create_err(err) ``` in a lot of places. It's a little shorter, makes the error level explicit, avoids some `IntoDiagnostic` imports, and is a necessary prerequisite for the next commit which will add a `level` arg to `into_diagnostic`. This requires adding `track_caller` on `create_err` to avoid mucking up the output of `tests/ui/track-diagnostics/track4.rs`. It probably should have been there already. --- compiler/rustc_errors/src/lib.rs | 1 + compiler/rustc_expand/src/base.rs | 5 +- .../infer/error_reporting/need_type_info.rs | 31 ++++----- .../src/infer/error_reporting/note.rs | 36 +++++----- compiler/rustc_parse/src/parser/attr.rs | 7 +- .../rustc_parse/src/parser/diagnostics.rs | 22 +++---- compiler/rustc_parse/src/parser/expr.rs | 66 ++++++++++--------- compiler/rustc_parse/src/parser/item.rs | 16 ++--- compiler/rustc_parse/src/parser/mod.rs | 9 +-- .../rustc_parse/src/parser/nonterminal.rs | 22 +++---- compiler/rustc_parse/src/parser/pat.rs | 11 ++-- compiler/rustc_parse/src/parser/path.rs | 7 +- compiler/rustc_query_system/src/query/job.rs | 6 +- 13 files changed, 109 insertions(+), 130 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 959e26fec70f..763de78451ec 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1274,6 +1274,7 @@ impl DiagCtxt { self.create_err(err).emit() } + #[track_caller] pub fn create_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b63609c48e91..5aeb5e61cd78 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1204,11 +1204,10 @@ pub fn resolve_path( .expect("attempting to resolve a file path in an external file"), FileName::DocTest(path, _) => path, other => { - return Err(errors::ResolveRelativePath { + return Err(parse_sess.dcx.create_err(errors::ResolveRelativePath { span, path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(), - } - .into_diagnostic(&parse_sess.dcx)); + })); } }; result.pop(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 817a4451dd13..700fb5d35109 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -5,7 +5,6 @@ use crate::errors::{ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::IntoDiagnostic; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -367,7 +366,7 @@ impl<'tcx> InferCtxt<'tcx> { let multi_suggestions = Vec::new(); let bad_label = Some(arg_data.make_bad_error(span)); match error_code { - TypeAnnotationNeeded::E0282 => AnnotationRequired { + TypeAnnotationNeeded::E0282 => self.tcx.sess.dcx().create_err(AnnotationRequired { span, source_kind, source_name, @@ -375,9 +374,8 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, - } - .into_diagnostic(self.tcx.sess.dcx()), - TypeAnnotationNeeded::E0283 => AmbiguousImpl { + }), + TypeAnnotationNeeded::E0283 => self.tcx.sess.dcx().create_err(AmbiguousImpl { span, source_kind, source_name, @@ -385,9 +383,8 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, - } - .into_diagnostic(self.tcx.sess.dcx()), - TypeAnnotationNeeded::E0284 => AmbiguousReturn { + }), + TypeAnnotationNeeded::E0284 => self.tcx.sess.dcx().create_err(AmbiguousReturn { span, source_kind, source_name, @@ -395,8 +392,7 @@ impl<'tcx> InferCtxt<'tcx> { infer_subdiags, multi_suggestions, bad_label, - } - .into_diagnostic(self.tcx.sess.dcx()), + }), } } } @@ -574,7 +570,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } match error_code { - TypeAnnotationNeeded::E0282 => AnnotationRequired { + TypeAnnotationNeeded::E0282 => self.tcx.sess.dcx().create_err(AnnotationRequired { span, source_kind, source_name: &name, @@ -582,9 +578,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - } - .into_diagnostic(self.tcx.sess.dcx()), - TypeAnnotationNeeded::E0283 => AmbiguousImpl { + }), + TypeAnnotationNeeded::E0283 => self.tcx.sess.dcx().create_err(AmbiguousImpl { span, source_kind, source_name: &name, @@ -592,9 +587,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - } - .into_diagnostic(self.tcx.sess.dcx()), - TypeAnnotationNeeded::E0284 => AmbiguousReturn { + }), + TypeAnnotationNeeded::E0284 => self.tcx.sess.dcx().create_err(AmbiguousReturn { span, source_kind, source_name: &name, @@ -602,8 +596,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - } - .into_diagnostic(self.tcx.sess.dcx()), + }), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 859c10ef1420..1f1c2bc20e2e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -5,9 +5,7 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; -use rustc_errors::{ - AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, -}; +use rustc_errors::{AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; @@ -136,11 +134,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::PrefixKind::ContentValidFor, note_and_explain::SuffixKind::Empty, ); - OutlivesContent { + self.tcx.sess.dcx().create_err(OutlivesContent { span, notes: reference_valid.into_iter().chain(content_valid).collect(), - } - .into_diagnostic(self.tcx.sess.dcx()) + }) } infer::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( @@ -157,11 +154,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::PrefixKind::SourcePointerValidFor, note_and_explain::SuffixKind::Empty, ); - OutlivesBound { + self.tcx.sess.dcx().create_err(OutlivesBound { span, notes: object_valid.into_iter().chain(pointer_valid).collect(), - } - .into_diagnostic(self.tcx.sess.dcx()) + }) } infer::RelateParamBound(span, ty, opt_span) => { let prefix = match *sub { @@ -176,8 +172,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let note = note_and_explain::RegionExplanation::new( self.tcx, sub, opt_span, prefix, suffix, ); - FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } - .into_diagnostic(self.tcx.sess.dcx()) + self.tcx.sess.dcx().create_err(FulfillReqLifetime { + span, + ty: self.resolve_vars_if_possible(ty), + note, + }) } infer::RelateRegionParamBound(span) => { let param_instantiated = note_and_explain::RegionExplanation::new( @@ -194,11 +193,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::PrefixKind::LfParamMustOutlive, note_and_explain::SuffixKind::Empty, ); - LfBoundNotSatisfied { + self.tcx.sess.dcx().create_err(LfBoundNotSatisfied { span, notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), - } - .into_diagnostic(self.tcx.sess.dcx()) + }) } infer::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( @@ -215,12 +213,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::PrefixKind::DataValidFor, note_and_explain::SuffixKind::Empty, ); - RefLongerThanData { + self.tcx.sess.dcx().create_err(RefLongerThanData { span, ty: self.resolve_vars_if_possible(ty), notes: pointer_valid.into_iter().chain(data_valid).collect(), - } - .into_diagnostic(self.tcx.sess.dcx()) + }) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { let mut err = self.report_extra_impl_obligation( @@ -277,11 +274,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_and_explain::PrefixKind::LfMustOutlive, note_and_explain::SuffixKind::Empty, ); - LfBoundNotSatisfied { + self.tcx.sess.dcx().create_err(LfBoundNotSatisfied { span, notes: instantiated.into_iter().chain(must_outlive).collect(), - } - .into_diagnostic(self.tcx.sess.dcx()) + }) } }; if sub.is_error() || sup.is_error() { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 56e52baf98b0..53b29eccc2cd 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -5,7 +5,7 @@ use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter, Nonterminal}; -use rustc_errors::{error_code, Diagnostic, IntoDiagnostic, PResult}; +use rustc_errors::{error_code, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -416,8 +416,9 @@ impl<'a> Parser<'a> { Err(err) => err.cancel(), } - Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() } - .into_diagnostic(self.dcx())) + Err(self + .dcx() + .create_err(InvalidMetaItem { span: self.token.span, token: self.token.clone() })) } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9e3637ea9f34..fb31815c3021 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -35,7 +35,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, PResult, + DiagnosticMessage, ErrorGuaranteed, FatalError, MultiSpan, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -280,11 +280,10 @@ impl<'a> Parser<'a> { recover: bool, ) -> PResult<'a, (Ident, /* is_raw */ bool)> { if let TokenKind::DocComment(..) = self.prev_token.kind { - return Err(DocCommentDoesNotDocumentAnything { + return Err(self.dcx().create_err(DocCommentDoesNotDocumentAnything { span: self.prev_token.span, missing_comma: None, - } - .into_diagnostic(self.dcx())); + })); } let valid_follow = &[ @@ -347,7 +346,7 @@ impl<'a> Parser<'a> { suggest_remove_comma, help_cannot_start_number, }; - let mut err = err.into_diagnostic(self.dcx()); + let mut err = self.dcx().create_err(err); // if the token we have is a `<` // it *might* be a misplaced generic @@ -1410,7 +1409,7 @@ impl<'a> Parser<'a> { // Not entirely sure now, but we bubble the error up with the // suggestion. self.restore_snapshot(snapshot); - Err(err.into_diagnostic(self.dcx())) + Err(self.dcx().create_err(err)) } } } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind { @@ -1425,7 +1424,7 @@ impl<'a> Parser<'a> { } // Consume the fn call arguments. match self.consume_fn_args() { - Err(()) => Err(err.into_diagnostic(self.dcx())), + Err(()) => Err(self.dcx().create_err(err)), Ok(()) => { self.sess.emit_err(err); // FIXME: actually check that the two expressions in the binop are @@ -1451,7 +1450,7 @@ impl<'a> Parser<'a> { mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } else { // These cases cause too many knock-down errors, bail out (#61329). - Err(err.into_diagnostic(self.dcx())) + Err(self.dcx().create_err(err)) } }; } @@ -2539,7 +2538,7 @@ impl<'a> Parser<'a> { Ok(Some(GenericArg::Const(self.parse_const_arg()?))) } else { let after_kw_const = self.token.span; - self.recover_const_arg(after_kw_const, err.into_diagnostic(self.dcx())).map(Some) + self.recover_const_arg(after_kw_const, self.dcx().create_err(err)).map(Some) } } @@ -2893,11 +2892,10 @@ impl<'a> Parser<'a> { let (a_span, b_span) = (a.span(), b.span()); let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo()); if self.span_to_snippet(between_span).as_deref() == Ok(":: ") { - return Err(DoubleColonInBound { + return Err(self.dcx().create_err(DoubleColonInBound { span: path.span.shrink_to_hi(), between: between_span, - } - .into_diagnostic(self.dcx())); + })); } } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cd3e8b92f2f9..a21a15338480 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -26,8 +26,8 @@ use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - PResult, StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult, + StashKey, }; use rustc_macros::Subdiagnostic; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; @@ -1255,21 +1255,21 @@ impl<'a> Parser<'a> { // that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different. self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")") { - let mut replacement_err = errors::ParenthesesWithStructFields { - span, - r#type: path, - braces_for_struct: errors::BracesForStructLiteral { - first: open_paren, - second: close_paren, - }, - no_fields_for_fn: errors::NoFieldsForFnCall { - fields: fields - .into_iter() - .map(|field| field.span.until(field.expr.span)) - .collect(), - }, - } - .into_diagnostic(self.dcx()); + let mut replacement_err = + self.dcx().create_err(errors::ParenthesesWithStructFields { + span, + r#type: path, + braces_for_struct: errors::BracesForStructLiteral { + first: open_paren, + second: close_paren, + }, + no_fields_for_fn: errors::NoFieldsForFnCall { + fields: fields + .into_iter() + .map(|field| field.span.until(field.expr.span)) + .collect(), + }, + }); replacement_err.emit(); let old_err = mem::replace(err, replacement_err); @@ -1883,8 +1883,7 @@ impl<'a> Parser<'a> { self.bump(); // `#` let Some((ident, false)) = self.token.ident() else { - let err = - errors::ExpectedBuiltinIdent { span: self.token.span }.into_diagnostic(self.dcx()); + let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span }); return Err(err); }; self.sess.gated_spans.gate(sym::builtin_syntax, ident.span); @@ -1894,8 +1893,10 @@ impl<'a> Parser<'a> { let ret = if let Some(res) = parse(self, lo, ident)? { Ok(res) } else { - let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name } - .into_diagnostic(self.dcx()); + let err = self.dcx().create_err(errors::UnknownBuiltinConstruct { + span: lo.to(ident.span), + name: ident.name, + }); return Err(err); }; self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?; @@ -1958,8 +1959,9 @@ impl<'a> Parser<'a> { && let token::NtExpr(e) | token::NtLiteral(e) = &nt.0 && matches!(e.kind, ExprKind::Err) { - let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } - .into_diagnostic(self.dcx()); + let mut err = self + .dcx() + .create_err(errors::InvalidInterpolatedExpression { span: self.token.span }); err.downgrade_to_delayed_bug(); return Err(err); } @@ -2168,10 +2170,10 @@ impl<'a> Parser<'a> { .span_to_snippet(snapshot.token.span) .is_ok_and(|snippet| snippet == "]") => { - return Err(errors::MissingSemicolonBeforeArray { + return Err(self.dcx().create_err(errors::MissingSemicolonBeforeArray { open_delim: open_delim_span, semicolon: prev_span.shrink_to_hi(), - }.into_diagnostic(self.dcx())); + })); } Ok(_) => (), Err(err) => err.cancel(), @@ -2318,8 +2320,9 @@ impl<'a> Parser<'a> { // Check for `move async` and recover if self.check_keyword(kw::Async) { let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); - Err(errors::AsyncMoveOrderIncorrect { span: move_async_span } - .into_diagnostic(self.dcx())) + Err(self + .dcx() + .create_err(errors::AsyncMoveOrderIncorrect { span: move_async_span })) } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } @@ -2509,7 +2512,7 @@ impl<'a> Parser<'a> { }; if self.prev_token.kind == token::BinOp(token::Or) { // This was part of a closure, the that part of the parser recover. - return Err(err.into_diagnostic(self.dcx())); + return Err(self.dcx().create_err(err)); } else { Some(self.sess.emit_err(err)) } @@ -3193,7 +3196,7 @@ impl<'a> Parser<'a> { fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; if self.eat_keyword(kw::Catch) { - Err(errors::CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.dcx())) + Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span })) } else { let span = span_lo.to(body.span); self.sess.gated_spans.gate(sym::try_blocks, span); @@ -3530,12 +3533,11 @@ impl<'a> Parser<'a> { || t == &token::CloseDelim(Delimiter::Parenthesis) }); if is_wrong { - return Err(errors::ExpectedStructField { + return Err(this.dcx().create_err(errors::ExpectedStructField { span: this.look_ahead(1, |t| t.span), ident_span: this.token.span, token: this.look_ahead(1, |t| t.clone()), - } - .into_diagnostic(&self.sess.dcx)); + })); } let (ident, expr) = if is_shorthand { // Mimic `x: x` for the `x` field shorthand. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bf619daba501..32c5bef7c8e1 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -10,10 +10,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; use rustc_ast_pretty::pprust; -use rustc_errors::{ - struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, - StashKey, -}; +use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; use rustc_span::source_map; @@ -438,7 +435,7 @@ impl<'a> Parser<'a> { None }; - if let Some(err) = err { Err(err.into_diagnostic(self.dcx())) } else { Ok(()) } + if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) } } fn parse_item_builtin(&mut self) -> PResult<'a, Option> { @@ -1373,8 +1370,7 @@ impl<'a> Parser<'a> { }; let span = self.prev_token.span.shrink_to_hi(); - let err: DiagnosticBuilder<'_, ErrorGuaranteed> = - errors::MissingConstType { span, colon, kind }.into_diagnostic(self.dcx()); + let err = self.dcx().create_err(errors::MissingConstType { span, colon, kind }); err.stash(span, StashKey::ItemNoType); // The user intended that the type be inferred, @@ -1391,7 +1387,7 @@ impl<'a> Parser<'a> { self.bump(); self.sess.emit_err(err); } else { - return Err(err.into_diagnostic(self.dcx())); + return Err(self.dcx().create_err(err)); } } @@ -1591,7 +1587,7 @@ impl<'a> Parser<'a> { } else { let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); - return Err(err.into_diagnostic(self.dcx())); + return Err(self.dcx().create_err(err)); }; Ok((class_name, ItemKind::Struct(vdata, generics))) @@ -1787,7 +1783,7 @@ impl<'a> Parser<'a> { let sp = previous_span.shrink_to_hi(); err.missing_comma = Some(sp); } - return Err(err.into_diagnostic(self.dcx())); + return Err(self.dcx().create_err(err)); } } _ => { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b91432f10c8f..0ab2adb404af 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -32,9 +32,7 @@ use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::PResult; -use rustc_errors::{ - Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, -}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -1500,14 +1498,13 @@ pub(crate) fn make_unclosed_delims_error( if let Some(sp) = unmatched.unclosed_span { spans.push(sp); }; - let err = MismatchedClosingDelimiter { + let err = sess.dcx.create_err(MismatchedClosingDelimiter { spans, delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(), unmatched: unmatched.found_span, opening_candidate: unmatched.candidate_span, unclosed: unmatched.unclosed_span, - } - .into_diagnostic(&sess.dcx); + }); Some(err) } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 301a88cd0776..071d6b72f3b9 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -2,7 +2,6 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; -use rustc_errors::IntoDiagnostic; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; @@ -114,9 +113,9 @@ impl<'a> Parser<'a> { NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { Some(item) => NtItem(item), None => { - return Err( - UnexpectedNonterminal::Item(self.token.span).into_diagnostic(self.dcx()) - ); + return Err(self + .dcx() + .create_err(UnexpectedNonterminal::Item(self.token.span))); } }, NonterminalKind::Block => { @@ -127,8 +126,9 @@ impl<'a> Parser<'a> { NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { Some(s) => NtStmt(P(s)), None => { - return Err(UnexpectedNonterminal::Statement(self.token.span) - .into_diagnostic(self.dcx())); + return Err(self + .dcx() + .create_err(UnexpectedNonterminal::Statement(self.token.span))); } }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { @@ -160,11 +160,10 @@ impl<'a> Parser<'a> { NtIdent(ident, is_raw) } NonterminalKind::Ident => { - return Err(UnexpectedNonterminal::Ident { + return Err(self.dcx().create_err(UnexpectedNonterminal::Ident { span: self.token.span, token: self.token.clone(), - } - .into_diagnostic(self.dcx())); + })); } NonterminalKind::Path => { NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) @@ -178,11 +177,10 @@ impl<'a> Parser<'a> { if self.check_lifetime() { NtLifetime(self.expect_lifetime().ident) } else { - return Err(UnexpectedNonterminal::Lifetime { + return Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, token: self.token.clone(), - } - .into_diagnostic(self.dcx())); + })); } } }; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 80233eddb9b7..d32582fd43d3 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -18,7 +18,7 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -872,8 +872,9 @@ impl<'a> Parser<'a> { // binding mode then we do not end up here, because the lookahead // will direct us over to `parse_enum_variant()`. if self.token == token::OpenDelim(Delimiter::Parenthesis) { - return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span } - .into_diagnostic(self.dcx())); + return Err(self + .dcx() + .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); } Ok(PatKind::Ident(binding_annotation, ident, sub)) @@ -986,8 +987,8 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { - let mut err = ExpectedCommaAfterPatternField { span: self.token.span } - .into_diagnostic(self.dcx()); + let mut err = + self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span }); if let Some(mut delayed) = delayed_err { delayed.emit(); } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 3b92a9119835..8970a99f1b7d 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -9,7 +9,7 @@ use rustc_ast::{ AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, Path, PathSegment, QSelf, }; -use rustc_errors::{Applicability, IntoDiagnostic, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span}; use std::mem; @@ -318,15 +318,14 @@ impl<'a> Parser<'a> { }) { err.cancel(); - err = PathSingleColon { + err = self.dcx().create_err(PathSingleColon { span: self.token.span, type_ascription: self .sess .unstable_features .is_nightly_build() .then_some(()), - } - .into_diagnostic(self.dcx()); + }); } // Attempt to find places where a missing `>` might belong. else if let Some(arg) = args diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 2a34ffb75f2c..0561fd147a91 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -4,9 +4,7 @@ use crate::query::plumbing::CycleError; use crate::query::DepKind; use crate::query::{QueryContext, QueryStackFrame}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, Level, -}; +use rustc_errors::{DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Level}; use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::Span; @@ -604,7 +602,7 @@ pub(crate) fn report_cycle<'a>( note_span: (), }; - cycle_diag.into_diagnostic(sess.dcx()) + sess.dcx().create_err(cycle_diag) } pub fn print_query_stack( From 18251c480b37c96db2d93ce79c138754d4e28904 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Dec 2023 08:11:25 +1100 Subject: [PATCH 010/106] Remove unnecessary `use` items in derived `IntoDiagnostic` impls. Presumably these are a hangover from an earlier time when they were necessary. --- compiler/rustc_macros/src/diagnostics/diagnostic.rs | 2 -- compiler/rustc_macros/src/diagnostics/subdiagnostic.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 5de0203fc1db..76ef2c264a8f 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -92,7 +92,6 @@ impl<'a> DiagnosticDerive<'a> { self, #dcx: &'_sess rustc_errors::DiagCtxt ) -> rustc_errors::DiagnosticBuilder<'_sess, G> { - use rustc_errors::IntoDiagnosticArg; #implementation } } @@ -177,7 +176,6 @@ impl<'a> LintDiagnosticDerive<'a> { self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> ) { - use rustc_errors::IntoDiagnosticArg; #implementation; } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 0f9e68cdc501..663abecb67c6 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -94,7 +94,6 @@ impl SubdiagnosticDeriveBuilder { rustc_errors::SubdiagnosticMessage ) -> rustc_errors::SubdiagnosticMessage, { - use rustc_errors::{Applicability, IntoDiagnosticArg}; #implementation } } From 31df50c8973aeb70fcf42b403239f4fc4712988c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Dec 2023 08:27:37 +1100 Subject: [PATCH 011/106] Streamline `Diagnostic` proc macro. First, it is parameterized by the name of the diagnostic and the DiagCtxt. These are given to `session_diagnostic_derive` and `lint_diagnostic_derive`. But the names are hard-wired as "diag" and "handler" (should be "dcx"), and there's no clear reason for the parameterization. So this commit removes the parameterization and hard-wires the names internally. Once that is done `DiagnosticDeriveBuilder` is reduced to a trivial wrapper around `DiagnosticDeriveKind`, and can be removed. Also, `DiagnosticDerive` and `LintDiagnosticDerive` don't need the `builder` field, because it has been reduced to a kind, and they know their own kind. This avoids the need for some `let`/`else`/`unreachable!` kind checks And `DiagnosticDeriveVariantBuilder` no longer needs a lifetime, because the `parent` field is changed to `kind`, which is now a trivial copy type. --- .../src/diagnostics/diagnostic.rs | 53 +++++--------- .../src/diagnostics/diagnostic_builder.rs | 70 +++++++------------ compiler/rustc_macros/src/diagnostics/mod.rs | 5 +- 3 files changed, 45 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 76ef2c264a8f..be8582d0ba07 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; -use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind}; +use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind; use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; use crate::diagnostics::utils::SetOnce; use proc_macro2::TokenStream; @@ -13,32 +13,21 @@ use synstructure::Structure; /// The central struct for constructing the `into_diagnostic` method from an annotated struct. pub(crate) struct DiagnosticDerive<'a> { structure: Structure<'a>, - builder: DiagnosticDeriveBuilder, } impl<'a> DiagnosticDerive<'a> { - pub(crate) fn new(diag: syn::Ident, dcx: syn::Ident, structure: Structure<'a>) -> Self { - Self { - builder: DiagnosticDeriveBuilder { - diag, - kind: DiagnosticDeriveKind::Diagnostic { dcx }, - }, - structure, - } + pub(crate) fn new(structure: Structure<'a>) -> Self { + Self { structure } } pub(crate) fn into_tokens(self) -> TokenStream { - let DiagnosticDerive { mut structure, mut builder } = self; - + let DiagnosticDerive { mut structure } = self; + let kind = DiagnosticDeriveKind::Diagnostic; let slugs = RefCell::new(Vec::new()); - let implementation = builder.each_variant(&mut structure, |mut builder, variant| { + let implementation = kind.each_variant(&mut structure, |mut builder, variant| { let preamble = builder.preamble(variant); let body = builder.body(variant); - let diag = &builder.parent.diag; - let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.parent.kind else { - unreachable!() - }; let init = match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") @@ -62,7 +51,7 @@ impl<'a> DiagnosticDerive<'a> { Some(slug) => { slugs.borrow_mut().push(slug.clone()); quote! { - let mut #diag = #dcx.struct_diagnostic(crate::fluent_generated::#slug); + let mut diag = dcx.struct_diagnostic(crate::fluent_generated::#slug); } } }; @@ -73,12 +62,10 @@ impl<'a> DiagnosticDerive<'a> { #formatting_init #preamble #body - #diag + diag } }); - let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.kind else { unreachable!() }; - // A lifetime of `'a` causes conflicts, but `_sess` is fine. let mut imp = structure.gen_impl(quote! { gen impl<'_sess, G> @@ -90,7 +77,7 @@ impl<'a> DiagnosticDerive<'a> { #[track_caller] fn into_diagnostic( self, - #dcx: &'_sess rustc_errors::DiagCtxt + dcx: &'_sess rustc_errors::DiagCtxt ) -> rustc_errors::DiagnosticBuilder<'_sess, G> { #implementation } @@ -106,36 +93,31 @@ impl<'a> DiagnosticDerive<'a> { /// The central struct for constructing the `decorate_lint` method from an annotated struct. pub(crate) struct LintDiagnosticDerive<'a> { structure: Structure<'a>, - builder: DiagnosticDeriveBuilder, } impl<'a> LintDiagnosticDerive<'a> { - pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self { - Self { - builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic }, - structure, - } + pub(crate) fn new(structure: Structure<'a>) -> Self { + Self { structure } } pub(crate) fn into_tokens(self) -> TokenStream { - let LintDiagnosticDerive { mut structure, mut builder } = self; - - let implementation = builder.each_variant(&mut structure, |mut builder, variant| { + let LintDiagnosticDerive { mut structure } = self; + let kind = DiagnosticDeriveKind::LintDiagnostic; + let implementation = kind.each_variant(&mut structure, |mut builder, variant| { let preamble = builder.preamble(variant); let body = builder.body(variant); - let diag = &builder.parent.diag; let formatting_init = &builder.formatting_init; quote! { #preamble #formatting_init #body - #diag + diag } }); let slugs = RefCell::new(Vec::new()); - let msg = builder.each_variant(&mut structure, |mut builder, variant| { + let msg = kind.each_variant(&mut structure, |mut builder, variant| { // Collect the slug by generating the preamble. let _ = builder.preamble(variant); @@ -168,13 +150,12 @@ impl<'a> LintDiagnosticDerive<'a> { } }); - let diag = &builder.diag; let mut imp = structure.gen_impl(quote! { gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self { #[track_caller] fn decorate_lint<'__b>( self, - #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> + diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> ) { #implementation; } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 511654d99499..f3e98d68b604 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -17,28 +17,18 @@ use synstructure::{BindingInfo, Structure, VariantInfo}; use super::utils::SubdiagnosticVariant; /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub(crate) enum DiagnosticDeriveKind { - Diagnostic { dcx: syn::Ident }, + Diagnostic, LintDiagnostic, } -/// Tracks persistent information required for the entire type when building up individual calls to -/// diagnostic methods for generated diagnostic derives - both `Diagnostic` for -/// fatal/errors/warnings and `LintDiagnostic` for lints. -pub(crate) struct DiagnosticDeriveBuilder { - /// The identifier to use for the generated `DiagnosticBuilder` instance. - pub diag: syn::Ident, - /// Kind of diagnostic that should be derived. - pub kind: DiagnosticDeriveKind, -} - /// Tracks persistent information required for a specific variant when building up individual calls /// to diagnostic methods for generated diagnostic derives - both `Diagnostic` for /// fatal/errors/warnings and `LintDiagnostic` for lints. -pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> { - /// The parent builder for the entire type. - pub parent: &'parent DiagnosticDeriveBuilder, +pub(crate) struct DiagnosticDeriveVariantBuilder { + /// The kind for the entire type. + pub kind: DiagnosticDeriveKind, /// Initialization of format strings for code suggestions. pub formatting_init: TokenStream, @@ -59,19 +49,19 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> { pub code: SpannedOption<()>, } -impl<'a> HasFieldMap for DiagnosticDeriveVariantBuilder<'a> { +impl HasFieldMap for DiagnosticDeriveVariantBuilder { fn get_field_binding(&self, field: &String) -> Option<&TokenStream> { self.field_map.get(field) } } -impl DiagnosticDeriveBuilder { +impl DiagnosticDeriveKind { /// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the /// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions /// or attributes on the type itself when input is an enum. - pub(crate) fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> TokenStream + pub(crate) fn each_variant<'s, F>(self, structure: &mut Structure<'s>, f: F) -> TokenStream where - F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream, + F: for<'v> Fn(DiagnosticDeriveVariantBuilder, &VariantInfo<'v>) -> TokenStream, { let ast = structure.ast(); let span = ast.span().unwrap(); @@ -101,7 +91,7 @@ impl DiagnosticDeriveBuilder { _ => variant.ast().ident.span().unwrap(), }; let builder = DiagnosticDeriveVariantBuilder { - parent: self, + kind: self, span, field_map: build_field_mapping(variant), formatting_init: TokenStream::new(), @@ -119,7 +109,7 @@ impl DiagnosticDeriveBuilder { } } -impl<'a> DiagnosticDeriveVariantBuilder<'a> { +impl DiagnosticDeriveVariantBuilder { /// Generates calls to `code` and similar functions based on the attributes on the type or /// variant. pub(crate) fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { @@ -184,8 +174,6 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { &mut self, attr: &Attribute, ) -> Result { - let diag = &self.parent.diag; - // Always allow documentation comments. if is_doc_comment(attr) { return Ok(quote! {}); @@ -223,7 +211,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { let code = nested.parse::()?; tokens.extend(quote! { - #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); + diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }); } else { span_err(path.span().unwrap(), "unknown argument") @@ -257,8 +245,6 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { } fn generate_field_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { - let diag = &self.parent.diag; - let field = binding_info.ast(); let mut field_binding = binding_info.binding.clone(); field_binding.set_span(field.ty.span()); @@ -267,7 +253,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { let ident = format_ident!("{}", ident); // strip `r#` prefix, if present quote! { - #diag.set_arg( + diag.set_arg( stringify!(#ident), #field_binding ); @@ -322,8 +308,6 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { info: FieldInfo<'_>, binding: TokenStream, ) -> Result { - let diag = &self.parent.diag; - let ident = &attr.path().segments.last().unwrap().ident; let name = ident.to_string(); match (&attr.meta, name.as_str()) { @@ -331,12 +315,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { // `set_arg` call will not be generated. (Meta::Path(_), "skip_arg") => return Ok(quote! {}), (Meta::Path(_), "primary_span") => { - match self.parent.kind { - DiagnosticDeriveKind::Diagnostic { .. } => { + match self.kind { + DiagnosticDeriveKind::Diagnostic => { report_error_if_not_applied_to_span(attr, &info)?; return Ok(quote! { - #diag.set_span(#binding); + diag.set_span(#binding); }); } DiagnosticDeriveKind::LintDiagnostic => { @@ -348,13 +332,13 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { } (Meta::Path(_), "subdiagnostic") => { if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() { - let DiagnosticDeriveKind::Diagnostic { dcx } = &self.parent.kind else { + let DiagnosticDeriveKind::Diagnostic = self.kind else { // No eager translation for lints. - return Ok(quote! { #diag.subdiagnostic(#binding); }); + return Ok(quote! { diag.subdiagnostic(#binding); }); }; - return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); }); + return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); }); } else { - return Ok(quote! { #diag.subdiagnostic(#binding); }); + return Ok(quote! { diag.subdiagnostic(#binding); }); } } (Meta::List(meta_list), "subdiagnostic") => { @@ -376,15 +360,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(quote! {}); } - let dcx = match &self.parent.kind { - DiagnosticDeriveKind::Diagnostic { dcx } => dcx, + match &self.kind { + DiagnosticDeriveKind::Diagnostic => {} DiagnosticDeriveKind::LintDiagnostic => { throw_invalid_attr!(attr, |diag| { diag.help("eager subdiagnostics are not supported on lints") }) } }; - return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); }); + return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); }); } _ => (), } @@ -442,7 +426,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { self.formatting_init.extend(code_init); Ok(quote! { - #diag.span_suggestions_with_style( + diag.span_suggestions_with_style( #span_field, crate::fluent_generated::#slug, #code_field, @@ -463,10 +447,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { kind: &Ident, fluent_attr_identifier: Path, ) -> TokenStream { - let diag = &self.parent.diag; let fn_name = format_ident!("span_{}", kind); quote! { - #diag.#fn_name( + diag.#fn_name( #field_binding, crate::fluent_generated::#fluent_attr_identifier ); @@ -476,9 +459,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug /// and `fluent_attr_identifier`. fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream { - let diag = &self.parent.diag; quote! { - #diag.#kind(crate::fluent_generated::#fluent_attr_identifier); + diag.#kind(crate::fluent_generated::#fluent_attr_identifier); } } diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index a536eb3b04e6..d3a4e7ba7d19 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -6,7 +6,6 @@ mod utils; use diagnostic::{DiagnosticDerive, LintDiagnosticDerive}; use proc_macro2::TokenStream; -use quote::format_ident; use subdiagnostic::SubdiagnosticDeriveBuilder; use synstructure::Structure; @@ -57,7 +56,7 @@ use synstructure::Structure; /// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`: /// pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { - DiagnosticDerive::new(format_ident!("diag"), format_ident!("handler"), s).into_tokens() + DiagnosticDerive::new(s).into_tokens() } /// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct, @@ -103,7 +102,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: /// pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { - LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens() + LintDiagnosticDerive::new(s).into_tokens() } /// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and From e7724a2e319f112ee6a97999976d8225b009456e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 14:12:39 +1100 Subject: [PATCH 012/106] Add `level` arg to `into_diagnostic`. And make all hand-written `IntoDiagnostic` impls generic, by using `DiagnosticBuilder::new(dcx, level, ...)` instead of e.g. `dcx.struct_err(...)`. This means the `create_*` functions are the source of the error level. This change will let us remove `struct_diagnostic`. Note: `#[rustc_lint_diagnostics]` is added to `DiagnosticBuilder::new`, it's necessary to pass diagnostics tests now that it's used in `into_diagnostic` functions. --- .../rustc_attr/src/session_diagnostics.rs | 27 +++--- compiler/rustc_builtin_macros/src/errors.rs | 20 ++-- compiler/rustc_codegen_gcc/src/errors.rs | 14 ++- compiler/rustc_codegen_llvm/src/errors.rs | 27 +++--- compiler/rustc_codegen_ssa/src/errors.rs | 95 ++++++++++--------- compiler/rustc_const_eval/src/errors.rs | 7 +- .../rustc_errors/src/diagnostic_builder.rs | 28 +++--- compiler/rustc_errors/src/diagnostic_impls.rs | 39 +++++--- compiler/rustc_errors/src/lib.rs | 12 +-- compiler/rustc_hir_analysis/src/errors.rs | 16 ++-- .../src/diagnostics/diagnostic.rs | 9 +- compiler/rustc_metadata/src/errors.rs | 31 +++--- compiler/rustc_middle/src/ty/layout.rs | 11 ++- compiler/rustc_mir_build/src/errors.rs | 17 ++-- compiler/rustc_mir_transform/src/errors.rs | 8 +- compiler/rustc_monomorphize/src/errors.rs | 13 +-- compiler/rustc_parse/src/errors.rs | 80 +++++++++------- compiler/rustc_passes/src/errors.rs | 74 ++++++--------- compiler/rustc_session/src/errors.rs | 12 ++- compiler/rustc_session/src/parse.rs | 10 +- compiler/rustc_symbol_mangling/src/errors.rs | 11 +-- compiler/rustc_trait_selection/src/errors.rs | 12 ++- .../ui-fulldeps/internal-lints/diagnostics.rs | 16 ++-- .../internal-lints/diagnostics.stderr | 6 +- 24 files changed, 307 insertions(+), 288 deletions(-) diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index ce8e04defb2d..fd2b08668673 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -2,7 +2,8 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, + error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + Level, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -50,14 +51,12 @@ pub(crate) struct UnknownMetaItem<'a> { } // Manual implementation to be able to format `expected` items correctly. -impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); - let mut diag = dcx.struct_span_err_with_code( - self.span, - fluent::attr_unknown_meta_item, - error_code!(E0541), - ); + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item); + diag.set_span(self.span); + diag.code(error_code!(E0541)); diag.set_arg("item", self.item); diag.set_arg("expected", expected.join(", ")); diag.span_label(self.span, fluent::attr_label); @@ -200,10 +199,11 @@ pub(crate) struct UnsupportedLiteral { pub start_point_span: Span, } -impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut diag = dcx.struct_span_err_with_code( - self.span, +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, match self.reason { UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, @@ -214,8 +214,9 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { fluent::attr_unsupported_literal_deprecated_kv_pair } }, - error_code!(E0565), ); + diag.set_span(self.span); + diag.code(error_code!(E0565)); if self.is_bytestr { diag.span_suggestion( self.start_point_span, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 6ffeb401453b..e07eb2e490b7 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - AddToDiagnostic, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, - SingleLabelManySpans, + AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, + MultiSpan, SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -446,14 +446,14 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" )] - let mut diag = dcx.struct_err(self.msg_from_user.to_string()); + let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string()); diag.set_span(self.span); diag } @@ -801,9 +801,13 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec, } -impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut diag = dcx.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg); +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, + crate::fluent_generated::builtin_macros_asm_clobber_no_reg, + ); diag.set_span(self.spans.clone()); // eager translation as `span_labels` takes `AsRef` let lbl1 = dcx.eagerly_translate_to_string( diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 766d90cf7240..1b1ed0b411c7 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - IntoDiagnosticArg, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + IntoDiagnosticArg, Level, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -111,9 +111,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { #[help(codegen_gcc_missing_features)] pub(crate) struct MissingFeatures; -impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); +impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, + fluent::codegen_gcc_target_feature_disable_or_enable + ); if let Some(span) = self.span { diag.set_span(span); }; diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 671a225259a2..6b7e38a6cb12 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -4,9 +4,7 @@ use std::path::Path; use crate::fluent_generated as fluent; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{ - DiagCtxt, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, IntoDiagnostic, -}; +use rustc_errors::{DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -101,13 +99,14 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, FatalError> { - let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(dcx); +impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(dcx, level); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); - let mut diag = dcx.struct_almost_fatal(fluent::codegen_llvm_parse_target_machine_config); + let mut diag = + DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config); diag.set_arg("error", message); diag } @@ -123,9 +122,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { #[help(codegen_llvm_missing_features)] pub(crate) struct MissingFeatures; -impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); +impl IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, + fluent::codegen_llvm_target_feature_disable_or_enable, + ); if let Some(span) = self.span { diag.set_span(span); }; @@ -184,7 +187,7 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); impl IntoDiagnostic<'_, G> for WithLlvmError<'_> { - fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, G> { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, @@ -201,7 +204,7 @@ impl IntoDiagnostic<'_, G> for WithLlvmError<'_> { PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, }; - let mut diag = self.0.into_diagnostic(dcx); + let mut diag = self.0.into_diagnostic(dcx, level); diag.set_primary_message(msg_with_llvm_err); diag.set_arg("llvm_err", self.1); diag diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 668d39afbda7..2b628d2aa69b 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -4,8 +4,8 @@ use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - IntoDiagnosticArg, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + IntoDiagnosticArg, Level, }; use rustc_macros::Diagnostic; use rustc_middle::ty::layout::LayoutError; @@ -209,192 +209,193 @@ pub enum LinkRlibError { pub struct ThorinErrorWrapper(pub thorin::Error); -impl IntoDiagnostic<'_> for ThorinErrorWrapper { - fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { +impl IntoDiagnostic<'_, G> for ThorinErrorWrapper { + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let build = |msg| DiagnosticBuilder::new(dcx, level, msg); let mut diag; match self.0 { thorin::Error::ReadInput(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_read_input_failure); + diag = build(fluent::codegen_ssa_thorin_read_input_failure); diag } thorin::Error::ParseFileKind(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind); + diag = build(fluent::codegen_ssa_thorin_parse_input_file_kind); diag } thorin::Error::ParseObjectFile(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file); + diag = build(fluent::codegen_ssa_thorin_parse_input_object_file); diag } thorin::Error::ParseArchiveFile(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file); + diag = build(fluent::codegen_ssa_thorin_parse_input_archive_file); diag } thorin::Error::ParseArchiveMember(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_archive_member); + diag = build(fluent::codegen_ssa_thorin_parse_archive_member); diag } thorin::Error::InvalidInputKind => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind); + diag = build(fluent::codegen_ssa_thorin_invalid_input_kind); diag } thorin::Error::DecompressData(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_decompress_data); + diag = build(fluent::codegen_ssa_thorin_decompress_data); diag } thorin::Error::NamelessSection(_, offset) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_without_name); + diag = build(fluent::codegen_ssa_thorin_section_without_name); diag.set_arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::RelocationWithInvalidSymbol(section, offset) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); + diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::MultipleRelocations(section, offset) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_relocations); + diag = build(fluent::codegen_ssa_thorin_multiple_relocations); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::UnsupportedRelocation(section, offset) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation); + diag = build(fluent::codegen_ssa_thorin_unsupported_relocation); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::MissingDwoName(id) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name); + diag = build(fluent::codegen_ssa_thorin_missing_dwo_name); diag.set_arg("id", format!("0x{id:08x}")); diag } thorin::Error::NoCompilationUnits => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_compilation_units); + diag = build(fluent::codegen_ssa_thorin_no_compilation_units); diag } thorin::Error::NoDie => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_die); + diag = build(fluent::codegen_ssa_thorin_no_die); diag } thorin::Error::TopLevelDieNotUnit => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit); + diag = build(fluent::codegen_ssa_thorin_top_level_die_not_unit); diag } thorin::Error::MissingRequiredSection(section) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_required_section); + diag = build(fluent::codegen_ssa_thorin_missing_required_section); diag.set_arg("section", section); diag } thorin::Error::ParseUnitAbbreviations(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations); + diag = build(fluent::codegen_ssa_thorin_parse_unit_abbreviations); diag } thorin::Error::ParseUnitAttribute(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute); + diag = build(fluent::codegen_ssa_thorin_parse_unit_attribute); diag } thorin::Error::ParseUnitHeader(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_header); + diag = build(fluent::codegen_ssa_thorin_parse_unit_header); diag } thorin::Error::ParseUnit(_) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit); + diag = build(fluent::codegen_ssa_thorin_parse_unit); diag } thorin::Error::IncompatibleIndexVersion(section, format, actual) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version); + diag = build(fluent::codegen_ssa_thorin_incompatible_index_version); diag.set_arg("section", section); diag.set_arg("actual", actual); diag.set_arg("format", format); diag } thorin::Error::OffsetAtIndex(_, index) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_offset_at_index); + diag = build(fluent::codegen_ssa_thorin_offset_at_index); diag.set_arg("index", index); diag } thorin::Error::StrAtOffset(_, offset) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_str_at_offset); + diag = build(fluent::codegen_ssa_thorin_str_at_offset); diag.set_arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::ParseIndex(_, section) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_index); + diag = build(fluent::codegen_ssa_thorin_parse_index); diag.set_arg("section", section); diag } thorin::Error::UnitNotInIndex(unit) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index); + diag = build(fluent::codegen_ssa_thorin_unit_not_in_index); diag.set_arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::RowNotInIndex(_, row) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_row_not_in_index); + diag = build(fluent::codegen_ssa_thorin_row_not_in_index); diag.set_arg("row", row); diag } thorin::Error::SectionNotInRow => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_not_in_row); + diag = build(fluent::codegen_ssa_thorin_section_not_in_row); diag } thorin::Error::EmptyUnit(unit) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_empty_unit); + diag = build(fluent::codegen_ssa_thorin_empty_unit); diag.set_arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::MultipleDebugInfoSection => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section); + diag = build(fluent::codegen_ssa_thorin_multiple_debug_info_section); diag } thorin::Error::MultipleDebugTypesSection => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section); + diag = build(fluent::codegen_ssa_thorin_multiple_debug_types_section); diag } thorin::Error::NotSplitUnit => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_split_unit); + diag = build(fluent::codegen_ssa_thorin_not_split_unit); diag } thorin::Error::DuplicateUnit(unit) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_duplicate_unit); + diag = build(fluent::codegen_ssa_thorin_duplicate_unit); diag.set_arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::MissingReferencedUnit(unit) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit); + diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit); diag.set_arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::NoOutputObjectCreated => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_output_object_created); + diag = build(fluent::codegen_ssa_thorin_not_output_object_created); diag } thorin::Error::MixedInputEncodings => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings); + diag = build(fluent::codegen_ssa_thorin_mixed_input_encodings); diag } thorin::Error::Io(e) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_io); + diag = build(fluent::codegen_ssa_thorin_io); diag.set_arg("error", format!("{e}")); diag } thorin::Error::ObjectRead(e) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_read); + diag = build(fluent::codegen_ssa_thorin_object_read); diag.set_arg("error", format!("{e}")); diag } thorin::Error::ObjectWrite(e) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_write); + diag = build(fluent::codegen_ssa_thorin_object_write); diag.set_arg("error", format!("{e}")); diag } thorin::Error::GimliRead(e) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_read); + diag = build(fluent::codegen_ssa_thorin_gimli_read); diag.set_arg("error", format!("{e}")); diag } thorin::Error::GimliWrite(e) => { - diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_write); + diag = build(fluent::codegen_ssa_thorin_gimli_write); diag.set_arg("error", format!("{e}")); diag } @@ -410,9 +411,9 @@ pub struct LinkingFailed<'a> { pub escaped_output: String, } -impl IntoDiagnostic<'_> for LinkingFailed<'_> { - fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::codegen_ssa_linking_failed); +impl IntoDiagnostic<'_, G> for LinkingFailed<'_> { + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_ssa_linking_failed); diag.set_arg("linker_path", format!("{}", self.linker_path.display())); diag.set_arg("exit_status", format!("{}", self.exit_status)); diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index adce1f5430f4..eb9bf52676aa 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, - IntoDiagnostic, + IntoDiagnostic, Level, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -875,7 +875,10 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { | InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::ConstPropNonsense => {} InvalidProgramInfo::Layout(e) => { - let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(dcx); + // The level doesn't matter, `diag` is consumed without it being used. + let dummy_level = Level::Bug; + let diag: DiagnosticBuilder<'_, ()> = + e.into_diagnostic().into_diagnostic(dcx, dummy_level); for (name, val) in diag.args() { builder.set_arg(name.clone(), val.clone()); } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 3f66af1fcff2..0079fa8b9953 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -21,7 +21,7 @@ use std::thread::panicking; pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G>; + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>; } impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned @@ -29,8 +29,8 @@ where T: IntoDiagnostic<'a, G>, G: EmissionGuarantee, { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G> { - let mut diag = self.node.into_diagnostic(dcx); + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = self.node.into_diagnostic(dcx, level); diag.set_span(self.span); diag } @@ -339,16 +339,10 @@ impl DerefMut for DiagnosticBuilder<'_, G> { } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`DiagCtxt`]. + #[rustc_lint_diagnostics] #[track_caller] - pub(crate) fn new>( - dcx: &'a DiagCtxt, - level: Level, - message: M, - ) -> Self { - let diagnostic = Diagnostic::new(level, message); - Self::new_diagnostic(dcx, diagnostic) + pub fn new>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self { + Self::new_diagnostic(dcx, Diagnostic::new(level, message)) } /// Creates a new `DiagnosticBuilder` with an already constructed @@ -400,15 +394,15 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// later stage of the compiler. The diagnostic can be accessed with /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`]. /// - /// As with `buffer`, this is unless the handler has disabled such buffering. + /// As with `buffer`, this is unless the dcx has disabled such buffering. pub fn stash(self, span: Span, key: StashKey) { - if let Some((diag, handler)) = self.into_diagnostic() { - handler.stash_diagnostic(span, key, diag); + if let Some((diag, dcx)) = self.into_diagnostic() { + dcx.stash_diagnostic(span, key, diag); } } /// Converts the builder to a `Diagnostic` for later emission, - /// unless handler has disabled such buffering, or `.emit()` was called. + /// unless dcx has disabled such buffering, or `.emit()` was called. pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> { let dcx = match self.inner.state { // No `.emit()` calls, the `&DiagCtxt` is still available. @@ -449,7 +443,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } /// Buffers the diagnostic for later emission, - /// unless handler has disabled such buffering. + /// unless dcx has disabled such buffering. pub fn buffer(self, buffered_diagnostics: &mut Vec) { buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag)); } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 3e4b3ee758a8..ccc951543d8e 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,10 +1,12 @@ use crate::diagnostic::DiagnosticLocation; use crate::{fluent_generated as fluent, AddToDiagnostic}; -use crate::{DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnostic, IntoDiagnosticArg}; +use crate::{ + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + IntoDiagnosticArg, Level, +}; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; -use rustc_lint_defs::Level; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::Span; @@ -216,7 +218,7 @@ impl IntoDiagnosticArg for ast::Visibility { } } -impl IntoDiagnosticArg for Level { +impl IntoDiagnosticArg for rustc_lint_defs::Level { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Borrowed(self.to_cmd_flag())) } @@ -245,19 +247,20 @@ impl IntoDiagnosticArg for hir::def::Res { } } -impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { - fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, !> { +impl IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> { + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag; match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { - diag = dcx.struct_fatal(fluent::errors_target_invalid_address_space); + diag = + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space); diag.set_arg("addr_space", addr_space); diag.set_arg("cause", cause); diag.set_arg("err", err); diag } TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { - diag = dcx.struct_fatal(fluent::errors_target_invalid_bits); + diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits); diag.set_arg("kind", kind); diag.set_arg("bit", bit); diag.set_arg("cause", cause); @@ -265,31 +268,39 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { diag } TargetDataLayoutErrors::MissingAlignment { cause } => { - diag = dcx.struct_fatal(fluent::errors_target_missing_alignment); + diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment); diag.set_arg("cause", cause); diag } TargetDataLayoutErrors::InvalidAlignment { cause, err } => { - diag = dcx.struct_fatal(fluent::errors_target_invalid_alignment); + diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment); diag.set_arg("cause", cause); diag.set_arg("err_kind", err.diag_ident()); diag.set_arg("align", err.align()); diag } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { - diag = dcx.struct_fatal(fluent::errors_target_inconsistent_architecture); + diag = DiagnosticBuilder::new( + dcx, + level, + fluent::errors_target_inconsistent_architecture, + ); diag.set_arg("dl", dl); diag.set_arg("target", target); diag } TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { - diag = dcx.struct_fatal(fluent::errors_target_inconsistent_pointer_width); + diag = DiagnosticBuilder::new( + dcx, + level, + fluent::errors_target_inconsistent_pointer_width, + ); diag.set_arg("pointer_size", pointer_size); diag.set_arg("target", target); diag } TargetDataLayoutErrors::InvalidBitsSize { err } => { - diag = dcx.struct_fatal(fluent::errors_target_invalid_bits_size); + diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size); diag.set_arg("err", err); diag } @@ -362,9 +373,9 @@ impl IntoDiagnosticArg for Backtrace { pub struct InvalidFlushedDelayedDiagnosticLevel { #[primary_span] pub span: Span, - pub level: rustc_errors::Level, + pub level: Level, } -impl IntoDiagnosticArg for rustc_errors::Level { +impl IntoDiagnosticArg for Level { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::from(self.to_string())) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 763de78451ec..5027f63a9704 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1279,14 +1279,14 @@ impl DiagCtxt { &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(self) + err.into_diagnostic(self, Level::Error { lint: false }) } pub fn create_warning<'a>( &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self) + warning.into_diagnostic(self, Level::Warning(None)) } pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { @@ -1297,7 +1297,7 @@ impl DiagCtxt { &'a self, fatal: impl IntoDiagnostic<'a, FatalError>, ) -> DiagnosticBuilder<'a, FatalError> { - fatal.into_diagnostic(self) + fatal.into_diagnostic(self, Level::Fatal) } pub fn emit_almost_fatal<'a>( @@ -1311,7 +1311,7 @@ impl DiagCtxt { &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !> { - fatal.into_diagnostic(self) + fatal.into_diagnostic(self, Level::Fatal) } pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { @@ -1322,7 +1322,7 @@ impl DiagCtxt { &'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>, ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> { - bug.into_diagnostic(self) + bug.into_diagnostic(self, Level::Bug) } pub fn emit_bug<'a>( @@ -1340,7 +1340,7 @@ impl DiagCtxt { &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted> { - note.into_diagnostic(self) + note.into_diagnostic(self, Level::Note) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f461b6a94ece..41f30057902b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,8 +2,8 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - MultiSpan, + error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + Level, MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -315,14 +315,12 @@ pub struct MissingTypeParams { } // Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`. -impl<'a> IntoDiagnostic<'a> for MissingTypeParams { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { #[track_caller] - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = dcx.struct_span_err_with_code( - self.span, - fluent::hir_analysis_missing_type_params, - error_code!(E0393), - ); + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params); + err.set_span(self.span); + err.code(error_code!(E0393)); err.set_arg("parameterCount", self.missing_type_params.len()); err.set_arg( "parameters", diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index be8582d0ba07..027c97330b11 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -51,7 +51,11 @@ impl<'a> DiagnosticDerive<'a> { Some(slug) => { slugs.borrow_mut().push(slug.clone()); quote! { - let mut diag = dcx.struct_diagnostic(crate::fluent_generated::#slug); + let mut diag = rustc_errors::DiagnosticBuilder::new( + dcx, + level, + crate::fluent_generated::#slug + ); } } }; @@ -77,7 +81,8 @@ impl<'a> DiagnosticDerive<'a> { #[track_caller] fn into_diagnostic( self, - dcx: &'_sess rustc_errors::DiagCtxt + dcx: &'_sess rustc_errors::DiagCtxt, + level: rustc_errors::Level ) -> rustc_errors::DiagnosticBuilder<'_sess, G> { #implementation } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 206c15edd78f..e13068cb6f9e 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -3,7 +3,9 @@ use std::{ path::{Path, PathBuf}, }; -use rustc_errors::{error_code, ErrorGuaranteed, IntoDiagnostic}; +use rustc_errors::{ + error_code, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, +}; use rustc_macros::Diagnostic; use rustc_session::config; use rustc_span::{sym, Span, Symbol}; @@ -495,12 +497,9 @@ pub(crate) struct MultipleCandidates { pub candidates: Vec, } -impl IntoDiagnostic<'_> for MultipleCandidates { - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::metadata_multiple_candidates); +impl IntoDiagnostic<'_, G> for MultipleCandidates { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates); diag.set_arg("crate_name", self.crate_name); diag.set_arg("flavor", self.flavor); diag.code(error_code!(E0464)); @@ -593,13 +592,10 @@ pub struct InvalidMetadataFiles { pub crate_rejections: Vec, } -impl IntoDiagnostic<'_> for InvalidMetadataFiles { +impl IntoDiagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::metadata_invalid_meta_files); + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files); diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); diag.code(error_code!(E0786)); @@ -623,13 +619,10 @@ pub struct CannotFindCrate { pub is_ui_testing: bool, } -impl IntoDiagnostic<'_> for CannotFindCrate { +impl IntoDiagnostic<'_, G> for CannotFindCrate { #[track_caller] - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::metadata_cannot_find_crate); + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_cannot_find_crate); diag.set_arg("crate_name", self.crate_name); diag.set_arg("current_crate", self.current_crate); diag.set_arg("add_info", self.add_info); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 225dd217807d..5ae758edfa33 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,7 +5,8 @@ use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, ConstKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagnosticMessage; use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnostic, IntoDiagnosticArg, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + IntoDiagnosticArg, Level, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -1272,14 +1273,14 @@ pub enum FnAbiError<'tcx> { AdjustForForeignAbi(call::AdjustForForeignAbiError), } -impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, !> { +impl<'a, 'b, G: EmissionGuarantee> IntoDiagnostic<'a, G> for FnAbiError<'b> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { match self { - Self::Layout(e) => e.into_diagnostic().into_diagnostic(dcx), + Self::Layout(e) => e.into_diagnostic().into_diagnostic(dcx, level), Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported { arch, abi, - }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(dcx), + }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(dcx, level), } } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index db2624cac024..0f6d8c362031 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,7 +2,7 @@ use crate::fluent_generated as fluent; use rustc_errors::DiagnosticArgValue; use rustc_errors::{ error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, + ErrorGuaranteed, IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -461,13 +461,18 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { } impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_span_err_with_code( - self.span, + fn into_diagnostic( + self, + dcx: &'a DiagCtxt, + level: Level, + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, fluent::mir_build_non_exhaustive_patterns_type_not_empty, - error_code!(E0004), ); - + diag.set_span(self.span); + diag.code(error_code!(E0004)); let peeled_ty = self.ty.peel_refs(); diag.set_arg("ty", self.ty); diag.set_arg("peeled_ty", peeled_ty); diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index fd4af31501c3..17916e16daf4 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_errors::{ Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, - DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, + DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; @@ -62,10 +62,10 @@ pub(crate) struct RequiresUnsafe { // so we need to eagerly translate the label here, which isn't supported by the derive API // We could also exhaustively list out the primary messages for all unsafe violations, // but this would result in a lot of duplication. -impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for RequiresUnsafe { #[track_caller] - fn into_diagnostic(self, dcx: &'sess DiagCtxt) -> DiagnosticBuilder<'sess, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::mir_transform_requires_unsafe); + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.set_span(self.span); diag.span_label(self.span, self.details.label()); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 247b22455839..592e71251b8b 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -1,8 +1,7 @@ use std::path::PathBuf; use crate::fluent_generated as fluent; -use rustc_errors::ErrorGuaranteed; -use rustc_errors::IntoDiagnostic; +use rustc_errors::{DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level}; use rustc_macros::{Diagnostic, LintDiagnostic}; use rustc_span::{Span, Symbol}; @@ -47,13 +46,11 @@ pub struct UnusedGenericParamsHint { pub param_names: Vec, } -impl IntoDiagnostic<'_> for UnusedGenericParamsHint { +impl IntoDiagnostic<'_, G> for UnusedGenericParamsHint { #[track_caller] - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::monomorphize_unused_generic_params); + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = + DiagnosticBuilder::new(dcx, level, fluent::monomorphize_unused_generic_params); diag.set_span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { // FIXME: I can figure out how to do a label with a fluent string with a fixed message, diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 008adcc83d0e..8ccfcb625a62 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2,7 +2,10 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; -use rustc_errors::{AddToDiagnostic, Applicability, ErrorGuaranteed, IntoDiagnostic}; +use rustc_errors::{ + AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, + Level, SubdiagnosticMessage, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -1042,23 +1045,30 @@ impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier { #[track_caller] fn into_diagnostic( self, - dcx: &'a rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { + dcx: &'a DiagCtxt, + level: Level, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); - let mut diag = dcx.struct_err(match token_descr { - Some(TokenDescription::ReservedIdentifier) => { - fluent::parse_expected_identifier_found_reserved_identifier_str - } - Some(TokenDescription::Keyword) => fluent::parse_expected_identifier_found_keyword_str, - Some(TokenDescription::ReservedKeyword) => { - fluent::parse_expected_identifier_found_reserved_keyword_str - } - Some(TokenDescription::DocComment) => { - fluent::parse_expected_identifier_found_doc_comment_str - } - None => fluent::parse_expected_identifier_found_str, - }); + let mut diag = DiagnosticBuilder::new( + dcx, + level, + match token_descr { + Some(TokenDescription::ReservedIdentifier) => { + fluent::parse_expected_identifier_found_reserved_identifier_str + } + Some(TokenDescription::Keyword) => { + fluent::parse_expected_identifier_found_keyword_str + } + Some(TokenDescription::ReservedKeyword) => { + fluent::parse_expected_identifier_found_reserved_keyword_str + } + Some(TokenDescription::DocComment) => { + fluent::parse_expected_identifier_found_doc_comment_str + } + None => fluent::parse_expected_identifier_found_str, + }, + ); diag.set_span(self.span); diag.set_arg("token", self.token); @@ -1099,21 +1109,28 @@ impl<'a> IntoDiagnostic<'a> for ExpectedSemi { #[track_caller] fn into_diagnostic( self, - dcx: &'a rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { + dcx: &'a DiagCtxt, + level: Level, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); - let mut diag = dcx.struct_err(match token_descr { - Some(TokenDescription::ReservedIdentifier) => { - fluent::parse_expected_semi_found_reserved_identifier_str - } - Some(TokenDescription::Keyword) => fluent::parse_expected_semi_found_keyword_str, - Some(TokenDescription::ReservedKeyword) => { - fluent::parse_expected_semi_found_reserved_keyword_str - } - Some(TokenDescription::DocComment) => fluent::parse_expected_semi_found_doc_comment_str, - None => fluent::parse_expected_semi_found_str, - }); + let mut diag = DiagnosticBuilder::new( + dcx, + level, + match token_descr { + Some(TokenDescription::ReservedIdentifier) => { + fluent::parse_expected_semi_found_reserved_identifier_str + } + Some(TokenDescription::Keyword) => fluent::parse_expected_semi_found_keyword_str, + Some(TokenDescription::ReservedKeyword) => { + fluent::parse_expected_semi_found_reserved_keyword_str + } + Some(TokenDescription::DocComment) => { + fluent::parse_expected_semi_found_doc_comment_str + } + None => fluent::parse_expected_semi_found_str, + }, + ); diag.set_span(self.span); diag.set_arg("token", self.token); @@ -1436,10 +1453,7 @@ pub(crate) struct FnTraitMissingParen { impl AddToDiagnostic for FnTraitMissingParen { fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut rustc_errors::Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); let applicability = if self.machine_applicable { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8f8da211d312..856256a06414 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,8 +6,8 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::Label; use rustc_errors::{ - error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticSymbolList, ErrorGuaranteed, - IntoDiagnostic, MultiSpan, + error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + DiagnosticSymbolList, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -863,13 +863,11 @@ pub struct ItemFollowingInnerAttr { pub kind: &'static str, } -impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { +impl IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel { #[track_caller] - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::passes_invalid_attr_at_crate_level); + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = + DiagnosticBuilder::new(dcx, level, fluent::passes_invalid_attr_at_crate_level); diag.set_span(self.span); diag.set_arg("name", self.name); // Only emit an error with a suggestion if we can create a string out @@ -879,7 +877,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { span, fluent::passes_suggestion, String::new(), - rustc_errors::Applicability::MachineApplicable, + Applicability::MachineApplicable, ); } if let Some(item) = self.item { @@ -1016,17 +1014,12 @@ pub struct BreakNonLoop<'a> { pub break_expr_span: Span, } -impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] - fn into_diagnostic( - self, - dcx: &rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_span_err_with_code( - self.span, - fluent::passes_break_non_loop, - error_code!(E0571), - ); + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop); + diag.set_span(self.span); + diag.code(error_code!(E0571)); diag.set_arg("kind", self.kind); diag.span_label(self.span, fluent::passes_label); if let Some(head) = self.head { @@ -1165,17 +1158,12 @@ pub struct NakedFunctionsAsmBlock { pub non_asms: Vec, } -impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock { +impl IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] - fn into_diagnostic( - self, - dcx: &rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_span_err_with_code( - self.span, - fluent::passes_naked_functions_asm_block, - error_code!(E0787), - ); + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block); + diag.set_span(self.span); + diag.code(error_code!(E0787)); for span in self.multiple_asms.iter() { diag.span_label(*span, fluent::passes_label_multiple_asm); } @@ -1281,17 +1269,12 @@ pub struct NoMainErr { pub add_teach_note: bool, } -impl<'a> IntoDiagnostic<'a> for NoMainErr { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr { #[track_caller] - fn into_diagnostic( - self, - dcx: &'a rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut diag = dcx.struct_span_err_with_code( - DUMMY_SP, - fluent::passes_no_main_function, - error_code!(E0601), - ); + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function); + diag.set_span(DUMMY_SP); + diag.code(error_code!(E0601)); diag.set_arg("crate_name", self.crate_name); diag.set_arg("filename", self.filename); diag.set_arg("has_filename", self.has_filename); @@ -1344,20 +1327,19 @@ pub struct DuplicateLangItem { pub(crate) duplicate: Duplicate, } -impl IntoDiagnostic<'_> for DuplicateLangItem { +impl IntoDiagnostic<'_, G> for DuplicateLangItem { #[track_caller] - fn into_diagnostic( - self, - dcx: &rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err_with_code( + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { + let mut diag = DiagnosticBuilder::new( + dcx, + level, match self.duplicate { Duplicate::Plain => fluent::passes_duplicate_lang_item, Duplicate::Crate => fluent::passes_duplicate_lang_item_crate, Duplicate::CrateDepends => fluent::passes_duplicate_lang_item_crate_depends, }, - error_code!(E0152), ); + diag.code(error_code!(E0152)); diag.set_arg("lang_item_name", self.lang_item_name); diag.set_arg("crate_name", self.crate_name); diag.set_arg("dependency_of", self.dependency_of); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index c3360815ac9f..8ab31f6f3825 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,10 @@ use std::num::NonZeroU32; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; -use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; +use rustc_errors::{ + error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, + Level, MultiSpan, +}; use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; @@ -17,9 +20,10 @@ impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic( self, - dcx: &'a rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut diag = dcx.struct_err(self.explain); + dcx: &'a DiagCtxt, + level: Level, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = DiagnosticBuilder::new(dcx, level, self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); diag diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 2cb47e3a9329..8e8b420df13a 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -14,7 +14,7 @@ use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, + ErrorGuaranteed, IntoDiagnostic, Level, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -322,7 +322,7 @@ impl ParseSess { &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(&self.dcx) + err.into_diagnostic(&self.dcx, Level::Error { lint: false }) } #[track_caller] @@ -335,7 +335,7 @@ impl ParseSess { &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(&self.dcx) + warning.into_diagnostic(&self.dcx, Level::Warning(None)) } #[track_caller] @@ -348,7 +348,7 @@ impl ParseSess { &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted> { - note.into_diagnostic(&self.dcx) + note.into_diagnostic(&self.dcx, Level::Note) } #[track_caller] @@ -361,7 +361,7 @@ impl ParseSess { &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !> { - fatal.into_diagnostic(&self.dcx) + fatal.into_diagnostic(&self.dcx, Level::Fatal) } #[track_caller] diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index ff253b6f4670..06a2b3ca9c4f 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -1,6 +1,6 @@ //! Errors emitted by symbol_mangling. -use rustc_errors::{ErrorGuaranteed, IntoDiagnostic}; +use rustc_errors::{DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level}; use rustc_span::Span; use std::fmt; @@ -13,15 +13,12 @@ pub struct TestOutput { // This diagnostic doesn't need translation because (a) it doesn't contain any // natural language, and (b) it's only used in tests. So we construct it // manually and avoid the fluent machinery. -impl IntoDiagnostic<'_> for TestOutput { - fn into_diagnostic( - self, - dcx: &'_ rustc_errors::DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { +impl IntoDiagnostic<'_, G> for TestOutput { + fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let TestOutput { span, kind, content } = self; #[allow(rustc::untranslatable_diagnostic)] - let mut diag = dcx.struct_err(format!("{kind}({content})")); + let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")); diag.set_span(span); diag } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index b0ec8b3a4fa8..bea6fbd6ac5c 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, ErrorGuaranteed, IntoDiagnostic, - SubdiagnosticMessage, + AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, + IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; @@ -57,13 +57,15 @@ pub struct NegativePositiveConflict<'tcx> { pub positive_impl_span: Result, } -impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> { +impl IntoDiagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] fn into_diagnostic( self, dcx: &DiagCtxt, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = dcx.struct_err(fluent::trait_selection_negative_positive_conflict); + level: Level, + ) -> rustc_errors::DiagnosticBuilder<'_, G> { + let mut diag = + DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict); diag.set_arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.set_arg( "self_desc", diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 4b006151c64c..ab42d3b8c1e4 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -13,8 +13,8 @@ extern crate rustc_session; extern crate rustc_span; use rustc_errors::{ - AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, - IntoDiagnostic, SubdiagnosticMessage, + AddToDiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, DiagCtxt, + IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -37,18 +37,18 @@ struct Note { pub struct UntranslatableInIntoDiagnostic; -impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for UntranslatableInIntoDiagnostic { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - dcx.struct_err("untranslatable diagnostic") +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UntranslatableInIntoDiagnostic { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + DiagnosticBuilder::new(dcx, level, "untranslatable diagnostic") //~^ ERROR diagnostics should be created using translatable messages } } pub struct TranslatableInIntoDiagnostic; -impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic { - fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - dcx.struct_err(crate::fluent_generated::no_crate_example) +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for TranslatableInIntoDiagnostic { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + DiagnosticBuilder::new(dcx, level, crate::fluent_generated::no_crate_example) } } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index d18db3cbbd37..f70240ecf172 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,8 +1,8 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:42:13 + --> $DIR/diagnostics.rs:42:9 | -LL | dcx.struct_err("untranslatable diagnostic") - | ^^^^^^^^^^ +LL | DiagnosticBuilder::new(dcx, level, "untranslatable diagnostic") + | ^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/diagnostics.rs:6:9 From 3a5f28f7e821a2325e9dbdb4ff40cd9ff417f065 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 16:22:45 +1100 Subject: [PATCH 013/106] Remove `struct_diagnostic` and `G::make_diagnostic_builder`. `EmissionGuarantee` no longer determines the error level, the `create_*` functions do. --- .../rustc_errors/src/diagnostic_builder.rs | 50 ------------------- compiler/rustc_errors/src/lib.rs | 15 ------ 2 files changed, 65 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 0079fa8b9953..59e5c1f352f7 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -106,13 +106,6 @@ pub trait EmissionGuarantee: Sized { /// of `Self` without actually performing the emission. #[track_caller] fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self; - - /// Creates a new `DiagnosticBuilder` that will return this type of guarantee. - #[track_caller] - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self>; } impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { @@ -163,14 +156,6 @@ impl EmissionGuarantee for ErrorGuaranteed { } } } - - #[track_caller] - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Error { lint: false }, msg) - } } // FIXME(eddyb) should there be a `Option` impl as well? @@ -187,13 +172,6 @@ impl EmissionGuarantee for () { DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} } } - - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Warning(None), msg) - } } /// Marker type which enables implementation of `create_note` and `emit_note` functions for @@ -215,13 +193,6 @@ impl EmissionGuarantee for Noted { Noted } - - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Note, msg) - } } /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for @@ -244,13 +215,6 @@ impl EmissionGuarantee for Bug { // Then panic. No need to return the marker type. panic::panic_any(ExplicitBug); } - - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Bug, msg) - } } impl EmissionGuarantee for ! { @@ -268,13 +232,6 @@ impl EmissionGuarantee for ! { // Then fatally error, returning `!` crate::FatalError.raise() } - - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Fatal, msg) - } } impl EmissionGuarantee for rustc_span::fatal_error::FatalError { @@ -292,13 +249,6 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { // Then fatally error.. rustc_span::fatal_error::FatalError } - - fn make_diagnostic_builder( - dcx: &DiagCtxt, - msg: impl Into, - ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new(dcx, Level::Fatal, msg) - } } /// In general, the `DiagnosticBuilder` uses deref to allow access to diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5027f63a9704..a86a12506ad6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -722,21 +722,6 @@ impl DiagCtxt { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// Construct a builder with the `msg` at the level appropriate for the - /// specific `EmissionGuarantee`. - /// - /// Note: this is necessary for `derive(Diagnostic)`, but shouldn't be used - /// outside of that. Instead use `struct_err`, `struct_warn`, etc., which - /// make the diagnostic kind clearer. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_diagnostic( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, G> { - G::make_diagnostic_builder(self, msg) - } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// /// Attempting to `.emit()` the builder will only emit if either: From f5459201e0f4f751bc30d890107942774ebf68fb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 16:31:15 +1100 Subject: [PATCH 014/106] Add `EmitResult` associated type to `EmissionGuarantee`. This lets different error levels share the same return type from `emit_*`. - A lot of inconsistencies in the `DiagCtxt` API are removed. - `Noted` is removed. - `FatalAbort` is introduced for fatal errors (abort via `raise`), replacing the `EmissionGuarantee` impl for `!`. - `Bug` is renamed `BugAbort` (to avoid clashing with `Level::Bug` and to mirror `FatalAbort`), and modified to work in the new way with bug errors (abort via panic). - Various diagnostic creators and emitters updated to the new, better signatures. Note that `DiagCtxt::bug` no longer needs to call `panic_any`, because `emit` handles that. Also shorten the obnoxiously long `diagnostic_builder_emit_producing_guarantee` name. --- .../rustc_errors/src/diagnostic_builder.rs | 64 ++++++++----------- compiler/rustc_errors/src/lib.rs | 36 +++++------ compiler/rustc_parse/src/lexer/mod.rs | 6 +- compiler/rustc_session/src/parse.rs | 19 +++--- compiler/rustc_session/src/session.rs | 27 ++++---- 5 files changed, 76 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 59e5c1f352f7..1c83250e0179 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -101,11 +101,15 @@ rustc_data_structures::static_assert_size!( /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" /// (or "proof") token that the emission happened. pub trait EmissionGuarantee: Sized { + /// This exists so that bugs and fatal errors can both result in `!` (an + /// abort) when emitted, but have different aborting behaviour. + type EmitResult = Self; + /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each /// `impl` of `EmissionGuarantee`, to make it impossible to create a value - /// of `Self` without actually performing the emission. + /// of `Self::EmitResult` without actually performing the emission. #[track_caller] - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self; + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult; } impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { @@ -119,7 +123,7 @@ impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. impl EmissionGuarantee for ErrorGuaranteed { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -160,7 +164,7 @@ impl EmissionGuarantee for ErrorGuaranteed { // FIXME(eddyb) should there be a `Option` impl as well? impl EmissionGuarantee for () { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -174,34 +178,15 @@ impl EmissionGuarantee for () { } } -/// Marker type which enables implementation of `create_note` and `emit_note` functions for -/// note-without-error struct diagnostics. -#[derive(Copy, Clone)] -pub struct Noted; - -impl EmissionGuarantee for Noted { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { - match db.inner.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } - - Noted - } -} - /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for -/// bug struct diagnostics. +/// bug diagnostics. #[derive(Copy, Clone)] -pub struct Bug; +pub struct BugAbort; -impl EmissionGuarantee for Bug { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { +impl EmissionGuarantee for BugAbort { + type EmitResult = !; + + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -217,8 +202,15 @@ impl EmissionGuarantee for Bug { } } -impl EmissionGuarantee for ! { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { +/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for +/// fatal diagnostics. +#[derive(Copy, Clone)] +pub struct FatalAbort; + +impl EmissionGuarantee for FatalAbort { + type EmitResult = !; + + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -235,7 +227,7 @@ impl EmissionGuarantee for ! { } impl EmissionGuarantee for rustc_span::fatal_error::FatalError { - fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -313,8 +305,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// but there are various places that rely on continuing to use `self` /// after calling `emit`. #[track_caller] - pub fn emit(&mut self) -> G { - G::diagnostic_builder_emit_producing_guarantee(self) + pub fn emit(&mut self) -> G::EmitResult { + G::emit_producing_guarantee(self) } /// Emit the diagnostic unless `delay` is true, @@ -322,7 +314,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// /// See `emit` and `delay_as_bug` for details. #[track_caller] - pub fn emit_unless(&mut self, delay: bool) -> G { + pub fn emit_unless(&mut self, delay: bool) -> G::EmitResult { if delay { self.downgrade_to_delayed_bug(); } @@ -409,7 +401,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// In the meantime, though, callsites are required to deal with the "bug" /// locally in whichever way makes the most sense. #[track_caller] - pub fn delay_as_bug(&mut self) -> G { + pub fn delay_as_bug(&mut self) -> G::EmitResult { self.downgrade_to_delayed_bug(); self.emit() } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a86a12506ad6..93813458718d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,6 +6,7 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(array_windows)] +#![feature(associated_type_defaults)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] @@ -401,7 +402,7 @@ pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; +pub use diagnostic_builder::{BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort}; pub use diagnostic_impls::{ DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, LabelKind, @@ -907,7 +908,7 @@ impl DiagCtxt { &self, span: impl Into, msg: impl Into, - ) -> DiagnosticBuilder<'_, !> { + ) -> DiagnosticBuilder<'_, FatalAbort> { let mut result = self.struct_fatal(msg); result.set_span(span); result @@ -921,7 +922,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, !> { + ) -> DiagnosticBuilder<'_, FatalAbort> { let mut result = self.struct_span_fatal(span, msg); result.code(code); result @@ -930,7 +931,10 @@ impl DiagCtxt { /// Construct a builder at the `Fatal` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { + pub fn struct_fatal( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, FatalAbort> { DiagnosticBuilder::new(self, Level::Fatal, msg) } @@ -1101,8 +1105,7 @@ impl DiagCtxt { } pub fn bug(&self, msg: impl Into) -> ! { - DiagnosticBuilder::::new(self, Bug, msg).emit(); - panic::panic_any(ExplicitBug); + DiagnosticBuilder::::new(self, Bug, msg).emit() } #[inline] @@ -1294,37 +1297,34 @@ impl DiagCtxt { pub fn create_fatal<'a>( &'a self, - fatal: impl IntoDiagnostic<'a, !>, - ) -> DiagnosticBuilder<'a, !> { + fatal: impl IntoDiagnostic<'a, FatalAbort>, + ) -> DiagnosticBuilder<'a, FatalAbort> { fatal.into_diagnostic(self, Level::Fatal) } - pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { self.create_fatal(fatal).emit() } pub fn create_bug<'a>( &'a self, - bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>, - ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> { + bug: impl IntoDiagnostic<'a, BugAbort>, + ) -> DiagnosticBuilder<'a, BugAbort> { bug.into_diagnostic(self, Level::Bug) } - pub fn emit_bug<'a>( - &'a self, - bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>, - ) -> diagnostic_builder::Bug { + pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! { self.create_bug(bug).emit() } - pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) { self.create_note(note).emit() } pub fn create_note<'a>( &'a self, - note: impl IntoDiagnostic<'a, Noted>, - ) -> DiagnosticBuilder<'a, Noted> { + note: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { note.into_diagnostic(self, Level::Note) } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index c158edaac255..59bc0eeb1c5b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,9 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey}; +use rustc_errors::{ + error_code, Applicability, Diagnostic, DiagnosticBuilder, FatalAbort, StashKey, +}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -344,7 +346,7 @@ impl<'a> StringReader<'a> { to_pos: BytePos, m: &str, c: char, - ) -> DiagnosticBuilder<'a, !> { + ) -> DiagnosticBuilder<'a, FatalAbort> { self.sess .dcx .struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c))) diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 8e8b420df13a..b33cc83f9cf3 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -14,7 +14,7 @@ use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, IntoDiagnostic, Level, MultiSpan, Noted, StashKey, + ErrorGuaranteed, FatalAbort, IntoDiagnostic, Level, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -346,26 +346,26 @@ impl ParseSess { #[track_caller] pub fn create_note<'a>( &'a self, - note: impl IntoDiagnostic<'a, Noted>, - ) -> DiagnosticBuilder<'a, Noted> { + note: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { note.into_diagnostic(&self.dcx, Level::Note) } #[track_caller] - pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) { self.create_note(note).emit() } #[track_caller] pub fn create_fatal<'a>( &'a self, - fatal: impl IntoDiagnostic<'a, !>, - ) -> DiagnosticBuilder<'a, !> { + fatal: impl IntoDiagnostic<'a, FatalAbort>, + ) -> DiagnosticBuilder<'a, FatalAbort> { fatal.into_diagnostic(&self.dcx, Level::Fatal) } #[track_caller] - pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { self.create_fatal(fatal).emit() } @@ -386,7 +386,10 @@ impl ParseSess { #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { + pub fn struct_fatal( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, FatalAbort> { self.dcx.struct_fatal(msg) } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 7f168572f7da..c9f0f74b0b21 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -23,8 +23,8 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticId, - DiagnosticMessage, ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, - MultiSpan, Noted, TerminalUrl, + DiagnosticMessage, ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, + LazyFallbackBundle, MultiSpan, TerminalUrl, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -428,7 +428,7 @@ impl Session { &self, sp: S, msg: impl Into, - ) -> DiagnosticBuilder<'_, !> { + ) -> DiagnosticBuilder<'_, FatalAbort> { self.dcx().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] @@ -437,11 +437,14 @@ impl Session { sp: S, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, !> { + ) -> DiagnosticBuilder<'_, FatalAbort> { self.dcx().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] - pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { + pub fn struct_fatal( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, FatalAbort> { self.dcx().struct_fatal(msg) } @@ -525,23 +528,23 @@ impl Session { #[track_caller] pub fn create_note<'a>( &'a self, - note: impl IntoDiagnostic<'a, Noted>, - ) -> DiagnosticBuilder<'a, Noted> { + note: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { self.parse_sess.create_note(note) } #[track_caller] - pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) { self.parse_sess.emit_note(note) } #[track_caller] pub fn create_fatal<'a>( &'a self, - fatal: impl IntoDiagnostic<'a, !>, - ) -> DiagnosticBuilder<'a, !> { + fatal: impl IntoDiagnostic<'a, FatalAbort>, + ) -> DiagnosticBuilder<'a, FatalAbort> { self.parse_sess.create_fatal(fatal) } #[track_caller] - pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { self.parse_sess.emit_fatal(fatal) } #[inline] @@ -1780,7 +1783,7 @@ impl EarlyDiagCtxt { pub fn early_struct_error( &self, msg: impl Into, - ) -> DiagnosticBuilder<'_, !> { + ) -> DiagnosticBuilder<'_, FatalAbort> { self.dcx.struct_fatal(msg) } From 9ed87336b07d26776470218e316e2df5bc9f4112 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 17:02:37 +1100 Subject: [PATCH 015/106] Factor out common `emit_producing_guarantee` code. --- .../rustc_errors/src/diagnostic_builder.rs | 64 ++++++------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 1c83250e0179..828560ec452c 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -112,6 +112,22 @@ pub trait EmissionGuarantee: Sized { fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult; } +impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + /// Most `emit_producing_guarantee` functions use this as a starting point. + fn emit_producing_nothing(&mut self) { + match self.inner.state { + // First `.emit()` call, the `&DiagCtxt` is still available. + DiagnosticBuilderState::Emittable(dcx) => { + self.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + + dcx.emit_diagnostic_without_consuming(&mut self.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + } +} + impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { /// Discard the guarantee `.emit()` would return, in favor of having the /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there @@ -124,6 +140,7 @@ impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. impl EmissionGuarantee for ErrorGuaranteed { fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + // Contrast this with `emit_producing_nothing`. match db.inner.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { @@ -165,16 +182,7 @@ impl EmissionGuarantee for ErrorGuaranteed { // FIXME(eddyb) should there be a `Option` impl as well? impl EmissionGuarantee for () { fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - match db.inner.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - - dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } + db.emit_producing_nothing(); } } @@ -187,17 +195,7 @@ impl EmissionGuarantee for BugAbort { type EmitResult = !; fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - match db.inner.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - - dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } - // Then panic. No need to return the marker type. + db.emit_producing_nothing(); panic::panic_any(ExplicitBug); } } @@ -211,34 +209,14 @@ impl EmissionGuarantee for FatalAbort { type EmitResult = !; fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - match db.inner.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - - dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } - // Then fatally error, returning `!` + db.emit_producing_nothing(); crate::FatalError.raise() } } impl EmissionGuarantee for rustc_span::fatal_error::FatalError { fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - match db.inner.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - - dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } - // Then fatally error.. + db.emit_producing_nothing(); rustc_span::fatal_error::FatalError } } From 072c157d680a0838b25bf1d7cb33c373945dc6db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 17:05:01 +1100 Subject: [PATCH 016/106] Introduce `DiagCtxt::struct_bug`. This makes `DiagCtxt::bug` look like the other similar functions. --- compiler/rustc_errors/src/lib.rs | 10 +++++++++- compiler/rustc_expand/src/base.rs | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 93813458718d..ae086153647b 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -961,6 +961,13 @@ impl DiagCtxt { DiagnosticBuilder::new(self, Level::Note, msg) } + /// Construct a builder at the `Bug` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> { + DiagnosticBuilder::new(self, Level::Bug, msg) + } + #[rustc_lint_diagnostics] #[track_caller] pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! { @@ -1104,8 +1111,9 @@ impl DiagCtxt { self.struct_note(msg).emit() } + #[rustc_lint_diagnostics] pub fn bug(&self, msg: impl Into) -> ! { - DiagnosticBuilder::::new(self, Bug, msg).emit() + self.struct_bug(msg).emit() } #[inline] diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 5aeb5e61cd78..ee0b10edfda0 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1159,6 +1159,7 @@ impl<'a> ExtCtxt<'a> { // Fixme: does this result in errors? self.expansions.clear(); } + #[rustc_lint_diagnostics] pub fn bug(&self, msg: &'static str) -> ! { self.sess.dcx().bug(msg); } From e4f237d39eed56803540eb57bc6297ad07488a58 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 19 Dec 2023 04:28:21 +0000 Subject: [PATCH 017/106] bless ui tests --- .../auxiliary/closure-in-foreign-crate.rs | 2 +- tests/ui/consts/const-float-classify.rs | 29 +++------- tests/ui/consts/const-float-classify.stderr | 11 ---- tests/ui/consts/const-try.stderr | 2 + tests/ui/consts/const_cmp_type_id.rs | 2 +- tests/ui/consts/const_cmp_type_id.stderr | 38 ++++++------- ...constifconst-call-in-const-position.stderr | 2 + .../ui/consts/issue-73976-monomorphic.stderr | 1 + tests/ui/consts/issue-94675.stderr | 1 + .../const-trait-impl.stderr | 1 + .../call-const-trait-method-pass.stderr | 2 + .../ui/rfcs/rfc-2632-const-trait-impl/call.rs | 2 +- ...ross-crate-default-method-body-is-const.rs | 2 +- ...nst_closure-const_trait_impl-ice-113381.rs | 4 +- ...closure-const_trait_impl-ice-113381.stderr | 11 ---- .../generic-bound.stderr | 1 + .../issue-102985.stderr | 2 + .../rfc-2632-const-trait-impl/issue-79450.rs | 2 +- .../issue-88155.stderr | 1 + .../match-non-const-eq.gated.stderr | 1 + ...st-op-const-closure-non-const-outer.stderr | 1 + .../specializing-constness-2.rs | 2 +- .../specializing-constness-2.stderr | 15 +++--- .../super-traits-fail-2.nn.stderr | 8 +-- .../super-traits-fail-2.ny.stderr | 4 +- .../super-traits-fail-2.rs | 11 ++-- .../super-traits-fail-2.yn.stderr | 16 ++++-- .../super-traits-fail-2.yy.stderr | 11 ++-- .../super-traits-fail-3.nn.stderr | 10 ++-- .../super-traits-fail-3.ny.stderr | 4 +- .../super-traits-fail-3.rs | 5 +- .../super-traits-fail-3.yn.stderr | 6 +-- .../super-traits-fail-3.yy.stderr | 11 ---- .../trait-default-body-stability.rs | 2 +- .../trait-default-body-stability.stderr | 54 +++++++++++-------- 35 files changed, 130 insertions(+), 147 deletions(-) delete mode 100644 tests/ui/consts/const-float-classify.stderr delete mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.stderr delete mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs index edc7fa81abb4..411707133a88 100644 --- a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs +++ b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs @@ -1,5 +1,5 @@ #![crate_type = "lib"] -#![feature(const_closures, const_trait_impl)] +#![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] pub const fn test() { diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs index 877ce02193c7..e8bd095ed25f 100644 --- a/tests/ui/consts/const-float-classify.rs +++ b/tests/ui/consts/const-float-classify.rs @@ -1,41 +1,24 @@ // compile-flags: -Zmir-opt-level=0 -// known-bug: #110395 -// FIXME run-pass +// run-pass #![feature(const_float_bits_conv)] #![feature(const_float_classify)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] // Don't promote const fn nop(x: T) -> T { x } -// FIXME(const-hack): replace with PartialEq -#[const_trait] -trait MyEq { - fn eq(self, b: T) -> bool; -} - -impl const MyEq for bool { - fn eq(self, b: bool) -> bool { - self == b - } -} - -impl const MyEq for bool { - fn eq(self, _: NonDet) -> bool { +impl const PartialEq for bool { + fn eq(&self, _: &NonDet) -> bool { true } } -const fn eq, B>(x: A, y: B) -> bool { - x.eq(y) -} - macro_rules! const_assert { ($a:expr, $b:expr) => { { - const _: () = assert!(eq($a, $b)); - assert!(eq(nop($a), nop($b))); + const _: () = assert!($a == $b); + assert!(nop($a) == nop($b)); } }; } diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr deleted file mode 100644 index f0c6c69eac4e..000000000000 --- a/tests/ui/consts/const-float-classify.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `>::eq` in constant functions - --> $DIR/const-float-classify.rs:31:7 - | -LL | x.eq(y) - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 94f4153a29e7..37a6598af9e6 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -10,6 +10,7 @@ note: impl defined here, but it is not `const` LL | impl const Try for TryMe { | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions --> $DIR/const-try.rs:33:5 @@ -23,6 +24,7 @@ note: impl defined here, but it is not `const` LL | impl const FromResidual for TryMe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index 19cee2022ac0..cda811144c76 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -1,6 +1,6 @@ // known-bug: #110395 #![feature(const_type_id)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] use std::any::TypeId; diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 0d915cec07de..84be0b67307d 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,34 +1,28 @@ -error[E0015]: cannot call non-const operator in constant functions +error[E0131]: `main` function is not allowed to have generic parameters + --> $DIR/const_cmp_type_id.rs:7:14 + | +LL | const fn main() { + | ^ `main` cannot have generic parameters + +error[E0308]: mismatched types --> $DIR/const_cmp_type_id.rs:8:13 | LL | assert!(TypeId::of::() == TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: expected constant `host` + found constant `true` -error[E0015]: cannot call non-const operator in constant functions +error[E0308]: mismatched types --> $DIR/const_cmp_type_id.rs:9:13 | LL | assert!(TypeId::of::<()>() != TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/const_cmp_type_id.rs:10:22 - | -LL | const _A: bool = TypeId::of::() < TypeId::of::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: expected constant `host` + found constant `true` error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0131, E0308. +For more information about an error, try `rustc --explain E0131`. diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr index 6eee466611c2..42ad41258248 100644 --- a/tests/ui/consts/constifconst-call-in-const-position.stderr +++ b/tests/ui/consts/constifconst-call-in-const-position.stderr @@ -14,6 +14,7 @@ LL | [0; T::a()] | ^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error[E0015]: cannot call non-const fn `::a` in constants --> $DIR/constifconst-call-in-const-position.rs:16:38 @@ -22,6 +23,7 @@ LL | const fn foo() -> [u8; T::a()] { | ^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr index ef754b23ff06..465efc7bfc24 100644 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ b/tests/ui/consts/issue-73976-monomorphic.stderr @@ -7,6 +7,7 @@ LL | GetTypeId::::VALUE == GetTypeId::::VALUE note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index f51f305ac381..60a56f85c11f 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -15,6 +15,7 @@ LL | self.bar[0] = baz.len(); note: impl defined here, but it is not `const` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/generic-const-items/const-trait-impl.stderr b/tests/ui/generic-const-items/const-trait-impl.stderr index e7e905427960..cdcd24eceffe 100644 --- a/tests/ui/generic-const-items/const-trait-impl.stderr +++ b/tests/ui/generic-const-items/const-trait-impl.stderr @@ -5,6 +5,7 @@ LL | const CREATE: T = T::create(); | ^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr index 60cd000f2d8c..e72d259e8a56 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr @@ -5,6 +5,7 @@ LL | a.plus(b) | ^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error[E0015]: cannot call non-const operator in constants --> $DIR/call-const-trait-method-pass.rs:39:22 @@ -18,6 +19,7 @@ note: impl defined here, but it is not `const` LL | impl const std::ops::Add for Int { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs index 5f48c2353735..e85976b7e1dc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(const_closures, const_trait_impl)] +#![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] pub const _: () = { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs index bde8bf20f46c..34a0ba1e271e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs @@ -3,7 +3,7 @@ // // check-pass -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] // aux-build: cross-crate.rs extern crate cross_crate; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs index 6598d1da0f86..7d811a2cc1f3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs @@ -1,3 +1,5 @@ +// check-pass +// FIXME(effects) this shouldn't pass #![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] @@ -11,5 +13,5 @@ impl Foo for () { fn main() { (const || { (()).foo() })(); - //~^ ERROR: cannot call non-const fn + // FIXME(effects) ~^ ERROR: cannot call non-const fn } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.stderr deleted file mode 100644 index 413e217020d4..000000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:13:22 - | -LL | (const || { (()).foo() })(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr index 1e8a70ffd291..f42fee59bf09 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr @@ -10,6 +10,7 @@ note: impl defined here, but it is not `const` LL | impl const std::ops::Add for S { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr index 077f6c7b2348..0fa4c8fe04c1 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr @@ -4,7 +4,9 @@ error[E0015]: cannot call non-const closure in constants LL | n => n(), | ^^^ | + = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs index b604c65d7510..269fd87ba0d4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs @@ -1,5 +1,5 @@ #![feature(const_fmt_arguments_new)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Tr { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr index 157b54214fa7..e5347a095981 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr @@ -5,6 +5,7 @@ LL | T::assoc() | ^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr index 89e59e5db6ed..28254ac15a87 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr @@ -6,6 +6,7 @@ LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in | = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr index 97ad83130d44..d82a49be75e4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr @@ -5,6 +5,7 @@ LL | (const || { (()).foo() })(); | ^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs index ada475909a3d..e0c20b819e84 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, min_specialization, rustc_attrs)] +#![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] // known-bug: #110395 #[rustc_specialization_trait] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index 0b35feddc553..5210a6942010 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -1,11 +1,12 @@ -error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/specializing-constness-2.rs:27:5 +error[E0119]: conflicting implementations of trait `A` + --> $DIR/specializing-constness-2.rs:20:1 | -LL | ::a(); - | ^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +LL | impl A for T { + | ------------------------ first implementation here +... +LL | impl const A for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr index 12bcdb034bc2..fd4d7ff34750 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr @@ -1,23 +1,23 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-2.rs:11:12 + --> $DIR/super-traits-fail-2.rs:10:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-2.rs:11:1 + --> $DIR/super-traits-fail-2.rs:10:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:11:19 + --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:11:19 + --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr index b60399c57dca..d2e3a5cec1d9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr @@ -1,11 +1,11 @@ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:11:19 + --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:11:19 + --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs index 93fd96f8f294..3820d0692434 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -1,5 +1,4 @@ -#![feature(const_trait_impl)] -// known-bug: #110395 +#![feature(const_trait_impl, effects)] // revisions: yy yn ny nn #[cfg_attr(any(yy, yn), const_trait)] @@ -9,12 +8,14 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: ~const Foo {} -// FIXME [ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` -// FIXME [ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` +//[yn,nn]~^^^ ERROR: `~const` is not allowed here const fn foo(x: &T) { x.a(); - // FIXME [yn,yy]~^ ERROR the trait bound + //[yy,yn]~^ ERROR mismatched types + // FIXME(effects) diagnostic } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr index e465ebaffa84..c05c4d50a33d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -1,14 +1,24 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-2.rs:11:12 + --> $DIR/super-traits-fail-2.rs:10:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-2.rs:11:1 + --> $DIR/super-traits-fail-2.rs:10:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/super-traits-fail-2.rs:16:5 + | +LL | x.a(); + | ^^^^^ expected `host`, found `true` + | + = note: expected constant `host` + found constant `true` +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr index 1faa5b4dd2c4..852c02cad5ca 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -1,11 +1,12 @@ -error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/super-traits-fail-2.rs:16:7 +error[E0308]: mismatched types + --> $DIR/super-traits-fail-2.rs:16:5 | LL | x.a(); - | ^^^ + | ^^^^^ expected `host`, found `true` | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: expected constant `host` + found constant `true` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr index e10c51ef45ab..199d2199c4ae 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr @@ -1,23 +1,23 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:12:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:13:1 + --> $DIR/super-traits-fail-3.rs:12:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:19 + --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:19 + --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ @@ -25,7 +25,7 @@ LL | trait Bar: ~const Foo {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:18:24 + --> $DIR/super-traits-fail-3.rs:17:24 | LL | const fn foo(x: &T) { | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr index cd0ee73277d6..46eedc333f14 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr @@ -1,11 +1,11 @@ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:19 + --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:19 + --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index 5994057b2db2..3e98e131930a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -1,8 +1,7 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] // revisions: yy yn ny nn -//[yy] known-bug: #110395 -//FIXME [yy] check-pass +//[yy] check-pass #[cfg_attr(any(yy, yn), const_trait)] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr index 34f6515b572e..dc08a8997389 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -1,17 +1,17 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:12:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:13:1 + --> $DIR/super-traits-fail-3.rs:12:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:18:24 + --> $DIR/super-traits-fail-3.rs:17:24 | LL | const fn foo(x: &T) { | ^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr deleted file mode 100644 index 5cccc025161b..000000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/super-traits-fail-3.rs:20:7 - | -LL | x.a(); - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs index 8d56295e7383..aa3b09ec9662 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs @@ -1,7 +1,7 @@ // known-bug: #110395 #![feature(staged_api)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #![feature(const_t_try)] #![feature(const_try)] #![feature(try_trait_v2)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr index deed05ae1798..62c4bc3b7ae6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr @@ -1,29 +1,39 @@ -error[E0015]: `?` cannot determine the branch of `T` in constant functions - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ - | -note: impl defined here, but it is not `const` - --> $DIR/trait-default-body-stability.rs:18:1 +error: const `impl` for trait `Try` which is not marked with `#[const_trait]` + --> $DIR/trait-default-body-stability.rs:18:12 | LL | impl const Try for T { - | ^^^^^^^^^^^^^^^^^^^^ - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + | ^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change -error[E0015]: `?` cannot convert from residual of `T` in constant functions - --> $DIR/trait-default-body-stability.rs:44:9 - | -LL | T? - | ^^ - | -note: impl defined here, but it is not `const` - --> $DIR/trait-default-body-stability.rs:33:1 +error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + --> $DIR/trait-default-body-stability.rs:33:12 | LL | impl const FromResidual for T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change -error: aborting due to 2 previous errors +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/trait-default-body-stability.rs:18:6 + | +LL | impl const Try for T { + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported -For more information about this error, try `rustc --explain E0015`. +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/trait-default-body-stability.rs:33:6 + | +LL | impl const FromResidual for T { + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0207`. From 324ca878cec59b623fb6e4dbcfad1e94937d477a Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 19 Dec 2023 04:28:43 +0000 Subject: [PATCH 018/106] fix ICE when `~const` used on non-const trait --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6f8e80172dd2..1603e2032057 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -378,7 +378,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none()); } - let arg_count = check_generic_arg_count( + let mut arg_count = check_generic_arg_count( tcx, span, def_id, @@ -560,6 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { inferred_params: vec![], infer_args, }; + if let ty::BoundConstness::ConstIfConst = constness + && generics.has_self + && !tcx.has_attr(def_id, sym::const_trait) + { + let e = tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span }); + arg_count.correct = + Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] }); + } let args = create_args_for_parent_generic_args( tcx, def_id, @@ -570,13 +578,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut args_ctx, ); - if let ty::BoundConstness::ConstIfConst = constness - && generics.has_self - && !tcx.has_attr(def_id, sym::const_trait) - { - tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span }); - } - (args, arg_count) } From 286329870dbae9c9e0f61f0c7a5d3d3963ce9f6a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Dec 2023 07:47:39 +1100 Subject: [PATCH 019/106] De-weirdify `fatally_break_rust`. The easter egg ICE on `break rust` is weird: it's the one ICE in the entire compiler that doesn't immediately abort, which makes it annoyingly inconsistent. This commit changes it to abort. As part of this, the extra notes are now appended onto the bug dignostic, rather than being printed as individual note diagnostics, which changes the output format a bit. These changes don't interferes with the joke, but they do help with my ongoing cleanups to error handling. --- compiler/rustc_errors/src/lib.rs | 13 +++++++++++++ compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 19 ++++++++++--------- tests/ui/track-diagnostics/track.rs | 2 ++ tests/ui/track-diagnostics/track.stderr | 20 ++++++++++++++++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ae086153647b..7dd9bd9c7652 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -968,6 +968,19 @@ impl DiagCtxt { DiagnosticBuilder::new(self, Level::Bug, msg) } + /// Construct a builder at the `Bug` level at the given `span` with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_span_bug( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_, BugAbort> { + let mut result = self.struct_bug(msg); + result.set_span(span); + result + } + #[rustc_lint_diagnostics] #[track_caller] pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7bd2c3f8b6b7..5d5b5f39ccfc 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -722,7 +722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let [segment] = path.segments && segment.ident.name == sym::rust { - fatally_break_rust(self.tcx); + fatally_break_rust(self.tcx, expr.span); } } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 13a249486113..c6d7650f7459 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -52,7 +52,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::RawTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -412,24 +412,25 @@ enum TupleArgumentsFlag { TupleArguments, } -fn fatally_break_rust(tcx: TyCtxt<'_>) { +fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { let dcx = tcx.sess.dcx(); - dcx.span_bug_no_panic( - MultiSpan::new(), + let mut diag = dcx.struct_span_bug( + span, "It looks like you're trying to break rust; would you like some ICE?", ); - dcx.note("the compiler expectedly panicked. this is a feature."); - dcx.note( + diag.note("the compiler expectedly panicked. this is a feature."); + diag.note( "we would appreciate a joke overview: \ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", ); - dcx.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),)); + diag.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),)); if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() { - dcx.note(format!("compiler flags: {}", flags.join(" "))); + diag.note(format!("compiler flags: {}", flags.join(" "))); if excluded_cargo_defaults { - dcx.note("some of the compiler flags provided by cargo are hidden"); + diag.note("some of the compiler flags provided by cargo are hidden"); } } + diag.emit() } /// `expected` here is the expected number of explicit generic arguments on the trait. diff --git a/tests/ui/track-diagnostics/track.rs b/tests/ui/track-diagnostics/track.rs index 97bd7789a633..08f926610d7c 100644 --- a/tests/ui/track-diagnostics/track.rs +++ b/tests/ui/track-diagnostics/track.rs @@ -1,5 +1,7 @@ // compile-flags: -Z track-diagnostics // error-pattern: created at +// rustc-env:RUST_BACKTRACE=0 +// failure-status: 101 // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr index 60254dc475be..54b1ea2764a5 100644 --- a/tests/ui/track-diagnostics/track.stderr +++ b/tests/ui/track-diagnostics/track.stderr @@ -13,15 +13,31 @@ LL | break rust -Ztrack-diagnostics: created at compiler/rustc_passes/src/loops.rs:LL:CC error: internal compiler error: It looks like you're trying to break rust; would you like some ICE? + --> $DIR/track.rs:LL:CC + | +LL | break rust + | ^^^^^^^^^^ +-Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/lib.rs:LL:CC + | + = note: the compiler expectedly panicked. this is a feature. + = note: we would appreciate a joke overview: https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675 + = note: rustc $VERSION running on $TARGET + = note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics -note: the compiler expectedly panicked. this is a feature. +thread 'rustc' panicked at compiler/rustc_hir_typeck/src/lib.rs:LL:CC: +Box +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: we would appreciate a joke overview: https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675 +note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md note: rustc $VERSION running on $TARGET note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics +query stack during panic: +#0 [typeck] type-checking `main` +#1 [analysis] running analysis passes on this crate +end of query stack error: aborting due to 3 previous errors Some errors have detailed explanations: E0268, E0425. From 006446e373eae84f585d17a9945fe75a5f56c37e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Dec 2023 09:50:29 +1100 Subject: [PATCH 020/106] Remove unused `DiagCtxt::span_bug_no_panic`. --- compiler/rustc_errors/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7dd9bd9c7652..518a2ddb71dd 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1079,13 +1079,6 @@ impl DiagCtxt { inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } - #[track_caller] - pub fn span_bug_no_panic(&self, span: impl Into, msg: impl Into) { - let mut diag = Diagnostic::new(Bug, msg); - diag.set_span(span); - self.emit_diagnostic(diag); - } - #[track_caller] #[rustc_lint_diagnostics] pub fn span_note(&self, span: impl Into, msg: impl Into) { From a4be90ed16f57a1b0e9641642a8c7b5f39d0a827 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Dec 2023 12:46:39 +0000 Subject: [PATCH 021/106] Merge commit '3a9bf729322fb5035518f99b9d76a742bf7c124e' into sync_cg_clif-2023-12-19 --- build_system/tests.rs | 7 ++ example/mini_core_hello_world.rs | 11 -- ...nable-the-exposed_provenance-feature.patch | 22 ++++ patches/stdlib-lock.toml | 55 +++++---- rust-toolchain | 2 +- scripts/test_rustc_tests.sh | 1 + src/base.rs | 16 +-- src/common.rs | 14 ++- src/intrinsics/mod.rs | 20 ++-- src/unsize.rs | 110 +++++++++++++----- src/value_and_place.rs | 59 +++++----- y.cmd | 9 ++ y.ps1 | 12 ++ 13 files changed, 223 insertions(+), 115 deletions(-) create mode 100644 patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch create mode 100644 y.cmd create mode 100644 y.ps1 diff --git a/build_system/tests.rs b/build_system/tests.rs index 1a38d5967f4b..cb7b2454cd5e 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -232,6 +232,13 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ if runner.is_native { let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs); test_cmd.arg("-q"); + // FIXME remove after portable-simd update + test_cmd + .arg("--") + .arg("--skip") + .arg("core_simd::swizzle::simd_swizzle") + .arg("--skip") + .arg("core_simd::vector::Simd::lanes"); spawn_and_wait(test_cmd); } }), diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index afc51a47f140..1d51b499c8ba 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -337,17 +337,6 @@ fn main() { static REF2: &u8 = REF1; assert_eq!(*REF1, *REF2); - extern "C" { - type A; - } - - fn main() { - let x: &A = unsafe { &*(1usize as *const A) }; - - assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0); - assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1); - } - #[repr(simd)] struct V([f64; 2]); diff --git a/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch b/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch new file mode 100644 index 000000000000..b8c0783f5243 --- /dev/null +++ b/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch @@ -0,0 +1,22 @@ +From a101a43b795431ce617e7782afb451f4853afc00 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Thu, 7 Dec 2023 14:51:35 +0000 +Subject: [PATCH] Enable the exposed_provenance feature + +--- + crates/core_simd/tests/pointers.rs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs +index 0ae8f83..06620d6 100644 +--- a/crates/core_simd/tests/pointers.rs ++++ b/crates/core_simd/tests/pointers.rs +@@ -1,4 +1,4 @@ +-#![feature(portable_simd, strict_provenance)] ++#![feature(exposed_provenance, portable_simd, strict_provenance)] + + use core_simd::simd::{Simd, SimdConstPtr, SimdMutPtr}; + +-- +2.34.1 + diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index 8a690bada0df..8e213f71c3f3 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -36,15 +36,18 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -58,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.103" +version = "0.1.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242" +checksum = "99c3f9035afc33f4358773239573f7d121099856753e1bbd2a6a5207098fc741" dependencies = [ "cc", "rustc-std-workspace-core", @@ -124,9 +127,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -135,9 +138,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "allocator-api2", "compiler_builtins", @@ -147,9 +150,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -167,9 +170,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -189,9 +192,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "compiler_builtins", "memchr", @@ -241,9 +244,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.2.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911" +checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -402,9 +405,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -419,6 +422,18 @@ dependencies = [ "compiler_builtins", "core", "libc", + "unwinding", +] + +[[package]] +name = "unwinding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +dependencies = [ + "compiler_builtins", + "gimli", + "rustc-std-workspace-core", ] [[package]] diff --git a/rust-toolchain b/rust-toolchain index 2997816d96c7..4ba08f1af44b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-25" +channel = "nightly-2023-12-19" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index a299b6de6b1c..7d7ffdadc7f7 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -44,6 +44,7 @@ rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs # vendor intrinsics rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" +rm tests/ui/simd/masked-load-store.rs # exotic linkages rm tests/ui/issues/issue-33992.rs # unsupported linkages diff --git a/src/base.rs b/src/base.rs index 8b0dc6110752..df40a5eb475c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -353,7 +353,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], - source_info.span, + Some(source_info.span), ); } AssertKind::MisalignedPointerDereference { ref required, ref found } => { @@ -365,7 +365,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], - source_info.span, + Some(source_info.span), ); } _ => { @@ -945,19 +945,19 @@ pub(crate) fn codegen_panic<'tcx>( let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len, location]; - codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span); + codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, Some(source_info.span)); } pub(crate) fn codegen_panic_nounwind<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, - source_info: mir::SourceInfo, + span: Option, ) { let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len]; - codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span); + codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, span); } pub(crate) fn codegen_unwind_terminate<'tcx>( @@ -967,16 +967,16 @@ pub(crate) fn codegen_unwind_terminate<'tcx>( ) { let args = []; - codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span); + codegen_panic_inner(fx, reason.lang_item(), &args, Some(source_info.span)); } fn codegen_panic_inner<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, lang_item: rustc_hir::LangItem, args: &[Value], - span: Span, + span: Option, ) { - let def_id = fx.tcx.require_lang_item(lang_item, Some(span)); + let def_id = fx.tcx.require_lang_item(lang_item, span); let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); let symbol_name = fx.tcx.symbol_name(instance).name; diff --git a/src/common.rs b/src/common.rs index 63562d335089..bd19a7ed0592 100644 --- a/src/common.rs +++ b/src/common.rs @@ -98,11 +98,15 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a fat ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - let ptr_ty = Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not }); - match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi { - Abi::Scalar(_) => false, - Abi::ScalarPair(_, _) => true, - abi => unreachable!("Abi of ptr to {:?} is {:?}???", ty, abi), + if ty.is_sized(tcx, ParamEnv::reveal_all()) { + return false; + } + + let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all()); + match tail.kind() { + ty::Foreign(..) => false, + ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail), } } diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index bfeeb117ff5b..68126f124242 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -487,13 +487,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let size = if let Abi::ScalarPair(_, _) = ptr.layout().abi { - let (_ptr, info) = ptr.load_scalar_pair(fx); - let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info); - size + let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + Some(ptr.load_scalar_pair(fx).1) } else { - fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64) + None }; + let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta); ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); } sym::min_align_of_val => { @@ -502,13 +501,12 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let align = if let Abi::ScalarPair(_, _) = ptr.layout().abi { - let (_ptr, info) = ptr.load_scalar_pair(fx); - let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info); - align + let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + Some(ptr.load_scalar_pair(fx).1) } else { - fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64) + None }; + let (_size, align) = crate::unsize::size_and_align_of(fx, layout, meta); ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); } @@ -688,7 +686,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } }) }); - crate::base::codegen_panic_nounwind(fx, &msg_str, source_info); + crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span)); return; } } diff --git a/src/unsize.rs b/src/unsize.rs index c6133f2b35cf..f777e11371f1 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -2,6 +2,9 @@ //! //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; + +use crate::base::codegen_panic_nounwind; use crate::prelude::*; // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/base.rs#L159-L307 @@ -187,63 +190,113 @@ pub(crate) fn coerce_dyn_star<'tcx>( // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs -pub(crate) fn size_and_align_of_dst<'tcx>( +pub(crate) fn size_and_align_of<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, layout: TyAndLayout<'tcx>, - info: Value, + info: Option, ) -> (Value, Value) { - assert!(layout.is_unsized() || layout.abi == Abi::Uninhabited); - match layout.ty.kind() { + if layout.is_sized() { + return ( + fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64), + ); + } + + let ty = layout.ty; + match ty.kind() { ty::Dynamic(..) => { // load size/align from vtable - (crate::vtable::size_of_obj(fx, info), crate::vtable::min_align_of_obj(fx, info)) + ( + crate::vtable::size_of_obj(fx, info.unwrap()), + crate::vtable::min_align_of_obj(fx, info.unwrap()), + ) } ty::Slice(_) | ty::Str => { let unit = layout.field(fx, 0); // The info in this case is the length of the str, so the size is that // times the unit size. ( - fx.bcx.ins().imul_imm(info, unit.size.bytes() as i64), + fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64), fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64), ) } - _ => { + ty::Foreign(_) => { + let trap_block = fx.bcx.create_block(); + let true_ = fx.bcx.ins().iconst(types::I8, 1); + let next_block = fx.bcx.create_block(); + fx.bcx.ins().brif(true_, trap_block, &[], next_block, &[]); + fx.bcx.seal_block(trap_block); + fx.bcx.seal_block(next_block); + fx.bcx.switch_to_block(trap_block); + + // `extern` type. We cannot compute the size, so panic. + let msg_str = with_no_visible_paths!({ + with_no_trimmed_paths!({ + format!("attempted to compute the size or alignment of extern type `{ty}`") + }) + }); + + codegen_panic_nounwind(fx, &msg_str, None); + + fx.bcx.switch_to_block(next_block); + + // This function does not return so we can now return whatever we want. + let size = fx.bcx.ins().iconst(fx.pointer_type, 42); + let align = fx.bcx.ins().iconst(fx.pointer_type, 42); + (size, align) + } + ty::Adt(..) | ty::Tuple(..) => { // First get the size of all statically known fields. // Don't use size_of because it also rounds up to alignment, which we // want to avoid, as the unsized field's alignment could be smaller. assert!(!layout.ty.is_simd()); let i = layout.fields.count() - 1; - let sized_size = layout.fields.offset(i).bytes(); + let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); + let unsized_offset_unadjusted = + fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64); let sized_align = layout.align.abi.bytes(); let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64); // Recurse to get the size of the dynamically sized field (must be // the last field). let field_layout = layout.field(fx, i); - let (unsized_size, mut unsized_align) = size_and_align_of_dst(fx, field_layout, info); + let (unsized_size, mut unsized_align) = size_and_align_of(fx, field_layout, info); - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) + // # First compute the dynamic alignment - // Return the sum of sizes and max of aligns. - let size = fx.bcx.ins().iadd_imm(unsized_size, sized_size as i64); - - // Packed types ignore the alignment of their fields. - if let ty::Adt(def, _) = layout.ty.kind() { - if def.repr().packed() { - unsized_align = sized_align; + // For packed types, we need to cap the alignment. + if let ty::Adt(def, _) = ty.kind() { + if let Some(packed) = def.repr().pack { + if packed.bytes() == 1 { + // We know this will be capped to 1. + unsized_align = fx.bcx.ins().iconst(fx.pointer_type, 1); + } else { + // We have to dynamically compute `min(unsized_align, packed)`. + let packed = fx.bcx.ins().iconst(fx.pointer_type, packed.bytes() as i64); + let cmp = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, unsized_align, packed); + unsized_align = fx.bcx.ins().select(cmp, unsized_align, packed); + } } } // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). let cmp = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, sized_align, unsized_align); - let align = fx.bcx.ins().select(cmp, sized_align, unsized_align); + let full_align = fx.bcx.ins().select(cmp, sized_align, unsized_align); + + // # Then compute the dynamic size + + // The full formula for the size would be: + // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align); + // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align); + // However, `unsized_size` is a multiple of `unsized_align`. + // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`: + // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align); + // Furthermore, `align >= unsized_align`, and therefore we only need to do: + // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); + + let full_size = fx.bcx.ins().iadd(unsized_offset_unadjusted, unsized_size); // Issue #27023: must add any necessary padding to `size` // (to make it a multiple of `align`) before returning it. @@ -255,12 +308,13 @@ pub(crate) fn size_and_align_of_dst<'tcx>( // emulated via the semi-standard fast bit trick: // // `(size + (align-1)) & -align` - let addend = fx.bcx.ins().iadd_imm(align, -1); - let add = fx.bcx.ins().iadd(size, addend); - let neg = fx.bcx.ins().ineg(align); - let size = fx.bcx.ins().band(add, neg); + let addend = fx.bcx.ins().iadd_imm(full_align, -1); + let add = fx.bcx.ins().iadd(full_size, addend); + let neg = fx.bcx.ins().ineg(full_align); + let full_size = fx.bcx.ins().band(add, neg); - (size, align) + (full_size, full_align) } + _ => bug!("size_and_align_of_dst: {ty} not supported"), } } diff --git a/src/value_and_place.rs b/src/value_and_place.rs index f52f59716a8a..567a5669d496 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -20,34 +20,36 @@ fn codegen_field<'tcx>( (base.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap()), field_layout) }; - if let Some(extra) = extra { - if field_layout.is_sized() { - return simple(fx); - } - match field_layout.ty.kind() { - ty::Slice(..) | ty::Str | ty::Foreign(..) => simple(fx), - ty::Adt(def, _) if def.repr().packed() => { - assert_eq!(layout.align.abi.bytes(), 1); - simple(fx) - } - _ => { - // We have to align the offset for DST's - let unaligned_offset = field_offset.bytes(); - let (_, unsized_align) = - crate::unsize::size_and_align_of_dst(fx, field_layout, extra); + if field_layout.is_sized() { + return simple(fx); + } + match field_layout.ty.kind() { + ty::Slice(..) | ty::Str => simple(fx), + _ => { + let unaligned_offset = field_offset.bytes(); - let one = fx.bcx.ins().iconst(fx.pointer_type, 1); - let align_sub_1 = fx.bcx.ins().isub(unsized_align, one); - let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64); - let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); - let and_rhs = fx.bcx.ins().isub(zero, unsized_align); - let offset = fx.bcx.ins().band(and_lhs, and_rhs); + // Get the alignment of the field + let (_, mut unsized_align) = crate::unsize::size_and_align_of(fx, field_layout, extra); - (base.offset_value(fx, offset), field_layout) + // For packed types, we need to cap alignment. + if let ty::Adt(def, _) = layout.ty.kind() { + if let Some(packed) = def.repr().pack { + let packed = fx.bcx.ins().iconst(fx.pointer_type, packed.bytes() as i64); + let cmp = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, unsized_align, packed); + unsized_align = fx.bcx.ins().select(cmp, unsized_align, packed); + } } + + // Bump the unaligned offset up to the appropriate alignment + let one = fx.bcx.ins().iconst(fx.pointer_type, 1); + let align_sub_1 = fx.bcx.ins().isub(unsized_align, one); + let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64); + let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); + let and_rhs = fx.bcx.ins().isub(zero, unsized_align); + let offset = fx.bcx.ins().band(and_lhs, and_rhs); + + (base.offset_value(fx, offset), field_layout) } - } else { - simple(fx) } } @@ -731,13 +733,8 @@ impl<'tcx> CPlace<'tcx> { }; let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field); - if field_layout.is_unsized() { - if let ty::Foreign(_) = field_layout.ty.kind() { - assert!(extra.is_none()); - CPlace::for_ptr(field_ptr, field_layout) - } else { - CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout) - } + if has_ptr_meta(fx.tcx, field_layout.ty) { + CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout) } else { CPlace::for_ptr(field_ptr, field_layout) } diff --git a/y.cmd b/y.cmd new file mode 100644 index 000000000000..e9b688645a4d --- /dev/null +++ b/y.cmd @@ -0,0 +1,9 @@ +@echo off +echo [BUILD] build system >&2 +mkdir build 2>nul +rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021 || goto :error +build\y.exe %* || goto :error +goto :EOF + +:error +exit /b diff --git a/y.ps1 b/y.ps1 new file mode 100644 index 000000000000..02ef0fcbd50f --- /dev/null +++ b/y.ps1 @@ -0,0 +1,12 @@ +$ErrorActionPreference = "Stop" + +$host.ui.WriteErrorLine("[BUILD] build system") +New-Item -ItemType Directory -Force -Path build | Out-Null +& rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021 +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} +& build\y.exe $args +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} From dab8395debbe86613caa508f5b8915ec8284721b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:04:40 +0000 Subject: [PATCH 022/106] Implement simd_masked_store --- scripts/test_rustc_tests.sh | 1 - src/intrinsics/simd.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 7d7ffdadc7f7..a299b6de6b1c 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -44,7 +44,6 @@ rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs # vendor intrinsics rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" -rm tests/ui/simd/masked-load-store.rs # exotic linkages rm tests/ui/issues/issue-33992.rs # unsupported linkages diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 90bfac9c9e5d..d06237f8d918 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -962,6 +962,37 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } + sym::simd_masked_store => { + intrinsic_args!(fx, args => (mask, ptr, val); intrinsic); + + let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx); + let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(val_lane_count, mask_lane_count); + let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap(); + let ptr_val = ptr.load_scalar(fx); + + for lane_idx in 0..val_lane_count { + let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx); + let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx); + + let if_enabled = fx.bcx.create_block(); + let next = fx.bcx.create_block(); + + fx.bcx.ins().brif(mask_lane, if_enabled, &[], next, &[]); + fx.bcx.seal_block(if_enabled); + + fx.bcx.switch_to_block(if_enabled); + let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32; + fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_val, Offset32::new(offset)); + fx.bcx.ins().jump(next, &[]); + + fx.bcx.seal_block(next); + fx.bcx.switch_to_block(next); + + fx.bcx.ins().nop(); + } + } + sym::simd_gather => { intrinsic_args!(fx, args => (val, ptr, mask); intrinsic); From 27d6539a46123dcdb6fae6e043b8c1c12b3e0d6f Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 8 Dec 2023 14:51:50 -0800 Subject: [PATCH 023/106] Plumb awaitness of for loops --- compiler/rustc_ast/src/ast.rs | 13 +++++++--- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/util/classify.rs | 14 ++++++++--- compiler/rustc_ast/src/visit.rs | 10 ++++---- compiler/rustc_ast_lowering/src/expr.rs | 9 +++---- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + .../rustc_ast_pretty/src/pprust/state/expr.rs | 10 +++++--- .../src/assert/context.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_lint/src/unused.rs | 6 ++--- compiler/rustc_parse/src/parser/expr.rs | 20 +++++++++++----- compiler/rustc_resolve/src/late.rs | 6 ++--- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + .../clippy_lints/src/needless_continue.rs | 6 ++++- .../clippy/clippy_lints/src/redundant_else.rs | 2 +- .../src/suspicious_operation_groupings.rs | 2 +- .../clippy/clippy_utils/src/ast_utils.rs | 19 ++++++++++++--- src/tools/clippy/clippy_utils/src/sugg.rs | 2 +- src/tools/rustfmt/src/closures.rs | 4 ++-- src/tools/rustfmt/src/expr.rs | 24 +++++++++++++------ src/tools/rustfmt/src/matches.rs | 2 +- src/tools/rustfmt/src/overflow.rs | 2 +- src/tools/rustfmt/src/utils.rs | 4 ++-- .../ui/async-await/feature-async-for-loop.rs | 14 +++++++++++ .../async-await/feature-async-for-loop.stderr | 11 +++++++++ 26 files changed, 137 insertions(+), 53 deletions(-) create mode 100644 tests/ui/async-await/feature-async-for-loop.rs create mode 100644 tests/ui/async-await/feature-async-for-loop.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9d543563c0f9..8a0fbdd1357a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1274,7 +1274,7 @@ impl Expr { ExprKind::Let(..) => ExprPrecedence::Let, ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, - ExprKind::ForLoop(..) => ExprPrecedence::ForLoop, + ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop, ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Match(..) => ExprPrecedence::Match, ExprKind::Closure(..) => ExprPrecedence::Closure, @@ -1436,10 +1436,10 @@ pub enum ExprKind { While(P, P, Option