diff --git a/Cargo.lock b/Cargo.lock index 117d8c2610e2d..5d78e29de0e08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4340,6 +4340,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ + "derivative", "rustc_apfloat", "rustc_arena", "rustc_data_structures", diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5252472261f30..ec3ab828b7194 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; @@ -162,24 +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) } - }; - - // 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() @@ -197,574 +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); - } - - // At this point, we have handled all unions and - // 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); + // 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 { - // 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 { - scalar_unit(prim) - } 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); - } - } + // 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, + ) } - - 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) } fn layout_of_union< @@ -872,6 +335,593 @@ 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, + 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, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2d61f3bceec73..1f6d47ab4535b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -670,7 +670,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let params = arena_vec![self; param]; let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::Async(async_coroutine_source)); + this.coroutine_kind = Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + async_coroutine_source, + )); let old_ctx = this.task_context; this.task_context = Some(task_context_hid); @@ -724,7 +727,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::Gen(coroutine_source)); + this.coroutine_kind = Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + coroutine_source, + )); let res = body(this); (&[], res) @@ -802,7 +808,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let params = arena_vec![self; param]; let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::AsyncGen(async_coroutine_source)); + this.coroutine_kind = Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + async_coroutine_source, + )); let old_ctx = this.task_context; this.task_context = Some(task_context_hid); @@ -888,9 +897,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let full_span = expr.span.to(await_kw_span); let is_async_gen = match self.coroutine_kind { - Some(hir::CoroutineKind::Async(_)) => false, - Some(hir::CoroutineKind::AsyncGen(_)) => true, - Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false, + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, + Some(hir::CoroutineKind::Coroutine) + | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) + | None => { return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { await_kw_span, item_span: self.current_item, @@ -1123,9 +1134,9 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(movability) } Some( - hir::CoroutineKind::Gen(_) - | hir::CoroutineKind::Async(_) - | hir::CoroutineKind::AsyncGen(_), + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), ) => { panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering"); } @@ -1638,9 +1649,9 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> { let is_async_gen = match self.coroutine_kind { - Some(hir::CoroutineKind::Gen(_)) => false, - Some(hir::CoroutineKind::AsyncGen(_)) => true, - Some(hir::CoroutineKind::Async(_)) => { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false, + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { return hir::ExprKind::Err( self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }), ); @@ -1803,7 +1814,25 @@ impl<'hir> LoweringContext<'_, 'hir> { arena_vec![self; head], ) } - ForLoopKind::ForAwait => self.arena.alloc(head), + // ` unsafe { Pin::new_unchecked(&mut into_async_iter()) }` + ForLoopKind::ForAwait => { + // `::core::async_iter::IntoAsyncIterator::into_async_iter()` + let iter = self.expr_call_lang_item_fn( + head_span, + hir::LangItem::IntoAsyncIterIntoIter, + arena_vec![self; head], + ); + let iter = self.expr_mut_addr_of(head_span, iter); + // `Pin::new_unchecked(...)` + let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut( + head_span, + hir::LangItem::PinNewUnchecked, + arena_vec![self; iter], + )); + // `unsafe { ... }` + let iter = self.arena.alloc(self.expr_unsafe(iter)); + iter + } }; let match_expr = self.arena.alloc(self.expr_match( diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 6731ef1230660..e527a91eb6f20 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, + struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -12,7 +12,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { place: &str, borrow_place: &str, value_place: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow { place, span, @@ -28,7 +28,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc: &str, borrow_span: Span, borrow_desc: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self, span, @@ -50,7 +50,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_loan_span: Span, old_opt_via: &str, old_load_end_span: Option, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_err!( self, @@ -97,7 +97,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc: &str, old_loan_span: Span, old_load_end_span: Option, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self, new_loan_span, @@ -130,7 +130,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { noun_old: &str, old_opt_via: &str, previous_end_span: Option, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, @@ -162,7 +162,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option, second_borrow_desc: &str, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, @@ -194,7 +194,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { kind_old: &str, msg_old: &str, old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_err!( self, @@ -235,7 +235,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, borrow_span: Span, desc: &str, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, @@ -254,16 +254,12 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, desc: &str, is_arg: bool, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) } - pub(crate) fn cannot_assign( - &self, - span: Span, - desc: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(self, span, E0594, "cannot assign to {}", desc) } @@ -271,7 +267,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, move_from_desc: &str, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc) } @@ -283,7 +279,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, ty: Ty<'_>, is_index: Option, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", @@ -305,7 +301,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, container_ty: Ty<'_>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, move_from_span, @@ -323,7 +319,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { verb: &str, optional_adverb_for_moved: &str, moved_path: Option, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); struct_span_err!( @@ -342,7 +338,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, path: &str, reason: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) } @@ -353,7 +349,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { immutable_place: &str, immutable_section: &str, action: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self, mutate_span, @@ -372,7 +368,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, span: Span, yield_span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; let mut err = struct_span_err!( self, @@ -387,7 +383,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn cannot_borrow_across_destructor( &self, borrow_span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { struct_span_err!( self, borrow_span, @@ -400,7 +396,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, span: Span, path: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { struct_span_err!(self, span, E0597, "{} does not live long enough", path,) } @@ -410,7 +406,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { return_kind: &str, reference_desc: &str, path_desc: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self, span, @@ -436,7 +432,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrowed_path: &str, capture_span: Span, scope: &str, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self, closure_span, @@ -452,14 +448,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn thread_local_value_does_not_live_long_enough( &self, span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) } pub(crate) fn temporary_value_borrowed_for_too_long( &self, span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) } @@ -470,7 +466,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { sp: S, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code) } } @@ -479,7 +475,7 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>( tcx: TyCtxt<'tcx>, escape_span: Span, escapes_from: &str, -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +) -> DiagnosticBuilder<'tcx> { struct_span_err!( tcx.sess, escape_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 60dbf7dc055bf..e6881316a8f5b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,7 +1,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::DiagnosticBuilder; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; @@ -147,11 +147,7 @@ impl<'tcx> ToUniverseInfo<'tcx> for ! { trait TypeOpInfo<'tcx> { /// Returns an error to be reported if rerunning the type op fails to /// recover the error's cause. - fn fallback_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; fn base_universe(&self) -> ty::UniverseIndex; @@ -161,7 +157,7 @@ trait TypeOpInfo<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, - ) -> Option>; + ) -> Option>; #[instrument(level = "debug", skip(self, mbcx))] fn report_error( @@ -224,11 +220,7 @@ struct PredicateQuery<'tcx> { } impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { - fn fallback_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { tcx.sess.create_err(HigherRankedLifetimeError { cause: Some(HigherRankedErrorCause::CouldNotProve { predicate: self.canonical_query.value.value.predicate.to_string(), @@ -247,7 +239,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, - ) -> Option> { + ) -> Option> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); @@ -265,11 +257,7 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> where T: Copy + fmt::Display + TypeFoldable> + 'tcx, { - fn fallback_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { tcx.sess.create_err(HigherRankedLifetimeError { cause: Some(HigherRankedErrorCause::CouldNotNormalize { value: self.canonical_query.value.value.value.to_string(), @@ -288,7 +276,7 @@ where cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, - ) -> Option> { + ) -> Option> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); @@ -312,11 +300,7 @@ struct AscribeUserTypeQuery<'tcx> { } impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { - fn fallback_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span }) @@ -332,7 +316,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, - ) -> Option> { + ) -> Option> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); @@ -342,11 +326,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { } impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { - fn fallback_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span }) @@ -362,7 +342,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { _cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, - ) -> Option> { + ) -> Option> { try_extract_error_from_region_constraints( mbcx.infcx, placeholder_region, @@ -383,7 +363,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, -) -> Option> { +) -> Option> { // We generally shouldn't have errors here because the query was // already run, but there's no point using `span_delayed_bug` // when we're going to emit an error here anyway. @@ -407,7 +387,7 @@ fn try_extract_error_from_region_constraints<'tcx>( region_constraints: &RegionConstraintData<'tcx>, mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, -) -> Option> { +) -> Option> { let placeholder_universe = match placeholder_region.kind() { ty::RePlaceholder(p) => p.universe, ty::ReVar(vid) => universe_of_region(vid), diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index db0f4559a6be0..1577b2896c3db 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,13 +1,11 @@ use either::Either; -use hir::PatField; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +use rustc_hir::{CoroutineDesugaring, PatField}; use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -324,7 +322,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, mpi: MovePathIndex, move_span: Span, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'_>, in_pattern: &mut bool, move_spans: UseSpans<'_>, ) { @@ -483,7 +481,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desired_action: InitializationRequiringAction, span: Span, use_spans: UseSpans<'tcx>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { // We need all statements in the body where the binding was assigned to to later find all // the branching code paths where the binding *wasn't* assigned to. let inits = &self.move_data.init_path_map[mpi]; @@ -873,7 +871,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, (place, _span): (Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); @@ -921,7 +919,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -2025,7 +2023,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { debug!( "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ @@ -2200,7 +2198,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, drop_span: Span, borrow_span: Span, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { debug!( "report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ @@ -2228,7 +2226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { @@ -2395,7 +2393,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Option> { + ) -> Option> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", @@ -2490,7 +2488,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { constraint_span: Span, captured_var: &str, scope: &str, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -2516,27 +2514,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; let kind = match use_span.coroutine_kind() { Some(coroutine_kind) => match coroutine_kind { - CoroutineKind::Gen(kind) => match kind { + CoroutineKind::Desugared(CoroutineDesugaring::Gen, kind) => match kind { CoroutineSource::Block => "gen block", CoroutineSource::Closure => "gen closure", CoroutineSource::Fn => { bug!("gen block/closure expected, but gen function found.") } }, - CoroutineKind::AsyncGen(kind) => match kind { + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, kind) => match kind { CoroutineSource::Block => "async gen block", CoroutineSource::Closure => "async gen closure", CoroutineSource::Fn => { bug!("gen block/closure expected, but gen function found.") } }, - CoroutineKind::Async(async_kind) => match async_kind { - CoroutineSource::Block => "async block", - CoroutineSource::Closure => "async closure", - CoroutineSource::Fn => { - bug!("async block/closure expected, but async function found.") + CoroutineKind::Desugared(CoroutineDesugaring::Async, async_kind) => { + match async_kind { + CoroutineSource::Block => "async block", + CoroutineSource::Closure => "async closure", + CoroutineSource::Fn => { + bug!("async block/closure expected, but async function found.") + } } - }, + } CoroutineKind::Coroutine => "coroutine", }, None => "closure", @@ -2566,7 +2566,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ConstraintCategory::CallArgument(_) => { fr_name.highlight_region_name(&mut err); - if matches!(use_span.coroutine_kind(), Some(CoroutineKind::Async(_))) { + if matches!( + use_span.coroutine_kind(), + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) + ) { err.note( "async blocks are not executed immediately and must either take a \ reference or ownership of outside variables they use", @@ -2593,7 +2596,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { upvar_span: Span, upvar_name: Symbol, escape_span: Span, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 43487b85a7b3b..f3b21d22c1a55 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; @@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, place: Place<'tcx>, span: Span, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) } else { @@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index c3c1f1293d2ab..506933c470e25 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,5 +1,5 @@ use hir::ExprKind; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; @@ -711,7 +711,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn construct_mut_suggestion_for_local_binding_patterns( &self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'_>, local: Local, ) { let local_decl = &self.body.local_decls[local]; @@ -1025,7 +1025,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) { + fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_>) { let source = self.body.source; let hir = self.infcx.tcx.hir(); if let InstanceDef::Item(def_id) = source.instance @@ -1067,12 +1067,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn suggest_make_local_mut( - &self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - local: Local, - name: Symbol, - ) { + fn suggest_make_local_mut(&self, err: &mut DiagnosticBuilder<'_>, local: Local, name: Symbol) { let local_decl = &self.body.local_decls[local]; let (pointer_sigil, pointer_desc) = diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 759f5e910f70a..f0b773b17ba0e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -3,7 +3,7 @@ //! Error reporting machinery for lifetime errors. use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res::Def; use rustc_hir::def_id::DefId; @@ -202,7 +202,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // and the span which bounded to the trait for adding 'static lifetime suggestion fn suggest_static_lifetime_for_gat_from_hrtb( &self, - diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + diag: &mut DiagnosticBuilder<'_>, lower_bound: RegionVid, ) { let mut suggestions = vec![]; @@ -573,7 +573,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &self, errci: &ErrorConstraintInfo<'tcx>, kind: ReturnConstraint, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; @@ -645,7 +645,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn report_escaping_data_error( &self, errci: &ErrorConstraintInfo<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let ErrorConstraintInfo { span, category, .. } = errci; let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( @@ -744,10 +744,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it /// | is returning data with lifetime `'b` /// ``` - fn report_general_error( - &self, - errci: &ErrorConstraintInfo<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> DiagnosticBuilder<'tcx> { let ErrorConstraintInfo { fr, fr_is_local, @@ -1049,7 +1046,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. }) => { let body = map.body(*body); - if !matches!(body.coroutine_kind, Some(hir::CoroutineKind::Async(..))) { + if !matches!( + body.coroutine_kind, + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) + ) { closure_span = Some(expr.span.shrink_to_lo()); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 8441dfaa7df28..78d84f468e026 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -684,39 +684,46 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), }; let mir_description = match hir.body(body).coroutine_kind { - Some(hir::CoroutineKind::Async(src)) => match src { - hir::CoroutineSource::Block => " of async block", - hir::CoroutineSource::Closure => " of async closure", - hir::CoroutineSource::Fn => { - let parent_item = - tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); - let output = &parent_item - .fn_decl() - .expect("coroutine lowered from async fn should be in fn") - .output; - span = output.span(); - if let hir::FnRetTy::Return(ret) = output { - hir_ty = Some(self.get_future_inner_return_ty(*ret)); + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, src)) => { + match src { + hir::CoroutineSource::Block => " of async block", + hir::CoroutineSource::Closure => " of async closure", + hir::CoroutineSource::Fn => { + let parent_item = + tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from async fn should be in fn") + .output; + span = output.span(); + if let hir::FnRetTy::Return(ret) = output { + hir_ty = Some(self.get_future_inner_return_ty(*ret)); + } + " of async function" } - " of async function" } - }, - Some(hir::CoroutineKind::Gen(src)) => match src { - hir::CoroutineSource::Block => " of gen block", - hir::CoroutineSource::Closure => " of gen closure", - hir::CoroutineSource::Fn => { - let parent_item = - tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); - let output = &parent_item - .fn_decl() - .expect("coroutine lowered from gen fn should be in fn") - .output; - span = output.span(); - " of gen function" + } + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, src)) => { + match src { + hir::CoroutineSource::Block => " of gen block", + hir::CoroutineSource::Closure => " of gen closure", + hir::CoroutineSource::Fn => { + let parent_item = + tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from gen fn should be in fn") + .output; + span = output.span(); + " of gen function" + } } - }, + } - Some(hir::CoroutineKind::AsyncGen(src)) => match src { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + src, + )) => match src { hir::CoroutineSource::Block => " of async gen block", hir::CoroutineSource::Closure => " of async gen closure", hir::CoroutineSource::Fn => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 43f48f579a373..cf2d2ca74655b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2407,8 +2407,8 @@ mod error { /// when errors in the map are being re-added to the error buffer so that errors with the /// same primary span come out in a consistent order. buffered_move_errors: - BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>, - buffered_mut_errors: FxIndexMap, usize)>, + BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>, + buffered_mut_errors: FxIndexMap, usize)>, /// Diagnostics to be reported buffer. buffered: Vec, /// Set to Some if we emit an error during borrowck @@ -2426,7 +2426,7 @@ mod error { } } - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) { + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { if let None = self.tainted_by_errors { self.tainted_by_errors = Some(self.tcx.sess.span_delayed_bug( t.span.clone_ignoring_labels(), @@ -2446,7 +2446,7 @@ mod error { } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) { + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { self.errors.buffer_error(t); } @@ -2457,7 +2457,7 @@ mod error { pub fn buffer_move_error( &mut self, move_out_indices: Vec, - place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>), + place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>), ) -> bool { if let Some((_, diag)) = self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) @@ -2473,16 +2473,11 @@ mod error { pub fn get_buffered_mut_error( &mut self, span: Span, - ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> { + ) -> Option<(DiagnosticBuilder<'tcx>, usize)> { self.errors.buffered_mut_errors.remove(&span) } - pub fn buffer_mut_error( - &mut self, - span: Span, - t: DiagnosticBuilder<'tcx, ErrorGuaranteed>, - count: usize, - ) { + pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) { self.errors.buffered_mut_errors.insert(span, (t, count)); } @@ -2517,7 +2512,7 @@ mod error { pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx, ErrorGuaranteed>)> { + ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> { self.errors.buffered_move_errors.get(move_out_indices) } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index c5fd535b03620..2f23146096fb3 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -8,9 +8,7 @@ use rustc_ast::{ FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult, SingleLabelManySpans, -}; +use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; @@ -726,7 +724,7 @@ fn report_redundant_format_arguments<'a>( args: &FormatArguments, used: &[bool], placeholders: Vec<(Span, &str)>, -) -> Option> { +) -> Option> { let mut fmt_arg_indices = vec![]; let mut args_spans = vec![]; let mut fmt_spans = vec![]; @@ -885,7 +883,6 @@ fn report_invalid_references( highlight: SingleLabelManySpans { spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(), label: "", - kind: rustc_errors::LabelKind::Label, }, }); // Point out `{:.*}` placeholders: those take an extra argument. diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index ec843a3a0cd81..d760cea59a712 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,7 +5,7 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast_pretty::pprust; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, DiagnosticBuilder, Level}; use rustc_expand::base::*; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; @@ -391,15 +391,14 @@ pub fn expand_test_or_bench( fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { let dcx = cx.sess.dcx(); let msg = "the `#[test]` attribute may only be used on a non-associated function"; - let mut err = match item.map(|i| &i.kind) { + let level = match item.map(|i| &i.kind) { // These were a warning before #92959 and need to continue being that to avoid breaking // stable user code (#94508). - Some(ast::ItemKind::MacCall(_)) => dcx.struct_span_warn(attr_sp, msg), - // `.forget_guarantee()` needed to get these two arms to match types. Because of how - // locally close the `.emit()` call is I'm comfortable with it, but if it can be - // reworked in the future to not need it, it'd be nice. - _ => dcx.struct_span_err(attr_sp, msg).forget_guarantee(), + Some(ast::ItemKind::MacCall(_)) => Level::Warning(None), + _ => Level::Error { lint: false }, }; + let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg); + err.set_span(attr_sp); if let Some(item) = item { err.span_label( item.span, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index df40a5eb475c3..8d3be19839e9a 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -179,7 +179,7 @@ pub(crate) fn compile_fn( let early_dcx = rustc_session::EarlyDiagCtxt::new( rustc_session::config::ErrorOutputType::default(), ); - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "backend implementation limit exceeded while compiling {name}", name = codegened_func.symbol_name )); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 6b7e38a6cb125..8db97d577ca76 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -102,7 +102,7 @@ pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); 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, _) = diag.messages().first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); let mut diag = diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0442bef8a44a7..53ae085a72160 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -15,7 +15,7 @@ use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{translation::Translate, DiagCtxt, DiagnosticId, FatalError, Level}; -use rustc_errors::{DiagnosticMessage, Style}; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, Style}; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ @@ -986,7 +986,7 @@ pub struct CguMessage; type DiagnosticArgName<'source> = Cow<'source, str>; struct Diagnostic { - msg: Vec<(DiagnosticMessage, Style)>, + msgs: Vec<(DiagnosticMessage, Style)>, args: FxHashMap, rustc_errors::DiagnosticArgValue<'static>>, code: Option, lvl: Level, @@ -1799,14 +1799,14 @@ impl Emitter for SharedEmitter { let args: FxHashMap, rustc_errors::DiagnosticArgValue<'_>> = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msg: diag.message.clone(), + msgs: diag.messages.clone(), args: args.clone(), code: diag.code.clone(), lvl: diag.level(), }))); for child in &diag.children { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msg: child.message.clone(), + msgs: child.messages.clone(), args: args.clone(), code: None, lvl: child.level, @@ -1838,7 +1838,7 @@ impl SharedEmitterMain { match message { Ok(SharedEmitterMessage::Diagnostic(diag)) => { let dcx = sess.dcx(); - let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msg); + let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msgs); if let Some(code) = diag.code { d.code(code); } @@ -1846,14 +1846,14 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); } Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); - - let mut err = match level { - Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), - Level::Warning(_) => sess.struct_warn(msg), - Level::Note => sess.struct_note(msg), + let err_level = match level { + Level::Error { lint: false } => rustc_errors::Level::Error { lint: false }, + Level::Warning(_) => rustc_errors::Level::Warning(None), + Level::Note => rustc_errors::Level::Note, _ => bug!("Invalid inline asm diagnostic level"), }; + let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); + let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), err_level, msg); // If the cookie is 0 then we don't have span information. if cookie != 0 { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index dda30046bfbad..2ecc5ad4fe42c 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_hir::{CoroutineKind, CoroutineSource, Mutability}; +use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability}; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; @@ -560,15 +560,31 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { match coroutine_kind { - Some(CoroutineKind::Gen(CoroutineSource::Block)) => "gen_block", - Some(CoroutineKind::Gen(CoroutineSource::Closure)) => "gen_closure", - Some(CoroutineKind::Gen(CoroutineSource::Fn)) => "gen_fn", - Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block", - Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure", - Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn", - Some(CoroutineKind::AsyncGen(CoroutineSource::Block)) => "async_gen_block", - Some(CoroutineKind::AsyncGen(CoroutineSource::Closure)) => "async_gen_closure", - Some(CoroutineKind::AsyncGen(CoroutineSource::Fn)) => "async_gen_fn", + Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Block)) => { + "gen_block" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Closure)) => { + "gen_closure" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Fn)) => "gen_fn", + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) => { + "async_block" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) => { + "async_closure" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) => { + "async_fn" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Block)) => { + "async_gen_block" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Closure)) => { + "async_gen_closure" + } + Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => { + "async_gen_fn" + } Some(CoroutineKind::Coroutine) => "coroutine", None => "closure", } diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 8f18cd78d3fff..2cafbb9331d1d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; -use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; use super::{CompileTimeInterpreter, InterpCx}; use crate::errors::{self, FrameNote, ReportErrorExt}; @@ -133,7 +133,7 @@ pub(super) fn report<'tcx, C, F, E>( where C: FnOnce() -> (Span, Vec), F: FnOnce(Span, Vec) -> E, - E: IntoDiagnostic<'tcx, ErrorGuaranteed>, + E: IntoDiagnostic<'tcx>, { // Special handling for certain errors match error { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 949606ed6c9f9..8a1e5356a159d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -464,8 +464,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() - && let Some(coroutine_kind @ hir::CoroutineKind::Async(..)) = - self.tcx.coroutine_kind(def_id) + && let Some( + coroutine_kind @ hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + _, + ), + ) = self.tcx.coroutine_kind(def_id) { self.check_op(ops::Coroutine(coroutine_kind)); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 2de6362b9fe01..532cd9c261fd3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -2,7 +2,7 @@ use hir::def_id::LocalDefId; use hir::{ConstContext, LangItem}; -use rustc_errors::{error_code, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{error_code, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -48,11 +48,7 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug { DiagnosticImportance::Primary } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; } #[derive(Debug)] @@ -66,11 +62,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { } } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_floating_point_arithmetic, @@ -84,11 +76,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { #[derive(Debug)] pub struct FnCallIndirect; impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() }) } } @@ -105,11 +93,7 @@ pub struct FnCallNonConst<'tcx> { } impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - _: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> { let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self; let ConstCx { tcx, param_env, .. } = *ccx; @@ -331,11 +315,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { pub struct FnCallUnstable(pub DefId, pub Option); impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let FnCallUnstable(def_id, feature) = *self; let mut err = ccx @@ -359,20 +339,24 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { pub struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { + if let hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) = self.0 + { Status::Unstable(sym::const_async_blocks) } else { Status::Forbidden } } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); - if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { + if let hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) = self.0 + { ccx.tcx.sess.create_feature_err( errors::UnallowedOpInConstContext { span, msg }, sym::const_async_blocks, @@ -386,11 +370,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { #[derive(Debug)] pub struct HeapAllocation; impl<'tcx> NonConstOp<'tcx> for HeapAllocation { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::UnallowedHeapAllocations { span, kind: ccx.const_kind(), @@ -402,11 +382,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { #[derive(Debug)] pub struct InlineAsm; impl<'tcx> NonConstOp<'tcx> for InlineAsm { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() }) } } @@ -417,11 +393,7 @@ pub struct LiveDrop<'tcx> { pub dropped_ty: Ty<'tcx>, } impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::LiveDrop { span, dropped_ty: self.dropped_ty, @@ -444,11 +416,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { // not additionally emit a feature gate error if activating the feature gate won't work. DiagnosticImportance::Secondary } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx .sess .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) @@ -461,11 +429,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { /// it in the future for static items. pub struct CellBorrow; impl<'tcx> NonConstOp<'tcx> for CellBorrow { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer { @@ -502,11 +466,7 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { DiagnosticImportance::Secondary } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { match self.0 { hir::BorrowKind::Raw => ccx.tcx.sess.create_err(errors::UnallowedMutableRefsRaw { span, @@ -530,11 +490,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { Status::Unstable(sym::const_mut_refs) } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let kind = ccx.const_kind(); match self.0 { hir::BorrowKind::Raw => ccx.tcx.sess.create_feature_err( @@ -561,11 +517,7 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref { DiagnosticImportance::Secondary } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_feature_err( errors::MutDerefErr { span, kind: ccx.const_kind() }, sym::const_mut_refs, @@ -577,11 +529,7 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref { #[derive(Debug)] pub struct PanicNonStr; impl<'tcx> NonConstOp<'tcx> for PanicNonStr { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::PanicNonStrErr { span }) } } @@ -592,11 +540,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr { #[derive(Debug)] pub struct RawPtrComparison; impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME(const_trait_impl): revert to span_bug? ccx.tcx.sess.create_err(errors::RawPtrComparisonErr { span }) } @@ -609,11 +553,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { Status::Unstable(sym::const_mut_refs) } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -629,11 +569,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::RawPtrToIntErr { span }) } } @@ -650,11 +586,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { } } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::StaticAccessErr { span, kind: ccx.const_kind(), @@ -667,11 +599,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { #[derive(Debug)] pub struct ThreadLocalAccess; impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.create_err(errors::NonConstOpErr { span }) } } @@ -696,11 +624,7 @@ pub mod ty { } } - fn build_error( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index cca5b90abb920..2f538cebaa653 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -8,9 +8,6 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance}; -use rustc_mir_dataflow::impls::MaybeStorageLive; -use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, FIRST_VARIANT}; use rustc_target::spec::abi::Abi; @@ -51,12 +48,6 @@ impl<'tcx> MirPass<'tcx> for Validator { Reveal::All => tcx.param_env_reveal_all_normalized(def_id), }; - let always_live_locals = always_storage_live_locals(body); - let storage_liveness = MaybeStorageLive::new(std::borrow::Cow::Owned(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body); - let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { // In this case `AbortUnwindingCalls` haven't yet been executed. true @@ -83,7 +74,6 @@ impl<'tcx> MirPass<'tcx> for Validator { mir_phase, unwind_edge_count: 0, reachable_blocks: traversal::reachable_as_bitset(body), - storage_liveness, place_cache: FxHashSet::default(), value_cache: FxHashSet::default(), can_unwind, @@ -116,7 +106,6 @@ struct CfgChecker<'a, 'tcx> { mir_phase: MirPhase, unwind_edge_count: usize, reachable_blocks: BitSet, - storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, place_cache: FxHashSet>, value_cache: FxHashSet, // If `false`, then the MIR must not contain `UnwindAction::Continue` or @@ -294,28 +283,13 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { - fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { if self.body.local_decls.get(local).is_none() { self.fail( location, format!("local {local:?} has no corresponding declaration in `body.local_decls`"), ); } - - if self.reachable_blocks.contains(location.block) && context.is_use() { - // We check that the local is live whenever it is used. Technically, violating this - // restriction is only UB and not actually indicative of not well-formed MIR. This means - // that an optimization which turns MIR that already has UB into MIR that fails this - // check is not necessarily wrong. However, we have no such optimizations at the moment, - // and so we include this check anyway to help us catch bugs. If you happen to write an - // optimization that might cause this to incorrectly fire, feel free to remove this - // check. - self.storage_liveness.seek_after_primary_effect(location); - let locals_with_storage = self.storage_liveness.get(); - if !locals_with_storage.contains(local) { - self.fail(location, format!("use of local {local:?}, which has no storage here")); - } - } } fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { @@ -367,26 +341,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.fail(location, format!("explicit `{kind:?}` is forbidden")); } } - StatementKind::StorageLive(local) => { - // We check that the local is not live when entering a `StorageLive` for it. - // Technically, violating this restriction is only UB and not actually indicative - // of not well-formed MIR. This means that an optimization which turns MIR that - // already has UB into MIR that fails this check is not necessarily wrong. However, - // we have no such optimizations at the moment, and so we include this check anyway - // to help us catch bugs. If you happen to write an optimization that might cause - // this to incorrectly fire, feel free to remove this check. - if self.reachable_blocks.contains(location.block) { - self.storage_liveness.seek_before_primary_effect(location); - let locals_with_storage = self.storage_liveness.get(); - if locals_with_storage.contains(*local) { - self.fail( - location, - format!("StorageLive({local:?}) which already has storage here"), - ); - } - } - } - StatementKind::StorageDead(_) + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) | StatementKind::Intrinsic(_) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index dc546da734275..b7407f5a508e4 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -28,7 +28,7 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec args.extend(arg), - Err(err) => early_dcx.early_error(format!("Failed to load argument file: {err}")), + Err(err) => early_dcx.early_fatal(format!("Failed to load argument file: {err}")), } } args diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d67fea7e9a441..c277304fb221c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -345,7 +345,7 @@ fn run_compiler( Ok(None) => match matches.free.len() { 0 => false, // no input: we will exit early 1 => panic!("make_input should have provided valid inputs"), - _ => default_early_dcx.early_error(format!( + _ => default_early_dcx.early_fatal(format!( "multiple input filenames provided (first two filenames are `{}` and `{}`)", matches.free[0], matches.free[1], )), @@ -376,7 +376,7 @@ fn run_compiler( } if !has_input { - early_dcx.early_error("no input filename given"); // this is fatal + early_dcx.early_fatal("no input filename given"); // this is fatal } if !sess.opts.unstable_opts.ls.is_empty() { @@ -505,9 +505,8 @@ fn make_input( if io::stdin().read_to_string(&mut src).is_err() { // Immediately stop compilation if there was an issue reading // the input (for example if the input stream is not UTF-8). - let reported = early_dcx.early_error_no_abort( - "couldn't read from stdin, as it did not contain valid UTF-8", - ); + let reported = early_dcx + .early_err("couldn't read from stdin, as it did not contain valid UTF-8"); return Err(reported); } if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { @@ -567,7 +566,7 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col } } Err(InvalidErrorCode) => { - early_dcx.early_error(format!("{code} is not a valid error code")); + early_dcx.early_fatal(format!("{code} is not a valid error code")); } } } @@ -685,7 +684,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy safe_println!("{}", String::from_utf8(v).unwrap()); } Input::Str { .. } => { - early_dcx.early_error("cannot list metadata for stdin"); + early_dcx.early_fatal("cannot list metadata for stdin"); } } } @@ -839,7 +838,7 @@ fn print_crate_info( println_info!("deployment_target={}", format!("{major}.{minor}")) } else { early_dcx - .early_error("only Apple targets currently support deployment version info") + .early_fatal("only Apple targets currently support deployment version info") } } } @@ -1182,7 +1181,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option None, }; - early_dcx.early_error(msg.unwrap_or_else(|| e.to_string())); + early_dcx.early_fatal(msg.unwrap_or_else(|| e.to_string())); }); // For all options we just parsed, we check a few aspects: @@ -1333,7 +1332,7 @@ pub fn install_ice_hook( { // the error code is already going to be reported when the panic unwinds up the stack let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - let _ = early_dcx.early_error_no_abort(msg.clone()); + let _ = early_dcx.early_err(msg.clone()); return; } }; @@ -1481,7 +1480,7 @@ pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) { /// the values directly rather than having to set an environment variable. pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { if let Err(error) = rustc_log::init_logger(cfg) { - early_dcx.early_error(error.to_string()); + early_dcx.early_fatal(error.to_string()); } } @@ -1500,7 +1499,7 @@ pub fn main() -> ! { .enumerate() .map(|(i, arg)| { arg.into_string().unwrap_or_else(|arg| { - early_dcx.early_error(format!("argument {i} is not valid Unicode: {arg:?}")) + early_dcx.early_fatal(format!("argument {i} is not valid Unicode: {arg:?}")) }) }) .collect::>(); diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index da266bf9c63e4..48e48f59a9992 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -60,7 +60,7 @@ impl Emitter for AnnotateSnippetEmitterWriter { self.emit_messages_default( &diag.level, - &diag.message, + &diag.messages, &fluent_args, &diag.code, &primary_span, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index be506806065d3..c226b2d41bdef 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -103,7 +103,7 @@ pub struct Diagnostic { // outside of what methods in this crate themselves allow. pub(crate) level: Level, - pub message: Vec<(DiagnosticMessage, Style)>, + pub messages: Vec<(DiagnosticMessage, Style)>, pub code: Option, pub span: MultiSpan, pub children: Vec, @@ -161,9 +161,8 @@ pub enum DiagnosticId { #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub struct SubDiagnostic { pub level: Level, - pub message: Vec<(DiagnosticMessage, Style)>, + pub messages: Vec<(DiagnosticMessage, Style)>, pub span: MultiSpan, - pub render_span: Option, } #[derive(Debug, PartialEq, Eq)] @@ -216,14 +215,14 @@ impl StringPart { impl Diagnostic { #[track_caller] pub fn new>(level: Level, message: M) -> Self { - Diagnostic::new_with_code(level, None, message) + Diagnostic::new_with_messages(level, vec![(message.into(), Style::NoStyle)]) } #[track_caller] pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>) -> Self { Diagnostic { level, - message: messages, + messages, code: None, span: MultiSpan::new(), children: vec![], @@ -235,26 +234,6 @@ impl Diagnostic { } } - #[track_caller] - pub(crate) fn new_with_code>( - level: Level, - code: Option, - message: M, - ) -> Self { - Diagnostic { - level, - message: vec![(message.into(), Style::NoStyle)], - code, - span: MultiSpan::new(), - children: vec![], - suggestions: Ok(vec![]), - args: Default::default(), - sort_span: DUMMY_SP, - is_lint: false, - emitted_at: DiagnosticLocation::caller(), - } - } - #[inline(always)] pub fn level(&self) -> Level { self.level @@ -445,7 +424,7 @@ impl Diagnostic { /// Add a note attached to this diagnostic. #[rustc_lint_diagnostics] pub fn note(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Note, msg, MultiSpan::new(), None); + self.sub(Level::Note, msg, MultiSpan::new()); self } @@ -453,14 +432,14 @@ impl Diagnostic { &mut self, msg: Vec<(M, Style)>, ) -> &mut Self { - self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None); + self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self } /// Prints the span with a note above it. /// This is like [`Diagnostic::note()`], but it gets its own span. pub fn note_once(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::OnceNote, msg, MultiSpan::new(), None); + self.sub(Level::OnceNote, msg, MultiSpan::new()); self } @@ -472,7 +451,7 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::Note, msg, sp.into(), None); + self.sub(Level::Note, msg, sp.into()); self } @@ -483,14 +462,14 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::OnceNote, msg, sp.into(), None); + self.sub(Level::OnceNote, msg, sp.into()); self } /// Add a warning attached to this diagnostic. #[rustc_lint_diagnostics] pub fn warn(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Warning(None), msg, MultiSpan::new(), None); + self.sub(Level::Warning(None), msg, MultiSpan::new()); self } @@ -502,27 +481,27 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::Warning(None), msg, sp.into(), None); + self.sub(Level::Warning(None), msg, sp.into()); self } /// Add a help message attached to this diagnostic. #[rustc_lint_diagnostics] pub fn help(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Help, msg, MultiSpan::new(), None); + self.sub(Level::Help, msg, MultiSpan::new()); self } /// Prints the span with a help above it. /// This is like [`Diagnostic::help()`], but it gets its own span. pub fn help_once(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::OnceHelp, msg, MultiSpan::new(), None); + self.sub(Level::OnceHelp, msg, MultiSpan::new()); self } /// Add a help message attached to this diagnostic with a customizable highlighted message. pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { - self.sub_with_highlights(Level::Help, msg, MultiSpan::new(), None); + self.sub_with_highlights(Level::Help, msg, MultiSpan::new()); self } @@ -534,7 +513,7 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::Help, msg, sp.into(), None); + self.sub(Level::Help, msg, sp.into()); self } @@ -925,7 +904,7 @@ impl Diagnostic { } pub fn set_primary_message(&mut self, msg: impl Into) -> &mut Self { - self.message[0] = (msg.into(), Style::NoStyle); + self.messages[0] = (msg.into(), Style::NoStyle); self } @@ -952,8 +931,8 @@ impl Diagnostic { self.args = args; } - pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] { - &self.message + pub fn messages(&self) -> &[(DiagnosticMessage, Style)] { + &self.messages } /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by @@ -964,7 +943,7 @@ impl Diagnostic { attr: impl Into, ) -> DiagnosticMessage { let msg = - self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); + self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); msg.with_subdiagnostic_message(attr.into()) } @@ -972,21 +951,14 @@ impl Diagnostic { /// public methods above. /// /// Used by `proc_macro_server` for implementing `server::Diagnostic`. - pub fn sub( - &mut self, - level: Level, - message: impl Into, - span: MultiSpan, - render_span: Option, - ) { + pub fn sub(&mut self, level: Level, message: impl Into, span: MultiSpan) { let sub = SubDiagnostic { level, - message: vec![( + messages: vec![( self.subdiagnostic_message_to_diagnostic_message(message), Style::NoStyle, )], span, - render_span, }; self.children.push(sub); } @@ -996,15 +968,14 @@ impl Diagnostic { fn sub_with_highlights>( &mut self, level: Level, - message: Vec<(M, Style)>, + messages: Vec<(M, Style)>, span: MultiSpan, - render_span: Option, ) { - let message = message + let messages = messages .into_iter() .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) .collect(); - let sub = SubDiagnostic { level, message, span, render_span }; + let sub = SubDiagnostic { level, messages, span }; self.children.push(sub); } @@ -1022,7 +993,7 @@ impl Diagnostic { ) { ( &self.level, - &self.message, + &self.messages, self.args().collect(), &self.code, &self.span, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 828560ec452cf..4703e71523dde 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -15,7 +15,7 @@ use std::ops::{Deref, DerefMut}; use std::panic; use std::thread::panicking; -/// Trait implemented by error types. This should not be implemented manually. Instead, use +/// Trait implemented by error types. This is rarely implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. #[rustc_diagnostic_item = "IntoDiagnostic"] pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { @@ -43,24 +43,7 @@ where /// extending `DiagCtxtFlags`. #[must_use] #[derive(Clone)] -pub struct DiagnosticBuilder<'a, G: EmissionGuarantee> { - inner: DiagnosticBuilderInner<'a>, - _marker: PhantomData, -} - -/// This type exists only for `DiagnosticBuilder::forget_guarantee`, because it: -/// 1. lacks the `G` parameter and therefore `DiagnosticBuilder` can be -/// converted into `DiagnosticBuilder` while reusing the `inner` field -/// 2. can implement the `Drop` "bomb" instead of `DiagnosticBuilder`, as it -/// contains all of the data (`state` + `diagnostic`) of `DiagnosticBuilder` -/// -/// The `diagnostic` field is not `Copy` and can't be moved out of whichever -/// type implements the `Drop` "bomb", but because of the above two facts, that -/// never needs to happen - instead, the whole `inner: DiagnosticBuilderInner` -/// can be moved out of a `DiagnosticBuilder` and into another. -#[must_use] -#[derive(Clone)] -struct DiagnosticBuilderInner<'a> { +pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { state: DiagnosticBuilderState<'a>, /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a @@ -68,6 +51,8 @@ struct DiagnosticBuilderInner<'a> { /// In theory, return value optimization (RVO) should avoid unnecessary /// copying. In practice, it does not (at the time of writing). diagnostic: Box, + + _marker: PhantomData, } #[derive(Clone)] @@ -83,7 +68,7 @@ enum DiagnosticBuilderState<'a> { /// assumed that `.emit()` was previously called, to end up in this state. /// /// While this is also used by `.cancel()`, this state is only observed by - /// the `Drop` `impl` of `DiagnosticBuilderInner`, as `.cancel()` takes + /// the `Drop` `impl` of `DiagnosticBuilder`, because `.cancel()` takes /// `self` by-value specifically to prevent any attempts to `.emit()`. /// // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`, @@ -115,12 +100,11 @@ pub trait EmissionGuarantee: Sized { 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 { + match self.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); + self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + dcx.emit_diagnostic_without_consuming(&mut self.diagnostic); } // `.emit()` was previously called, disallowed from repeating it. DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} @@ -128,34 +112,24 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } } -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 - /// is a common codepath handling both errors and warnings. - pub fn forget_guarantee(self) -> DiagnosticBuilder<'a, ()> { - DiagnosticBuilder { inner: self.inner, _marker: PhantomData } - } -} - // 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 { + match db.state { // First `.emit()` call, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => { - db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - - let guar = dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic); + db.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + let guar = dcx.emit_diagnostic_without_consuming(&mut db.diagnostic); // Only allow a guarantee if the `level` wasn't switched to a // non-error - the field isn't `pub`, but the whole `Diagnostic` // can be overwritten with a new one, thanks to `DerefMut`. assert!( - db.inner.diagnostic.is_error(), + db.diagnostic.is_error(), "emitted non-error ({:?}) diagnostic \ from `DiagnosticBuilder`", - db.inner.diagnostic.level, + db.diagnostic.level, ); guar.unwrap() } @@ -167,10 +141,10 @@ impl EmissionGuarantee for ErrorGuaranteed { // non-error - the field isn't `pub`, but the whole `Diagnostic` // can be overwritten with a new one, thanks to `DerefMut`. assert!( - db.inner.diagnostic.is_error(), + db.diagnostic.is_error(), "`DiagnosticBuilder`'s diagnostic \ became non-error ({:?}), after original `.emit()`", - db.inner.diagnostic.level, + db.diagnostic.level, ); #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() @@ -238,7 +212,7 @@ macro_rules! forward { $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { - self.inner.diagnostic.$n($($name),*); + self.diagnostic.$n($($name),*); self } }; @@ -248,13 +222,13 @@ impl Deref for DiagnosticBuilder<'_, G> { type Target = Diagnostic; fn deref(&self) -> &Diagnostic { - &self.inner.diagnostic + &self.diagnostic } } impl DerefMut for DiagnosticBuilder<'_, G> { fn deref_mut(&mut self) -> &mut Diagnostic { - &mut self.inner.diagnostic + &mut self.diagnostic } } @@ -271,10 +245,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diagnostic: Diagnostic) -> Self { debug!("Created new diagnostic"); Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(dcx), - diagnostic: Box::new(diagnostic), - }, + state: DiagnosticBuilderState::Emittable(dcx), + diagnostic: Box::new(diagnostic), _marker: PhantomData, } } @@ -306,7 +278,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// which may be expected to *guarantee* the emission of an error, either /// at the time of the call, or through a prior `.emit()` call. pub fn cancel(mut self) { - self.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; drop(self); } @@ -324,7 +296,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Converts the builder to a `Diagnostic` for later emission, /// 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 { + let dcx = match self.state { // No `.emit()` calls, the `&DiagCtxt` is still available. DiagnosticBuilderState::Emittable(dcx) => dcx, // `.emit()` was previously called, nothing we can do. @@ -342,7 +314,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { // Take the `Diagnostic` by replacing it with a dummy. let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::from("")); - let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy); + let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy); // Disable the ICE on `Drop`. self.cancel(); @@ -356,7 +328,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Retrieves the [`DiagCtxt`] if available pub fn dcx(&self) -> Option<&DiagCtxt> { - match self.inner.state { + match self.state { DiagnosticBuilderState::Emittable(dcx) => Some(dcx), DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None, } @@ -544,13 +516,13 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { impl Debug for DiagnosticBuilder<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.diagnostic.fmt(f) + self.diagnostic.fmt(f) } } /// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled /// or we emit a bug. -impl Drop for DiagnosticBuilderInner<'_> { +impl Drop for DiagnosticBuilder<'_, G> { fn drop(&mut self) { match self.state { // No `.emit()` or `.cancel()` calls. diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index ccc951543d8e6..29cb304e8b5b0 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -312,25 +312,13 @@ impl IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> pub struct SingleLabelManySpans { pub spans: Vec, pub label: &'static str, - pub kind: LabelKind, } impl AddToDiagnostic for SingleLabelManySpans { fn add_to_diagnostic_with(self, diag: &mut crate::Diagnostic, _: F) { - match self.kind { - LabelKind::Note => diag.span_note(self.spans, self.label), - LabelKind::Label => diag.span_labels(self.spans, self.label), - LabelKind::Help => diag.span_help(self.spans, self.label), - }; + diag.span_labels(self.spans, self.label); } } -/// The kind of label to attach when using [`SingleLabelManySpans`] -pub enum LabelKind { - Note, - Label, - Help, -} - #[derive(Subdiagnostic)] #[label(errors_expected_lifetime_parameter)] pub struct ExpectedLifetimeParameter { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 3fb993c3651b2..546159c9d13dd 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -350,9 +350,8 @@ pub trait Emitter: Translate { children.push(SubDiagnostic { level: Level::Note, - message: vec![(DiagnosticMessage::from(msg), Style::NoStyle)], + messages: vec![(DiagnosticMessage::from(msg), Style::NoStyle)], span: MultiSpan::new(), - render_span: None, }); } } @@ -533,7 +532,7 @@ impl Emitter for EmitterWriter { self.emit_messages_default( &diag.level, - &diag.message, + &diag.messages, &fluent_args, &diag.code, &primary_span, @@ -1228,10 +1227,10 @@ impl EmitterWriter { /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. - fn msg_to_buffer( + fn msgs_to_buffer( &self, buffer: &mut StyledBuffer, - msg: &[(DiagnosticMessage, Style)], + msgs: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, padding: usize, label: &str, @@ -1267,7 +1266,7 @@ impl EmitterWriter { // Provided the following diagnostic message: // - // let msg = vec![ + // let msgs = vec![ // (" // ("highlighted multiline\nstring to\nsee how it ", Style::NoStyle), // ("looks", Style::Highlight), @@ -1284,7 +1283,7 @@ impl EmitterWriter { // see how it *looks* with // very *weird* formats // see? - for (text, style) in msg.iter() { + for (text, style) in msgs.iter() { let text = self.translate_message(text, args).map_err(Report::new).unwrap(); let text = &normalize_whitespace(&text); let lines = text.split('\n').collect::>(); @@ -1303,10 +1302,10 @@ impl EmitterWriter { } #[instrument(level = "trace", skip(self, args), ret)] - fn emit_message_default( + fn emit_messages_default_inner( &mut self, msp: &MultiSpan, - msg: &[(DiagnosticMessage, Style)], + msgs: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, code: &Option, level: &Level, @@ -1327,7 +1326,7 @@ impl EmitterWriter { buffer.append(0, level.to_str(), Style::MainHeaderMsg); buffer.append(0, ": ", Style::NoStyle); } - self.msg_to_buffer(&mut buffer, msg, args, max_line_num_len, "note", None); + self.msgs_to_buffer(&mut buffer, msgs, args, max_line_num_len, "note", None); } else { let mut label_width = 0; // The failure note level itself does not provide any useful diagnostic information @@ -1360,7 +1359,7 @@ impl EmitterWriter { buffer.append(0, ": ", header_style); label_width += 2; } - for (text, _) in msg.iter() { + for (text, _) in msgs.iter() { let text = self.translate_message(text, args).map_err(Report::new).unwrap(); // Account for newlines to align output to its label. for (line, text) in normalize_whitespace(&text).lines().enumerate() { @@ -1747,7 +1746,7 @@ impl EmitterWriter { buffer.append(0, level.to_str(), Style::Level(*level)); buffer.append(0, ": ", Style::HeaderMsg); - self.msg_to_buffer( + self.msgs_to_buffer( &mut buffer, &[(suggestion.msg.to_owned(), Style::NoStyle)], args, @@ -2074,7 +2073,7 @@ impl EmitterWriter { fn emit_messages_default( &mut self, level: &Level, - message: &[(DiagnosticMessage, Style)], + messages: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, code: &Option, span: &MultiSpan, @@ -2089,9 +2088,9 @@ impl EmitterWriter { num_decimal_digits(n) }; - match self.emit_message_default( + match self.emit_messages_default_inner( span, - message, + messages, args, code, level, @@ -2118,10 +2117,10 @@ impl EmitterWriter { } if !self.short_message { for child in children { - let span = child.render_span.as_ref().unwrap_or(&child.span); - if let Err(err) = self.emit_message_default( + let span = &child.span; + if let Err(err) = self.emit_messages_default_inner( span, - &child.message, + &child.messages, args, &None, &child.level, @@ -2138,7 +2137,7 @@ impl EmitterWriter { // do not display this suggestion, it is meant only for tools } SuggestionStyle::HideCodeAlways => { - if let Err(e) = self.emit_message_default( + if let Err(e) = self.emit_messages_default_inner( &MultiSpan::new(), &[(sugg.msg.to_owned(), Style::HeaderMsg)], args, diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index aa3749334d97d..52fcb50e9fb96 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -398,7 +398,7 @@ impl Diagnostic { let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); - let translated_message = je.translate_messages(&diag.message, &args); + let translated_message = je.translate_messages(&diag.messages, &args); Diagnostic { message: translated_message.to_string(), code: DiagnosticCode::map_opt_string(diag.code.clone(), je), @@ -419,16 +419,12 @@ impl Diagnostic { args: &FluentArgs<'_>, je: &JsonEmitter, ) -> Diagnostic { - let translated_message = je.translate_messages(&diag.message, args); + let translated_message = je.translate_messages(&diag.messages, args); Diagnostic { message: translated_message.to_string(), code: None, level: diag.level.to_str(), - spans: diag - .render_span - .as_ref() - .map(|sp| DiagnosticSpan::from_multispan(sp, args, je)) - .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)), + spans: DiagnosticSpan::from_multispan(&diag.span, args, je), children: vec![], rendered: None, } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 518a2ddb71dd9..7a1faac04d3a7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -27,26 +27,42 @@ extern crate tracing; extern crate self as rustc_errors; +pub use diagnostic::{ + AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, + DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, +}; +pub use diagnostic_builder::{ + BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic, +}; +pub use diagnostic_impls::{ + DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, + IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, SingleLabelManySpans, +}; pub use emitter::ColorConfig; +pub use rustc_error_messages::{ + fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, + LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, +}; +pub use rustc_lint_defs::{pluralize, Applicability}; +pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; +pub use rustc_span::ErrorGuaranteed; +pub use snippet::Style; -use rustc_lint_defs::LintExpectationId; -use Level::*; +// Used by external projects such as `rust-gpu`. +// See https://github.com/rust-lang/rust/pull/115393. +pub use termcolor::{Color, ColorSpec, WriteColor}; +use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; use emitter::{is_case_difference, DynEmitter, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::AtomicRef; -pub use rustc_error_messages::{ - fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, - LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, -}; -pub use rustc_lint_defs::{pluralize, Applicability}; +use rustc_lint_defs::LintExpectationId; use rustc_span::source_map::SourceMap; -pub use rustc_span::ErrorGuaranteed; use rustc_span::{Loc, Span, DUMMY_SP}; - +use std::backtrace::{Backtrace, BacktraceStatus}; use std::borrow::Cow; use std::error::Report; use std::fmt; @@ -56,9 +72,7 @@ use std::num::NonZeroUsize; use std::panic; use std::path::{Path, PathBuf}; -// Used by external projects such as `rust-gpu`. -// See https://github.com/rust-lang/rust/pull/115393. -pub use termcolor::{Color, ColorSpec, WriteColor}; +use Level::*; pub mod annotate_snippet_emitter_writer; mod diagnostic; @@ -76,10 +90,7 @@ mod styled_buffer; mod tests; pub mod translation; -pub use diagnostic_builder::IntoDiagnostic; -pub use snippet::Style; - -pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>; +pub type PErr<'a> = DiagnosticBuilder<'a>; pub type PResult<'a, T> = Result>; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -163,7 +174,7 @@ pub struct SubstitutionPart { /// Used to translate between `Span`s and byte positions within a single output line in highlighted /// code of structured suggestions. #[derive(Debug, Clone, Copy)] -pub struct SubstitutionHighlight { +pub(crate) struct SubstitutionHighlight { start: usize, end: usize, } @@ -190,7 +201,7 @@ impl SubstitutionPart { impl CodeSuggestion { /// Returns the assembled code suggestions, whether they should be shown with an underline /// and whether the substitution only differs in capitalization. - pub fn splice_lines( + pub(crate) fn splice_lines( &self, sm: &SourceMap, ) -> Vec<(String, Vec, Vec>, bool)> { @@ -387,8 +398,6 @@ impl CodeSuggestion { } } -pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; - /// Signifies that the compiler died with an explicit call to `.bug` /// or `.span_bug` rather than a failed assertion, etc. pub struct ExplicitBug; @@ -397,20 +406,7 @@ pub struct ExplicitBug; /// rather than a failed assertion, etc. pub struct DelayedBugPanic; -use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; -pub use diagnostic::{ - AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, - DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, -}; -pub use diagnostic_builder::{BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort}; -pub use diagnostic_impls::{ - DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, - IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, LabelKind, - SingleLabelManySpans, -}; -use std::backtrace::{Backtrace, BacktraceStatus}; - -/// A handler deals with errors and other compiler output. +/// A `DiagCtxt` deals with errors and other compiler output. /// Certain errors (fatal, bug, unimpl) may cause immediate exit, /// others log errors for later reporting. pub struct DiagCtxt { @@ -447,7 +443,7 @@ struct DiagCtxtInner { emitted_diagnostic_codes: FxIndexSet, /// This set contains a hash of every diagnostic that has been emitted by - /// this handler. These hashes is used to avoid emitting the same error + /// this `DiagCtxt`. These hashes is used to avoid emitting the same error /// twice. emitted_diagnostics: FxHashSet, @@ -677,7 +673,7 @@ impl DiagCtxt { let key = (span.with_parent(None), key); if diag.is_error() { - if matches!(diag.level, Level::Error { lint: true }) { + if matches!(diag.level, Error { lint: true }) { inner.lint_err_count += 1; } else { inner.err_count += 1; @@ -701,7 +697,7 @@ impl DiagCtxt { let key = (span.with_parent(None), key); let diag = inner.stashed_diagnostics.remove(&key)?; if diag.is_error() { - if matches!(diag.level, Level::Error { lint: true }) { + if matches!(diag.level, Error { lint: true }) { inner.lint_err_count -= 1; } else { inner.err_count -= 1; @@ -740,37 +736,6 @@ impl DiagCtxt { result } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// The `id` is used for lint emissions which should also fulfill a lint expectation. - /// - /// Attempting to `.emit()` the builder will only emit if either: - /// * `can_emit_warnings` is `true` - /// * `is_force_warn` was set in `DiagnosticId::Lint` - #[track_caller] - pub fn struct_span_warn_with_expectation( - &self, - span: impl Into, - msg: impl Into, - id: LintExpectationId, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_warn_with_expectation(msg, id); - result.set_span(span); - result - } - - /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_allow( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_allow(msg); - result.set_span(span); - result - } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// Also include a code. #[rustc_lint_diagnostics] @@ -794,29 +759,14 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Warning(None), msg) - } - - /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for - /// lint emissions which should also fulfill a lint expectation. - /// - /// Attempting to `.emit()` the builder will only emit if either: - /// * `can_emit_warnings` is `true` - /// * `is_force_warn` was set in `DiagnosticId::Lint` - #[track_caller] - pub fn struct_warn_with_expectation( - &self, - msg: impl Into, - id: LintExpectationId, - ) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg) + DiagnosticBuilder::new(self, Warning(None), msg) } /// Construct a builder at the `Allow` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Allow, msg) + DiagnosticBuilder::new(self, Allow, msg) } /// Construct a builder at the `Expect` level with the `msg`. @@ -827,7 +777,7 @@ impl DiagCtxt { msg: impl Into, id: LintExpectationId, ) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Expect(id), msg) + DiagnosticBuilder::new(self, Expect(id), msg) } /// Construct a builder at the `Error` level at the given `span` and with the `msg`. @@ -837,7 +787,7 @@ impl DiagCtxt { &self, span: impl Into, msg: impl Into, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { let mut result = self.struct_err(msg); result.set_span(span); result @@ -851,7 +801,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { let mut result = self.struct_span_err(span, msg); result.code(code); result @@ -861,18 +811,8 @@ impl DiagCtxt { // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_err( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - DiagnosticBuilder::new(self, Level::Error { lint: false }, msg) - } - - /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. - #[doc(hidden)] - #[track_caller] - pub fn struct_err_lint(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Error { lint: true }, msg) + pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> { + DiagnosticBuilder::new(self, Error { lint: false }, msg) } /// Construct a builder at the `Error` level with the `msg` and the `code`. @@ -882,7 +822,7 @@ impl DiagCtxt { &self, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { let mut result = self.struct_err(msg); result.code(code); result @@ -935,7 +875,7 @@ impl DiagCtxt { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, FatalAbort> { - DiagnosticBuilder::new(self, Level::Fatal, msg) + DiagnosticBuilder::new(self, Fatal, msg) } /// Construct a builder at the `Fatal` level with the `msg`, that doesn't abort. @@ -945,27 +885,27 @@ impl DiagCtxt { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, FatalError> { - DiagnosticBuilder::new(self, Level::Fatal, msg) + DiagnosticBuilder::new(self, Fatal, msg) } /// Construct a builder at the `Help` level with the `msg`. #[rustc_lint_diagnostics] pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Help, msg) + DiagnosticBuilder::new(self, Help, msg) } /// Construct a builder at the `Note` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Note, msg) + DiagnosticBuilder::new(self, 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) + DiagnosticBuilder::new(self, Bug, msg) } /// Construct a builder at the `Bug` level at the given `span` with the `msg`. @@ -1037,7 +977,7 @@ impl DiagCtxt { } pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { - self.inner.borrow_mut().span_bug(span, msg) + self.struct_span_bug(span, msg).emit() } /// For documentation on this, see `Session::span_delayed_bug`. @@ -1050,20 +990,14 @@ impl DiagCtxt { sp: impl Into, msg: impl Into, ) -> ErrorGuaranteed { - let mut inner = self.inner.borrow_mut(); - - // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before - // incrementing `err_count` by one, so we need to +1 the comparing. - // FIXME: Would be nice to increment err_count in a more coherent way. - if inner.flags.treat_err_as_bug.is_some_and(|c| { - inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get() - }) { + let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug(); + if treat_next_err_as_bug { // FIXME: don't abort here if report_delayed_bugs is off - inner.span_bug(sp, msg); + self.span_bug(sp, msg); } - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); + let mut diagnostic = Diagnostic::new(DelayedBug, msg); diagnostic.set_span(sp); - inner.emit_diagnostic(diagnostic).unwrap() + self.emit_diagnostic(diagnostic).unwrap() } // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's @@ -1071,7 +1005,7 @@ impl DiagCtxt { pub fn good_path_delayed_bug(&self, msg: impl Into) { let mut inner = self.inner.borrow_mut(); - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); + let mut diagnostic = Diagnostic::new(DelayedBug, msg); if inner.flags.report_delayed_bugs { inner.emit_diagnostic_without_consuming(&mut diagnostic); } @@ -1184,10 +1118,9 @@ impl DiagCtxt { match (errors.len(), warnings.len()) { (0, 0) => return, - (0, _) => inner.emitter.emit_diagnostic(&Diagnostic::new( - Level::Warning(None), - DiagnosticMessage::Str(warnings), - )), + (0, _) => inner + .emitter + .emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))), (_, 0) => { inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); } @@ -1219,14 +1152,12 @@ impl DiagCtxt { if error_codes.len() > 9 { "..." } else { "." } )); inner.failure_note(format!( - "For more information about an error, try \ - `rustc --explain {}`.", + "For more information about an error, try `rustc --explain {}`.", &error_codes[0] )); } else { inner.failure_note(format!( - "For more information about this error, try \ - `rustc --explain {}`.", + "For more information about this error, try `rustc --explain {}`.", &error_codes[0] )); } @@ -1277,18 +1208,15 @@ impl DiagCtxt { } #[track_caller] - pub fn create_err<'a>( - &'a self, - err: impl IntoDiagnostic<'a>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(self, Level::Error { lint: false }) + pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { + err.into_diagnostic(self, Error { lint: false }) } pub fn create_warning<'a>( &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self, Level::Warning(None)) + warning.into_diagnostic(self, Warning(None)) } pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { @@ -1299,7 +1227,7 @@ impl DiagCtxt { &'a self, fatal: impl IntoDiagnostic<'a, FatalError>, ) -> DiagnosticBuilder<'a, FatalError> { - fatal.into_diagnostic(self, Level::Fatal) + fatal.into_diagnostic(self, Fatal) } pub fn emit_almost_fatal<'a>( @@ -1313,7 +1241,7 @@ impl DiagCtxt { &'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>, ) -> DiagnosticBuilder<'a, FatalAbort> { - fatal.into_diagnostic(self, Level::Fatal) + fatal.into_diagnostic(self, Fatal) } pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { @@ -1324,7 +1252,7 @@ impl DiagCtxt { &'a self, bug: impl IntoDiagnostic<'a, BugAbort>, ) -> DiagnosticBuilder<'a, BugAbort> { - bug.into_diagnostic(self, Level::Bug) + bug.into_diagnostic(self, Bug) } pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! { @@ -1339,7 +1267,7 @@ impl DiagCtxt { &'a self, note: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - note.into_diagnostic(self, Level::Note) + note.into_diagnostic(self, Note) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { @@ -1426,7 +1354,7 @@ impl DiagCtxtInner { for diag in diags { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - if matches!(diag.level, Level::Error { lint: true }) { + if matches!(diag.level, Error { lint: true }) { self.lint_err_count -= 1; } else { self.err_count -= 1; @@ -1457,9 +1385,8 @@ impl DiagCtxtInner { &mut self, diagnostic: &mut Diagnostic, ) -> Option { - if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug() - { - diagnostic.level = Level::Bug; + if matches!(diagnostic.level, Error { .. } | Fatal) && self.treat_err_as_bug() { + diagnostic.level = Bug; } // The `LintExpectationId` can be stable or unstable depending on when it was created. @@ -1471,7 +1398,7 @@ impl DiagCtxtInner { return None; } - if diagnostic.level == Level::DelayedBug { + if diagnostic.level == DelayedBug { // FIXME(eddyb) this should check for `has_errors` and stop pushing // once *any* errors were emitted (and truncate `span_delayed_bugs` // when an error is first emitted, also), but maybe there's a case @@ -1487,7 +1414,7 @@ impl DiagCtxtInner { } if diagnostic.has_future_breakage() { - // Future breakages aren't emitted if they're Level::Allowed, + // Future breakages aren't emitted if they're Level::Allow, // but they still need to be constructed and stashed below, // so they'll trigger the good-path bug check. self.suppressed_expected_diag = true; @@ -1509,7 +1436,7 @@ impl DiagCtxtInner { return None; } - if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) { + if matches!(diagnostic.level, Expect(_) | Allow) { (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {}); return None; } @@ -1534,7 +1461,7 @@ impl DiagCtxtInner { debug!(?self.emitted_diagnostics); let already_emitted_sub = |sub: &mut SubDiagnostic| { debug!(?sub); - if sub.level != Level::OnceNote && sub.level != Level::OnceHelp { + if sub.level != OnceNote && sub.level != OnceHelp { return false; } let mut hasher = StableHasher::new(); @@ -1559,7 +1486,7 @@ impl DiagCtxtInner { } } if diagnostic.is_error() { - if matches!(diagnostic.level, Level::Error { lint: true }) { + if matches!(diagnostic.level, Error { lint: true }) { self.bump_lint_err_count(); } else { self.bump_err_count(); @@ -1583,6 +1510,13 @@ impl DiagCtxtInner { }) } + // Use this one before incrementing `err_count`. + fn treat_next_err_as_bug(&self) -> bool { + self.flags.treat_err_as_bug.is_some_and(|c| { + self.err_count + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get() + }) + } + fn delayed_bug_count(&self) -> usize { self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len() } @@ -1591,27 +1525,22 @@ impl DiagCtxtInner { self.err_count > 0 } - #[track_caller] - fn span_bug(&mut self, sp: impl Into, msg: impl Into) -> ! { - let mut diag = Diagnostic::new(Bug, msg); - diag.set_span(sp); - self.emit_diagnostic(diag); - panic::panic_any(ExplicitBug); - } - fn failure_note(&mut self, msg: impl Into) { self.emit_diagnostic(Diagnostic::new(FailureNote, msg)); } fn flush_delayed( &mut self, - bugs: impl IntoIterator, + bugs: Vec, explanation: impl Into + Copy, ) { - let mut no_bugs = true; + if bugs.is_empty() { + return; + } + // If backtraces are enabled, also print the query stack let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); - for bug in bugs { + for (i, bug) in bugs.into_iter().enumerate() { if let Some(file) = self.ice_file.as_ref() && let Ok(mut out) = std::fs::File::options().create(true).append(true).open(file) { @@ -1619,25 +1548,25 @@ impl DiagCtxtInner { &mut out, "delayed span bug: {}\n{}\n", bug.inner - .styled_message() + .messages() .iter() .filter_map(|(msg, _)| msg.as_str()) .collect::(), &bug.note ); } - let mut bug = - if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; - if no_bugs { + if i == 0 { // Put the overall explanation before the `DelayedBug`s, to // frame them better (e.g. separate warnings from them). self.emit_diagnostic(Diagnostic::new(Bug, explanation)); - no_bugs = false; } + let mut bug = + if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; + // "Undelay" the `DelayedBug`s (into plain `Bug`s). - if bug.level != Level::DelayedBug { + if bug.level != DelayedBug { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { @@ -1645,15 +1574,13 @@ impl DiagCtxtInner { level: bug.level, }); } - bug.level = Level::Bug; + bug.level = Bug; self.emit_diagnostic(bug); } // Panic with `DelayedBugPanic` to avoid "unexpected panic" messages. - if !no_bugs { - panic::panic_any(DelayedBugPanic); - } + panic::panic_any(DelayedBugPanic); } fn bump_lint_err_count(&mut self) { @@ -1731,25 +1658,80 @@ impl DelayedDiagnostic { #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { + /// For bugs in the compiler. Manifests as an ICE (internal compiler error) panic. + /// + /// Its `EmissionGuarantee` is `BugAbort`. Bug, + + /// This is a strange one: lets you register an error without emitting it. If compilation ends + /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be + /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths + /// that should only be reached when compiling erroneous code. + /// + /// Its `EmissionGuarantee` is `ErrorGuaranteed`. DelayedBug, + + /// An error that causes an immediate abort. Used for things like configuration errors, + /// internal overflows, some file operation errors. + /// + /// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case + /// that is occasionaly used, where it is `FatalError`. Fatal, + + /// An error in the code being compiled, which prevents compilation from finishing. This is the + /// most common case. + /// + /// Its `EmissionGuarantee` is `ErrorGuaranteed`. Error { - /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called. + /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is + /// called. lint: bool, }, + + /// A warning about the code being compiled. Does not prevent compilation from finishing. + /// /// This [`LintExpectationId`] is used for expected lint diagnostics, which should /// also emit a warning due to the `force-warn` flag. In all other cases this should /// be `None`. + /// + /// Its `EmissionGuarantee` is `()`. Warning(Option), + + /// A message giving additional context. Rare, because notes are more commonly attached to other + /// diagnostics such as errors. + /// + /// Its `EmissionGuarantee` is `()`. Note, - /// A note that is only emitted once. + + /// A note that is only emitted once. Rare, mostly used in circumstances relating to lints. + /// + /// Its `EmissionGuarantee` is `()`. OnceNote, + + /// A message suggesting how to fix something. Rare, because help messages are more commonly + /// attached to other diagnostics such as errors. + /// + /// Its `EmissionGuarantee` is `()`. Help, - /// A help that is only emitted once. + + /// A help that is only emitted once. Rare. + /// + /// Its `EmissionGuarantee` is `()`. OnceHelp, + + /// Similar to `Note`, but used in cases where compilation has failed. Rare. + /// + /// Its `EmissionGuarantee` is `()`. FailureNote, + + /// Only used for lints. + /// + /// Its `EmissionGuarantee` is `()`. Allow, + + /// Only used for lints. + /// + /// Its `EmissionGuarantee` is `()`. Expect(LintExpectationId), } @@ -1789,8 +1771,7 @@ impl Level { Note | OnceNote => "note", Help | OnceHelp => "help", FailureNote => "failure-note", - Allow => panic!("Shouldn't call on allowed error"), - Expect(_) => panic!("Shouldn't call on expected error"), + Allow | Expect(_) => unreachable!(), } } @@ -1800,7 +1781,7 @@ impl Level { pub fn get_expectation_id(&self) -> Option { match self { - Level::Expect(id) | Level::Warning(Some(id)) => Some(*id), + Expect(id) | Warning(Some(id)) => Some(*id), _ => None, } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ee0b10edfda04..1fd4d2d55dd81 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1118,15 +1118,12 @@ impl<'a> ExtCtxt<'a> { &self, sp: S, msg: impl Into, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { self.sess.dcx().struct_span_err(sp, msg) } #[track_caller] - pub fn create_err( - &self, - err: impl IntoDiagnostic<'a>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub fn create_err(&self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { self.sess.create_err(err) } @@ -1230,7 +1227,7 @@ pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P, err_msg: &'static str, -) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorGuaranteed>, bool)>> { +) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 8f80e6e2927ce..b6718ec8c411b 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -215,7 +215,7 @@ impl<'matcher> Tracker<'matcher> for FailureForwarder { } pub(super) fn emit_frag_parse_err( - mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>, + mut e: DiagnosticBuilder<'_>, parser: &Parser<'_>, orig_parser: &mut Parser<'_>, site_span: Span, @@ -224,11 +224,11 @@ pub(super) fn emit_frag_parse_err( ) { // FIXME(davidtwco): avoid depending on the error message text if parser.token == token::Eof - && let DiagnosticMessage::Str(message) = &e.message[0].0 + && let DiagnosticMessage::Str(message) = &e.messages[0].0 && message.ends_with(", found ``") { - let msg = &e.message[0]; - e.message[0] = ( + let msg = &e.messages[0]; + e.messages[0] = ( DiagnosticMessage::from(format!( "macro expansion ends with an incomplete expression: {}", message.replace(", found ``", ""), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 80fd82e030289..ac5f3fb325d95 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -9,8 +9,8 @@ use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagnosticBuilder; use rustc_errors::{pluralize, PResult}; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; @@ -528,7 +528,7 @@ fn out_of_bounds_err<'a>( max: usize, span: Span, ty: &str, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'a> { let msg = if max == 0 { format!( "meta-variable expression `{ty}` with depth parameter \ diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index a0dec89d63119..cd59ea9092c12 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -43,7 +43,7 @@ pub enum ModError<'a> { ModInBlock(Option), FileNotFound(Ident, PathBuf, PathBuf), MultipleCandidates(Ident, PathBuf, PathBuf), - ParserError(DiagnosticBuilder<'a, ErrorGuaranteed>), + ParserError(DiagnosticBuilder<'a>), } pub(crate) fn parse_external_mod( diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index c412b064ce966..5eb6aed72534d 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -499,12 +499,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); diag.set_span(MultiSpan::from_spans(diagnostic.spans)); for child in diagnostic.children { - diag.sub( - child.level.to_internal(), - child.message, - MultiSpan::from_spans(child.spans), - None, - ); + diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans)); } self.sess().dcx.emit_diagnostic(diag); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 26430dcf965fe..452f5d0b7ace9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1351,15 +1351,8 @@ impl<'hir> Body<'hir> { /// The type of source expression that caused this coroutine to be created. #[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] pub enum CoroutineKind { - /// An explicit `async` block or the body of an `async` function. - Async(CoroutineSource), - - /// An explicit `gen` block or the body of a `gen` function. - Gen(CoroutineSource), - - /// An explicit `async gen` block or the body of an `async gen` function, - /// which is able to both `yield` and `.await`. - AsyncGen(CoroutineSource), + /// A coroutine that comes from a desugaring. + Desugared(CoroutineDesugaring, CoroutineSource), /// A coroutine literal created via a `yield` inside a closure. Coroutine, @@ -1368,31 +1361,11 @@ pub enum CoroutineKind { impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CoroutineKind::Async(k) => { - if f.alternate() { - f.write_str("`async` ")?; - } else { - f.write_str("async ")? - } + CoroutineKind::Desugared(d, k) => { + d.fmt(f)?; k.fmt(f) } CoroutineKind::Coroutine => f.write_str("coroutine"), - CoroutineKind::Gen(k) => { - if f.alternate() { - f.write_str("`gen` ")?; - } else { - f.write_str("gen ")? - } - k.fmt(f) - } - CoroutineKind::AsyncGen(k) => { - if f.alternate() { - f.write_str("`async gen` ")?; - } else { - f.write_str("async gen ")? - } - k.fmt(f) - } } } } @@ -1425,6 +1398,49 @@ impl fmt::Display for CoroutineSource { } } +#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] +pub enum CoroutineDesugaring { + /// An explicit `async` block or the body of an `async` function. + Async, + + /// An explicit `gen` block or the body of a `gen` function. + Gen, + + /// An explicit `async gen` block or the body of an `async gen` function, + /// which is able to both `yield` and `.await`. + AsyncGen, +} + +impl fmt::Display for CoroutineDesugaring { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CoroutineDesugaring::Async => { + if f.alternate() { + f.write_str("`async` ")?; + } else { + f.write_str("async ")? + } + } + CoroutineDesugaring::Gen => { + if f.alternate() { + f.write_str("`gen` ")?; + } else { + f.write_str("gen ")? + } + } + CoroutineDesugaring::AsyncGen => { + if f.alternate() { + f.write_str("`async gen` ")?; + } else { + f.write_str("async gen ")? + } + } + } + + Ok(()) + } +} + #[derive(Copy, Clone, Debug)] pub enum BodyOwnerKind { /// Functions and methods. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7691cd11c4f55..3f3b57ba94f98 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -308,6 +308,7 @@ language_item_table! { FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; AsyncIteratorPollNext, sym::async_iterator_poll_next, async_iterator_poll_next, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); + IntoAsyncIterIntoIter, sym::into_async_iter_into_iter, into_async_iter_into_iter, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); Option, sym::Option, option_type, Target::Enum, GenericRequirement::None; OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6f8e80172dd26..d1f99f3b79951 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2686,7 +2686,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, constrained_regions: FxHashSet, referenced_regions: FxHashSet, - generate_err: impl Fn(&str) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>, + generate_err: impl Fn(&str) -> DiagnosticBuilder<'tcx>, ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b2ff795910693..cc34dbfd9b981 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1912,11 +1912,7 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))) } -fn error_392( - tcx: TyCtxt<'_>, - span: Span, - param_name: Symbol, -) -> DiagnosticBuilder<'_, ErrorGuaranteed> { +fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> { let mut err = struct_span_err!(tcx.sess, span, E0392, "parameter `{param_name}` is never used"); err.span_label(span, "unused parameter"); err diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d48535c82f59d..d43b4adfe39f2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -181,7 +181,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( suggest: bool, hir_ty: Option<&hir::Ty<'_>>, kind: &'static str, -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +) -> DiagnosticBuilder<'tcx> { if placeholder_types.is_empty() { return bad_placeholder(tcx, additional_spans, kind); } @@ -333,7 +333,7 @@ fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, mut spans: Vec, kind: &'static str, -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +) -> DiagnosticBuilder<'tcx> { let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") }; spans.sort(); diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs index 0b46fce173549..04d04304e70f9 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors.rs @@ -6,7 +6,7 @@ pub use self::{ missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, }; -use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_session::Session; pub trait StructuredDiagnostic<'tcx> { @@ -14,7 +14,7 @@ pub trait StructuredDiagnostic<'tcx> { fn code(&self) -> DiagnosticId; - fn diagnostic(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic(&self) -> DiagnosticBuilder<'tcx> { let err = self.diagnostic_common(); if self.session().teach(&self.code()) { @@ -24,19 +24,13 @@ pub trait StructuredDiagnostic<'tcx> { } } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx>; - fn diagnostic_regular( - &self, - err: DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { err } - fn diagnostic_extended( - &self, - err: DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { err } } diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs index c37dff61b727a..7cc4982820be1 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -20,7 +20,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> { rustc_errors::error_code!(E0617) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { let (sugg_span, replace, help) = if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) { (Some(self.span), format!("{} as {}", snippet, self.cast_ty), None) @@ -44,10 +44,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> { err } - fn diagnostic_extended( - &self, - mut err: DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { err.note(format!( "certain types, like `{}`, must be casted before passing them to a \ variadic function, because of arcane ABI rules dictated by the C \ diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs index 910417abe6e7c..6ba27f4974404 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -20,7 +20,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> { rustc_errors::error_code!(E0607) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { let mut err = self.sess.create_err(errors::CastThinPointerToFatPointer { span: self.span, expr_ty: self.expr_ty, @@ -34,10 +34,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> { err } - fn diagnostic_extended( - &self, - mut err: DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { err.help( "Thin pointers are \"simple\" pointers: they are purely a reference to a memory address. diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index fab841e36792d..c7818d80dbf9e 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,7 +1,6 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, - MultiSpan, + pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, MultiSpan, }; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; @@ -521,7 +520,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx> { let span = self.path_segment.ident.span; let msg = self.create_error_message(); @@ -1113,7 +1112,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> { rustc_errors::error_code!(E0107) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { let mut err = self.start_diagnostics(); self.notify(&mut err); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 5e6b54950b302..2146effd84f06 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -305,8 +305,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) = (parent_node, callee_node) { let fn_decl_span = if hir.body(body).coroutine_kind - == Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure)) - { + == Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )) { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... let async_closure = hir.parent_id(parent_hir_id); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 0de0365364c6a..9783fe79a90fc 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -187,7 +187,7 @@ fn make_invalid_casting_error<'a, 'tcx>( expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'a> { type_error_struct!( sess, span, diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2855cea80b212..8e2af40291879 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -59,7 +59,8 @@ pub(super) fn check_fn<'a, 'tcx>( && can_be_coroutine.is_some() { let yield_ty = match kind { - hir::CoroutineKind::Gen(..) | hir::CoroutineKind::Coroutine => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + | hir::CoroutineKind::Coroutine => { let yield_ty = fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, @@ -71,7 +72,7 @@ pub(super) fn check_fn<'a, 'tcx>( // guide inference on the yield type so that we can handle `AsyncIterator` // in this block in projection correctly. In the new trait solver, it is // not a problem. - hir::CoroutineKind::AsyncGen(..) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { let yield_ty = fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, @@ -89,7 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>( .into()]), ) } - hir::CoroutineKind::Async(..) => Ty::new_unit(tcx), + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => Ty::new_unit(tcx), }; // Resume type defaults to `()` if the coroutine has no argument. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d19d304128a1a..cd42be28e6f04 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -634,7 +634,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing // function. - Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + )) => { debug!("closure is async fn body"); let def_id = self.tcx.hir().body_owner_def_id(body.id()); self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else( @@ -651,9 +654,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } // All `gen {}` and `async gen {}` must return unit. - Some(hir::CoroutineKind::Gen(_) | hir::CoroutineKind::AsyncGen(_)) => { - self.tcx.types.unit - } + Some( + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), + ) => self.tcx.types.unit, _ => astconv.ty_infer(None, decl.output.span()), }, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 61236c07135cd..aed2dbb4505f0 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,9 +36,7 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -1772,7 +1770,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { id: hir::HirId, expression: Option<&'tcx hir::Expr<'tcx>>, blk_id: Option, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); let parent_id = fcx.tcx.hir().parent_id(id); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 8b666c634257f..6e5bd740b2ee4 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,6 +1,6 @@ use crate::FnCtxt; use rustc_errors::MultiSpan; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Option> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Option> { match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -199,7 +199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Option> { self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } @@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Option> { match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -246,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, - ) -> (Ty<'tcx>, Option>) { + ) -> (Ty<'tcx>, Option>) { let expected = self.resolve_vars_with_obligations(expected); let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5d5b5f39ccfc8..c4755b852bd0b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_for_missing_semi( &self, expr: &'tcx hir::Expr<'tcx>, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'_>, ) -> bool { if let hir::ExprKind::Binary(binop, lhs, rhs) = expr.kind && let hir::BinOpKind::Mul = binop.node @@ -2738,7 +2738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Ident, expr_t: Ty<'tcx>, id: HirId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { let span = field.span; debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); @@ -2821,11 +2821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err } - fn private_field_err( - &self, - field: Ident, - base_did: DefId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + fn private_field_err(&self, field: Ident, base_did: DefId) -> DiagnosticBuilder<'_> { let struct_path = self.tcx().def_path_str(base_did); let kind_name = self.tcx().def_descr(base_did); let mut err = struct_span_err!( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 4caa0df58b6d0..752401845cd92 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1258,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, arg: &hir::Expr<'tcx>, - err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut rustc_errors::DiagnosticBuilder<'tcx>, ) { if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind() && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 668e547571f69..d2917b25c54bd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -17,8 +17,8 @@ use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt, - StmtKind, TyKind, WherePredicate, + CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, + Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::traits::{self, StatementAsExpression}; @@ -549,7 +549,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Coroutine(def_id, ..) if matches!( self.tcx.coroutine_kind(def_id), - Some(CoroutineKind::Async(CoroutineSource::Closure)) + Some(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Closure + )) ) => { errors::SuggestBoxing::AsyncBody diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7595f21d9f12d..9327161eccb0f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -13,8 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::StashKey; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -120,7 +119,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args: Option<&'tcx [hir::Expr<'tcx>]>, expected: Expectation<'tcx>, trait_missing_method: bool, - ) -> Option> { + ) -> Option> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; @@ -261,7 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { let mut file = None; let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file); let mut err = struct_span_err!( @@ -299,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, - ) -> Option> { + ) -> Option> { let mode = no_match_data.mode; let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 56a420fab4fef..0c0af51cb0dfd 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -99,7 +99,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: TopInfo<'tcx>, - ) -> Option> { + ) -> Option> { let mut diag = self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?; if let Some(expr) = ti.origin_expr { @@ -967,7 +967,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn emit_bad_pat_path( &self, - mut e: DiagnosticBuilder<'_, ErrorGuaranteed>, + mut e: DiagnosticBuilder<'_>, pat: &hir::Pat<'tcx>, res: Res, pat_res: Res, @@ -1508,7 +1508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &VariantDef, pat: &'_ Pat<'_>, fields: &[hir::PatField<'_>], - ) -> Option> { + ) -> Option> { // if this is a tuple struct, then all field names will be numbers // so if any fields in a struct pattern use shorthand syntax, they will // be invalid identifiers (for example, Foo { 0, 1 }). @@ -1584,7 +1584,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, variant: &ty::VariantDef, args: &'tcx ty::List>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; let (field_names, t, plural) = if let [field] = inexistent_fields { (format!("a field named `{}`", field.ident), "this", "") @@ -1689,7 +1689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, - ) -> Option> { + ) -> Option> { if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = (variant.ctor_kind(), &pat.kind) { @@ -1775,7 +1775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = self .tcx .sess @@ -1867,7 +1867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &[(&ty::FieldDef, Ident)], have_inaccessible_fields: bool, fields: &'tcx [hir::PatField<'tcx>], - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; let field_names = if let [(_, field)] = unmentioned_fields { format!("field `{field}`{inaccessible}") diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 3ea1a52ae2829..d730ef58deba6 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -502,6 +502,7 @@ impl ChunkedBitSet { }; #[cfg(not(feature = "nightly"))] let mut words = { + // FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291). let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); // SAFETY: `words` can safely be all zeroes. let words = unsafe { words.assume_init() }; @@ -567,6 +568,7 @@ impl ChunkedBitSet { }; #[cfg(not(feature = "nightly"))] let mut words = { + // FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#63291). let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); // SAFETY: `words` can safely be all zeroes. let words = unsafe { words.assume_init() }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d396c41007b17..d77c224f3c86a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -306,7 +306,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, opaque_ty_key: ty::OpaqueTypeKey<'tcx>, -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +) -> DiagnosticBuilder<'tcx> { let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime { span, opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args), @@ -2171,7 +2171,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trace: TypeTrace<'tcx>, terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span(); @@ -2319,7 +2319,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { origin: Option>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { if let Some(SubregionOrigin::CompareImplItemObligation { span, impl_item_def_id, @@ -2732,7 +2732,7 @@ impl<'tcx> InferCtxt<'tcx> { fn report_inference_failure( &self, var_origin: RegionVariableOrigin, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BrNamed(_, name) => name.to_string(), 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 700fb5d35109e..fd38e52cfde1f 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,7 @@ use crate::errors::{ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{DiagnosticBuilder, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -358,7 +358,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let source_kind = "other"; let source_name = ""; let failure_span = None; @@ -406,7 +406,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, should_label_span: bool, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 2a70c4673b03a..e13d1d38a89ff 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -50,7 +50,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { self.cx.tcx } - pub fn try_report_from_nll(&self) -> Option> { + pub fn try_report_from_nll(&self) -> Option> { // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of // the nice region errors are required when running under the MIR borrow checker. self.try_report_named_anon_conflict() diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 1b43022f8f7d0..a5a69b77a050a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -5,16 +5,14 @@ use crate::{ errors::ExplicitLifetimeRequired, infer::error_reporting::nice_region_error::find_anon_type::find_anon_type, }; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::DiagnosticBuilder; use rustc_middle::ty; use rustc_span::symbol::kw; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. - pub(super) fn try_report_named_anon_conflict( - &self, - ) -> Option> { + pub(super) fn try_report_named_anon_conflict(&self) -> Option> { let (span, sub, sup) = self.regions()?; debug!( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index d98ca995d71d4..45affb538a31a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -8,7 +8,7 @@ use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{DiagnosticBuilder, IntoDiagnosticArg}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; @@ -57,9 +57,7 @@ where impl<'tcx> NiceRegionError<'_, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit a descriptive diagnostic error. - pub(super) fn try_report_placeholder_conflict( - &self, - ) -> Option> { + pub(super) fn try_report_placeholder_conflict(&self) -> Option> { match &self.error { /////////////////////////////////////////////////////////////////////////// // NB. The ordering of cases in this match is very @@ -195,7 +193,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_placeholder: Option>, sup_placeholder: Option>, value_pairs: &ValuePairs<'tcx>, - ) -> Option> { + ) -> Option> { let (expected_args, found_args, trait_def_id) = match value_pairs { ValuePairs::PolyTraitRefs(ExpectedFound { expected, found }) if expected.def_id() == found.def_id() => @@ -238,7 +236,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { trait_def_id: DefId, expected_args: GenericArgsRef<'tcx>, actual_args: GenericArgsRef<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let span = cause.span(); let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index f5b8912532b11..51b65a9dd2d0e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -5,14 +5,12 @@ use crate::{ }, }; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::DiagnosticBuilder; use rustc_middle::ty::{self, RePlaceholder, Region}; impl<'tcx> NiceRegionError<'_, 'tcx> { /// Emitted wwhen given a `ConcreteFailure` when relating two placeholders. - pub(super) fn try_report_placeholder_relation( - &self, - ) -> Option> { + pub(super) fn try_report_placeholder_relation(&self) -> Option> { match &self.error { Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::RelateRegionParamBound(span), diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 1f1c2bc20e2e0..73139d8e72084 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -5,7 +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}; +use rustc_errors::{AddToDiagnostic, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; @@ -78,7 +78,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); @@ -350,7 +350,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e092bbbfdd674..a36735b7600f2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1740,9 +1740,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { sp: Span, mk_diag: M, actual_ty: Ty<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + ) -> DiagnosticBuilder<'tcx> where - M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>, + M: FnOnce(String) -> DiagnosticBuilder<'tcx>, { let actual_ty = self.resolve_vars_if_possible(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); @@ -1763,7 +1763,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } @@ -1773,7 +1773,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected: ty::Const<'tcx>, actual: ty::Const<'tcx>, err: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index b3cfd843ace3c..99fb4b33f249e 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,7 +2,7 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{struct_span_err, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -18,7 +18,7 @@ impl<'tcx> InferCtxt<'tcx> { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, requirement: &dyn fmt::Display, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( self.tcx.sess, error_span, @@ -44,7 +44,7 @@ pub fn report_object_safety_error<'tcx>( span: Span, trait_def_id: DefId, violations: &[ObjectSafetyViolation], -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +) -> DiagnosticBuilder<'tcx> { let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => Some(item.ident.span), diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d58d60fc8bee3..6c000380e713a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -347,7 +347,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se ) { Ok(bundle) => bundle, Err(e) => { - early_dcx.early_error(format!("failed to load fluent bundle: {e}")); + early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")); } }; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index bffa743218f11..f230c5b172c29 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -164,13 +164,13 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn { let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {path:?}: {err}"); - early_dcx.early_error(err); + early_dcx.early_fatal(err); }); let backend_sym = unsafe { lib.get::(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { let err = format!("couldn't load codegen backend: {e}"); - early_dcx.early_error(err); + early_dcx.early_fatal(err); }); // Intentionally leak the dynamic library. We can't ever unload it @@ -271,7 +271,7 @@ fn get_codegen_sysroot( "failed to find a `codegen-backends` folder \ in the sysroot candidates:\n* {candidates}" ); - early_dcx.early_error(err); + early_dcx.early_fatal(err); }); info!("probing {} for a codegen backend", sysroot.display()); @@ -282,7 +282,7 @@ fn get_codegen_sysroot( sysroot.display(), e ); - early_dcx.early_error(err); + early_dcx.early_fatal(err); }); let mut file: Option = None; @@ -310,7 +310,7 @@ fn get_codegen_sysroot( prev.display(), path.display() ); - early_dcx.early_error(err); + early_dcx.early_fatal(err); } file = Some(path.clone()); } @@ -319,7 +319,7 @@ fn get_codegen_sysroot( Some(ref s) => load_backend_from_dylib(early_dcx, s), None => { let err = format!("unsupported builtin codegen backend `{backend_name}`"); - early_dcx.early_error(err); + early_dcx.early_fatal(err); } } } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 0f5d4d9476d63..667fc30199187 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -206,16 +206,16 @@ fixed_size_enum! { fixed_size_enum! { hir::CoroutineKind { - ( Coroutine ) - ( Gen(hir::CoroutineSource::Block) ) - ( Gen(hir::CoroutineSource::Fn) ) - ( Gen(hir::CoroutineSource::Closure) ) - ( Async(hir::CoroutineSource::Block) ) - ( Async(hir::CoroutineSource::Fn) ) - ( Async(hir::CoroutineSource::Closure) ) - ( AsyncGen(hir::CoroutineSource::Block) ) - ( AsyncGen(hir::CoroutineSource::Fn) ) - ( AsyncGen(hir::CoroutineSource::Closure) ) + ( Coroutine ) + ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) ) + ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) ) + ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) ) + ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Block) ) + ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Fn) ) + ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure) ) + ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Block) ) + ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Fn) ) + ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure) ) } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index c49c4ee819cbb..d34d9160d55bf 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -293,19 +293,16 @@ pub fn struct_lint_level( }, ); - let mut err = match (level, span) { - (Level::Allow, span) => { + // Convert lint level to error level. + let err_level = match level { + Level::Allow => { if has_future_breakage { - if let Some(span) = span { - sess.struct_span_allow(span, "") - } else { - sess.struct_allow("") - } + rustc_errors::Level::Allow } else { return; } } - (Level::Expect(expect_id), _) => { + Level::Expect(expect_id) => { // This case is special as we actually allow the lint itself in this context, but // we can't return early like in the case for `Level::Allow` because we still // need the lint diagnostic to be emitted to `rustc_error::DiagCtxtInner`. @@ -313,23 +310,16 @@ pub fn struct_lint_level( // We can also not mark the lint expectation as fulfilled here right away, as it // can still be cancelled in the decorate function. All of this means that we simply // create a `DiagnosticBuilder` and continue as we would for warnings. - sess.struct_expect("", expect_id) + rustc_errors::Level::Expect(expect_id) } - (Level::ForceWarn(Some(expect_id)), Some(span)) => { - sess.struct_span_warn_with_expectation(span, "", expect_id) - } - (Level::ForceWarn(Some(expect_id)), None) => { - sess.struct_warn_with_expectation("", expect_id) - } - (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""), - (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""), - (Level::Deny | Level::Forbid, Some(span)) => { - let mut builder = sess.dcx().struct_err_lint(""); - builder.set_span(span); - builder - } - (Level::Deny | Level::Forbid, None) => sess.dcx().struct_err_lint(""), + Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)), + Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None), + Level::Deny | Level::Forbid => rustc_errors::Level::Error { lint: true }, }; + let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, ""); + if let Some(span) = span { + err.set_span(span); + } err.set_is_lint(); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 41386793987f5..2cd2fcca9d5aa 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -90,10 +90,7 @@ pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// This is needed in `thir::pattern::lower_inline_const`. pub type EvalToValTreeResult<'tcx> = Result>, ErrorHandled>; -pub fn struct_error<'tcx>( - tcx: TyCtxtAt<'tcx>, - msg: &str, -) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { +pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1e5a7401c6f94..5c425fef27ebc 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -17,7 +17,7 @@ use rustc_data_structures::captures::Captures; use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; -use rustc_hir::{self, CoroutineKind, ImplicitSelfKind}; +use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind}; use rustc_hir::{self as hir, HirId}; use rustc_session::Session; use rustc_target::abi::{FieldIdx, VariantIdx}; diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 98e3a1f604e6e..e0c9def037948 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -148,19 +148,23 @@ impl AssertKind { DivisionByZero(_) => "attempt to divide by zero", RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero", ResumedAfterReturn(CoroutineKind::Coroutine) => "coroutine resumed after completion", - ResumedAfterReturn(CoroutineKind::Async(_)) => "`async fn` resumed after completion", - ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => { + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + "`async fn` resumed after completion" + } + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { "`async gen fn` resumed after completion" } - ResumedAfterReturn(CoroutineKind::Gen(_)) => { + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { "`gen fn` should just keep returning `None` after completion" } ResumedAfterPanic(CoroutineKind::Coroutine) => "coroutine resumed after panicking", - ResumedAfterPanic(CoroutineKind::Async(_)) => "`async fn` resumed after panicking", - ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => { + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + "`async fn` resumed after panicking" + } + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { "`async gen fn` resumed after panicking" } - ResumedAfterPanic(CoroutineKind::Gen(_)) => { + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { "`gen fn` should just keep returning `None` after panicking" } @@ -249,17 +253,27 @@ impl AssertKind { OverflowNeg(_) => middle_assert_overflow_neg, DivisionByZero(_) => middle_assert_divide_by_zero, RemainderByZero(_) => middle_assert_remainder_by_zero, - ResumedAfterReturn(CoroutineKind::Async(_)) => middle_assert_async_resume_after_return, - ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => todo!(), - ResumedAfterReturn(CoroutineKind::Gen(_)) => { + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + middle_assert_async_resume_after_return + } + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { + todo!() + } + ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { bug!("gen blocks can be resumed after they return and will keep returning `None`") } ResumedAfterReturn(CoroutineKind::Coroutine) => { middle_assert_coroutine_resume_after_return } - ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic, - ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => todo!(), - ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_gen_resume_after_panic, + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + middle_assert_async_resume_after_panic + } + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { + todo!() + } + ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { + middle_assert_gen_resume_after_panic + } ResumedAfterPanic(CoroutineKind::Coroutine) => { middle_assert_coroutine_resume_after_panic } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b5ca700c2cd5a..655dde1d9c987 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -849,7 +849,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if the node pointed to by `def_id` is a coroutine for an async construct. pub fn coroutine_is_async(self, def_id: DefId) -> bool { - matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Async(_))) + matches!( + self.coroutine_kind(def_id), + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) + ) } /// Returns `true` if the node pointed to by `def_id` is a general coroutine that implements `Coroutine`. @@ -860,12 +863,18 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if the node pointed to by `def_id` is a coroutine for a `gen` construct. pub fn coroutine_is_gen(self, def_id: DefId) -> bool { - matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Gen(_))) + matches!( + self.coroutine_kind(def_id), + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) + ) } /// Returns `true` if the node pointed to by `def_id` is a coroutine for a `async gen` construct. pub fn coroutine_is_async_gen(self, def_id: DefId) -> bool { - matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::AsyncGen(_))) + matches!( + self.coroutine_kind(def_id), + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) + ) } pub fn stability(self) -> &'tcx stability::Index { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 35c135830c3f3..36b8d387d6966 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1481,7 +1481,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { other: &Self, opaque_def_id: LocalDefId, tcx: TyCtxt<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { if let Some(diag) = tcx .sess .dcx() diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 8b2b76764e646..ab2488f2e9103 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -728,10 +728,16 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { - rustc_hir::CoroutineKind::Async(..) => "async closure", - rustc_hir::CoroutineKind::AsyncGen(..) => "async gen closure", - rustc_hir::CoroutineKind::Coroutine => "coroutine", - rustc_hir::CoroutineKind::Gen(..) => "gen closure", + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { + "async closure" + } + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { + "async gen closure" + } + hir::CoroutineKind::Coroutine => "coroutine", + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { + "gen closure" + } } } _ => def_kind.descr(def_id), @@ -749,10 +755,10 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { - rustc_hir::CoroutineKind::Async(..) => "an", - rustc_hir::CoroutineKind::AsyncGen(..) => "an", - rustc_hir::CoroutineKind::Coroutine => "a", - rustc_hir::CoroutineKind::Gen(..) => "a", + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, ..) => "an", + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, ..) => "a", + hir::CoroutineKind::Coroutine => "a", } } _ => def_kind.article(), diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 22d0a66548910..8677cba6a7c3d 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, Level, MultiSpan, SubdiagnosticMessage, + IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -461,11 +461,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { } impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diagnostic( - self, - dcx: &'a DiagCtxt, - level: Level, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'_> { let mut diag = DiagnosticBuilder::new( dcx, level, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d67dc59c6185f..fcccdf105f649 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -54,11 +54,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err visitor.error } -fn create_e0004( - sess: &Session, - sp: Span, - error_message: String, -) -> DiagnosticBuilder<'_, ErrorGuaranteed> { +fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> { struct_span_err!(sess, sp, E0004, "{}", &error_message) } @@ -860,7 +856,7 @@ fn report_arm_reachability<'p, 'tcx>( for (arm, is_useful) in report.arm_usefulness.iter() { match is_useful { Usefulness::Redundant => { - report_unreachable_pattern(*arm.pat.data(), arm.arm_data, catchall) + report_unreachable_pattern(*arm.pat.data().unwrap(), arm.arm_data, catchall) } Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {} // The arm is reachable, but contains redundant subpatterns (from or-patterns). @@ -869,12 +865,12 @@ fn report_arm_reachability<'p, 'tcx>( // Emit lints in the order in which they occur in the file. redundant_subpats.sort_unstable_by_key(|pat| pat.data()); for pat in redundant_subpats { - report_unreachable_pattern(*pat.data(), arm.arm_data, None); + report_unreachable_pattern(*pat.data().unwrap(), arm.arm_data, None); } } } if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { - catchall = Some(*arm.pat.data()); + catchall = Some(*arm.pat.data().unwrap()); } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 646c70eb88fca..595c2ff5bf7fa 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -81,17 +81,17 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } #[derive(Clone)] -pub struct MaybeStorageDead { - always_live_locals: BitSet, +pub struct MaybeStorageDead<'a> { + always_live_locals: Cow<'a, BitSet>, } -impl MaybeStorageDead { - pub fn new(always_live_locals: BitSet) -> Self { +impl<'a> MaybeStorageDead<'a> { + pub fn new(always_live_locals: Cow<'a, BitSet>) -> Self { MaybeStorageDead { always_live_locals } } } -impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead { +impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_dead"; @@ -112,7 +112,7 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead { } } -impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { +impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d7dd44af7d251..6da102dcb1c61 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -59,7 +59,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_hir::CoroutineKind; +use rustc_hir::{CoroutineDesugaring, CoroutineKind}; use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; @@ -254,10 +254,12 @@ impl<'tcx> TransformVisitor<'tcx> { let source_info = SourceInfo::outermost(body.span); let none_value = match self.coroutine_kind { - CoroutineKind::Async(_) => span_bug!(body.span, "`Future`s are not fused inherently"), + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + span_bug!(body.span, "`Future`s are not fused inherently") + } CoroutineKind::Coroutine => span_bug!(body.span, "`Coroutine`s cannot be fused"), // `gen` continues return `None` - CoroutineKind::Gen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); Rvalue::Aggregate( Box::new(AggregateKind::Adt( @@ -271,7 +273,7 @@ impl<'tcx> TransformVisitor<'tcx> { ) } // `async gen` continues to return `Poll::Ready(None)` - CoroutineKind::AsyncGen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => { let ty::Adt(_poll_adt, args) = *self.old_yield_ty.kind() else { bug!() }; let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() }; let yield_ty = args.type_at(0); @@ -316,7 +318,7 @@ impl<'tcx> TransformVisitor<'tcx> { statements: &mut Vec>, ) { let rvalue = match self.coroutine_kind { - CoroutineKind::Async(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); if is_return { @@ -345,7 +347,7 @@ impl<'tcx> TransformVisitor<'tcx> { ) } } - CoroutineKind::Gen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); let args = self.tcx.mk_args(&[self.old_yield_ty.into()]); if is_return { @@ -374,7 +376,7 @@ impl<'tcx> TransformVisitor<'tcx> { ) } } - CoroutineKind::AsyncGen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => { if is_return { let ty::Adt(_poll_adt, args) = *self.old_yield_ty.kind() else { bug!() }; let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() }; @@ -1426,10 +1428,11 @@ fn create_coroutine_resume_function<'tcx>( if can_return { let block = match coroutine_kind { - CoroutineKind::Async(_) | CoroutineKind::Coroutine => { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) | CoroutineKind::Coroutine => { insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind)) } - CoroutineKind::AsyncGen(_) | CoroutineKind::Gen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) + | CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { transform.insert_none_ret_block(body) } }; @@ -1443,7 +1446,7 @@ fn create_coroutine_resume_function<'tcx>( match coroutine_kind { // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. - CoroutineKind::Gen(_) => {} + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {} _ => { make_coroutine_state_argument_pinned(tcx, body); } @@ -1609,25 +1612,34 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } }; - let is_async_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Async(_))); - let is_async_gen_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::AsyncGen(_))); - let is_gen_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Gen(_))); + let is_async_kind = matches!( + body.coroutine_kind(), + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) + ); + let is_async_gen_kind = matches!( + body.coroutine_kind(), + Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) + ); + let is_gen_kind = matches!( + body.coroutine_kind(), + Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) + ); let new_ret_ty = match body.coroutine_kind().unwrap() { - CoroutineKind::Async(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { // Compute Poll let poll_did = tcx.require_lang_item(LangItem::Poll, None); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[old_ret_ty.into()]); Ty::new_adt(tcx, poll_adt_ref, poll_args) } - CoroutineKind::Gen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { // Compute Option let option_did = tcx.require_lang_item(LangItem::Option, None); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[old_yield_ty.into()]); Ty::new_adt(tcx, option_adt_ref, option_args) } - CoroutineKind::AsyncGen(_) => { + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => { // The yield ty is already `Poll>` old_yield_ty } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 89e897191e852..98d4d96d0c76c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -86,6 +86,7 @@ pub mod inline; mod instsimplify; mod jump_threading; mod large_enums; +mod lint; mod lower_intrinsics; mod lower_slice_len; mod match_branches; diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs new file mode 100644 index 0000000000000..3940d0ddbf344 --- /dev/null +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -0,0 +1,119 @@ +//! This pass statically detects code which has undefined behaviour or is likely to be erroneous. +//! It can be used to locate problems in MIR building or optimizations. It assumes that all code +//! can be executed, so it has false positives. +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive}; +use rustc_mir_dataflow::storage::always_storage_live_locals; +use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use std::borrow::Cow; + +pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { + let reachable_blocks = traversal::reachable_as_bitset(body); + let always_live_locals = &always_storage_live_locals(body); + + let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals)) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + Lint { + tcx, + when, + body, + is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(), + always_live_locals, + reachable_blocks, + maybe_storage_live, + maybe_storage_dead, + } + .visit_body(body); +} + +struct Lint<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + when: String, + body: &'a Body<'tcx>, + is_fn_like: bool, + always_live_locals: &'a BitSet, + reachable_blocks: BitSet, + maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, + maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>, +} + +impl<'a, 'tcx> Lint<'a, 'tcx> { + #[track_caller] + fn fail(&self, location: Location, msg: impl AsRef) { + let span = self.body.source_info(location).span; + self.tcx.sess.dcx().span_delayed_bug( + span, + format!( + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.body.source.instance, + self.when, + location, + msg.as_ref() + ), + ); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { + if self.reachable_blocks.contains(location.block) && context.is_use() { + self.maybe_storage_dead.seek_after_primary_effect(location); + if self.maybe_storage_dead.get().contains(local) { + self.fail(location, format!("use of local {local:?}, which has no storage here")); + } + } + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match statement.kind { + StatementKind::StorageLive(local) => { + if self.reachable_blocks.contains(location.block) { + self.maybe_storage_live.seek_before_primary_effect(location); + if self.maybe_storage_live.get().contains(local) { + self.fail( + location, + format!("StorageLive({local:?}) which already has storage here"), + ); + } + } + } + _ => {} + } + + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Return => { + if self.is_fn_like && self.reachable_blocks.contains(location.block) { + self.maybe_storage_live.seek_after_primary_effect(location); + for local in self.maybe_storage_live.get().iter() { + if !self.always_live_locals.contains(local) { + self.fail( + location, + format!( + "local {local:?} still has storage when returning from function" + ), + ); + } + } + } + } + _ => {} + } + + self.super_terminator(terminator, location); + } +} diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index c4eca18ff277a..1da1c1920b249 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -2,7 +2,7 @@ use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use crate::{validate, MirPass}; +use crate::{lint::lint_body, validate, MirPass}; /// Just like `MirPass`, except it cannot mutate `Body`. pub trait MirLint<'tcx> { @@ -109,6 +109,7 @@ fn run_passes_inner<'tcx>( phase_change: Option, validate_each: bool, ) { + let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip(); let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip(); let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); @@ -131,6 +132,9 @@ fn run_passes_inner<'tcx>( if validate { validate_body(tcx, body, format!("before pass {name}")); } + if lint { + lint_body(tcx, body, format!("before pass {name}")); + } if let Some(prof_arg) = &prof_arg { tcx.sess @@ -147,6 +151,9 @@ fn run_passes_inner<'tcx>( if validate { validate_body(tcx, body, format!("after pass {name}")); } + if lint { + lint_body(tcx, body, format!("after pass {name}")); + } body.pass_count += 1; } @@ -164,6 +171,9 @@ fn run_passes_inner<'tcx>( if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { validate_body(tcx, body, format!("after phase change to {}", new_phase.name())); } + if lint { + lint_body(tcx, body, format!("after phase change to {}", new_phase.name())); + } body.pass_count = 1; } diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index f13ab5b0f1fe5..05a3ac3cc7558 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -7,6 +7,7 @@ use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::MaybeStorageDead; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::Analysis; +use std::borrow::Cow; use crate::ssa::{SsaLocals, StorageLiveLocals}; @@ -120,7 +121,7 @@ fn compute_replacement<'tcx>( // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is // definitely live. - let mut maybe_dead = MaybeStorageDead::new(always_live_locals) + let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals)) .into_engine(tcx, body) .iterate_to_fixpoint() .into_results_cursor(body); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8ccfcb625a626..53cce9e2883a9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,8 +3,8 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, - Level, SubdiagnosticMessage, + AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, + SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -1043,11 +1043,7 @@ pub(crate) struct ExpectedIdentifier { impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier { #[track_caller] - fn into_diagnostic( - self, - dcx: &'a DiagCtxt, - level: Level, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = DiagnosticBuilder::new( @@ -1107,11 +1103,7 @@ pub(crate) struct ExpectedSemi { impl<'a> IntoDiagnostic<'a> for ExpectedSemi { #[track_caller] - fn into_diagnostic( - self, - dcx: &'a DiagCtxt, - level: Level, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = DiagnosticBuilder::new( diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f19d420bb49b9..4d557e495d8d4 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, MultiSpan, PResult, + DiagnosticMessage, FatalError, MultiSpan, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -245,7 +245,7 @@ impl<'a> Parser<'a> { &self, sp: S, m: impl Into, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { self.dcx().struct_span_err(sp, m) } @@ -413,7 +413,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a> { self.expected_ident_found(false).unwrap_err() } @@ -958,7 +958,7 @@ impl<'a> Parser<'a> { pub(super) fn recover_closure_body( &mut self, - mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, + mut err: DiagnosticBuilder<'a>, before: token::Token, prev: token::Token, token: token::Token, @@ -1189,7 +1189,7 @@ impl<'a> Parser<'a> { /// encounter a parse error when encountering the first `,`. pub(super) fn check_mistyped_turbofish_with_multiple_type_params( &mut self, - mut e: DiagnosticBuilder<'a, ErrorGuaranteed>, + mut e: DiagnosticBuilder<'a>, expr: &mut P, ) -> PResult<'a, ()> { if let ExprKind::Binary(binop, _, _) = &expr.kind @@ -1234,10 +1234,7 @@ impl<'a> Parser<'a> { /// Suggest add the missing `let` before the identifier in stmt /// `a: Ty = 1` -> `let a: Ty = 1` - pub(super) fn suggest_add_missing_let_for_stmt( - &mut self, - err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, - ) { + pub(super) fn suggest_add_missing_let_for_stmt(&mut self, err: &mut DiagnosticBuilder<'a>) { if self.token == token::Colon { let prev_span = self.prev_token.span.shrink_to_lo(); let snapshot = self.create_snapshot_for_diagnostic(); @@ -2320,7 +2317,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { let sp = self.prev_token.span.shrink_to_hi(); @@ -2572,7 +2569,7 @@ impl<'a> Parser<'a> { pub fn recover_const_arg( &mut self, start: Span, - mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, + mut err: DiagnosticBuilder<'a>, ) -> PResult<'a, GenericArg> { let is_op_or_dot = AssocOp::from_token(&self.token) .and_then(|op| { @@ -2674,7 +2671,7 @@ impl<'a> Parser<'a> { /// Creates a dummy const argument, and reports that the expression must be enclosed in braces pub fn dummy_const_arg_needs_braces( &self, - mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, + mut err: DiagnosticBuilder<'a>, span: Span, ) -> GenericArg { err.multipart_suggestion( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e653d4064c868..a6783eaf8d41d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -26,8 +26,7 @@ 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, PResult, - StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, PResult, StashKey, }; use rustc_macros::Subdiagnostic; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; @@ -1691,7 +1690,7 @@ impl<'a> Parser<'a> { &self, lifetime: Ident, mk_lit_char: impl FnOnce(Symbol, Span) -> L, - err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, + err: impl FnOnce(&Self) -> DiagnosticBuilder<'a>, ) -> L { if let Some(mut diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0ab2adb404afe..47c337ad91367 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -32,7 +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, MultiSpan}; +use rustc_errors::{Applicability, DiagnosticBuilder, FatalError, MultiSpan}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -908,7 +908,7 @@ impl<'a> Parser<'a> { fn recover_missing_braces_around_closure_body( &mut self, closure_spans: ClosureSpans, - mut expect_err: DiagnosticBuilder<'_, ErrorGuaranteed>, + mut expect_err: DiagnosticBuilder<'_>, ) -> PResult<'a, ()> { let initial_semicolon = self.token.span; @@ -1490,7 +1490,7 @@ impl<'a> Parser<'a> { pub(crate) fn make_unclosed_delims_error( unmatched: UnmatchedDelim, sess: &ParseSess, -) -> Option> { +) -> Option> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to // `unmatched_delims` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d32582fd43d3d..56a3f5ce3c2a3 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, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -687,7 +687,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, - err: DiagnosticBuilder<'a, ErrorGuaranteed>, + err: DiagnosticBuilder<'a>, expected: Option, ) -> PResult<'a, P> { err.cancel(); @@ -969,7 +969,7 @@ impl<'a> Parser<'a> { let mut fields = ThinVec::new(); let mut etc = false; let mut ate_comma = true; - let mut delayed_err: Option> = None; + let mut delayed_err: Option> = None; let mut first_etc_and_maybe_comma_span = None; let mut last_non_comma_dotdot_span = None; @@ -1135,7 +1135,7 @@ impl<'a> Parser<'a> { fn recover_misplaced_pattern_modifiers( &self, fields: &ThinVec, - err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'a>, ) { if let Some(last) = fields.iter().last() && last.is_shorthand diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1ee5a96d5dc54..1ac5aba212c23 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -19,7 +19,7 @@ use rustc_ast::util::classify; use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; -use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span}; @@ -442,7 +442,7 @@ impl<'a> Parser<'a> { fn error_block_no_opening_brace_msg( &mut self, msg: Cow<'static, str>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { let sp = self.token.span; let mut e = self.struct_span_err(sp, msg); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 908d00cf10567..2152f9fda007d 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +derivative = "2.2.0" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index af0a7497a34f9..b688051ca9ccb 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -642,7 +642,8 @@ impl OpaqueId { /// `specialize_constructor` returns the list of fields corresponding to a pattern, given a /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and /// `Fields`. -#[derive(Clone, Debug, PartialEq)] +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))] pub enum Constructor { /// Tuples and structs. Struct, diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index f00e6f18617b9..a1c9b15766676 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -49,7 +49,7 @@ impl<'a, T: ?Sized> Captures<'a> for T {} /// Context that provides type information about constructors. /// /// Most of the crate is parameterized on a type that implements this trait. -pub trait TypeCx: Sized + Clone + fmt::Debug { +pub trait TypeCx: Sized + fmt::Debug { /// The type of a pattern. type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy /// The index of an enum variant. @@ -58,9 +58,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug { type StrLit: Clone + PartialEq + fmt::Debug; /// Extra data to store in a match arm. type ArmData: Copy + Clone + fmt::Debug; - /// Extra data to store in a pattern. `Default` needed when we create fictitious wildcard - /// patterns during analysis. - type PatData: Clone + Default; + /// Extra data to store in a pattern. + type PatData: Clone; /// FIXME(Nadrieril): `Cx` should only give us revealed types. fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty; @@ -86,7 +85,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug { } /// Context that provides information global to a match. -#[derive(Clone)] +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""))] pub struct MatchCtxt<'a, 'p, Cx: TypeCx> { /// The context for type information. pub tycx: &'a Cx, @@ -94,18 +94,16 @@ pub struct MatchCtxt<'a, 'p, Cx: TypeCx> { pub wildcard_arena: &'a TypedArena>, } -impl<'a, 'p, Cx: TypeCx> Copy for MatchCtxt<'a, 'p, Cx> {} - /// The arm of a match expression. -#[derive(Clone, Debug)] +#[derive(Debug)] +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""))] pub struct MatchArm<'p, Cx: TypeCx> { pub pat: &'p DeconstructedPat<'p, Cx>, pub has_guard: bool, pub arm_data: Cx::ArmData, } -impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {} - /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are /// useful, and runs some lints. #[cfg(feature = "rustc")] diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 450a5cb0a105a..2be6e8e3db346 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -203,7 +203,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( }; use rustc_errors::DecorateLint; - let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data(), ""); + let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data().unwrap(), ""); err.set_primary_message(decorator.msg()); decorator.decorate_lint(&mut err); err.emit(); @@ -253,8 +253,8 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>( let mut suffixes: SmallVec<[_; 1]> = Default::default(); // Iterate on patterns that contained `overlap`. for pat in column.iter() { - let this_span = *pat.data(); let Constructor::IntRange(this_range) = pat.ctor() else { continue }; + let this_span = *pat.data().unwrap(); if this_range.is_singleton() { // Don't lint when one of the ranges is a singleton. continue; diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 0cc8477b7cdc3..9efd3e864dac0 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -26,14 +26,16 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> { ctor: Constructor, fields: &'p [DeconstructedPat<'p, Cx>], ty: Cx::Ty, - data: Cx::PatData, + /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not + /// correspond to a user-supplied pattern. + data: Option, /// Whether removing this arm would change the behavior of the match expression. useful: Cell, } impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { - pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self { - Self::new(Wildcard, &[], ty, data) + pub fn wildcard(ty: Cx::Ty) -> Self { + DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) } } pub fn new( @@ -42,7 +44,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { ty: Cx::Ty, data: Cx::PatData, ) -> Self { - DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) } + DeconstructedPat { ctor, fields, ty, data: Some(data), useful: Cell::new(false) } } pub(crate) fn is_or_pat(&self) -> bool { @@ -63,8 +65,10 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { pub fn ty(&self) -> Cx::Ty { self.ty } - pub fn data(&self) -> &Cx::PatData { - &self.data + /// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that + /// does not correspond to a user-supplied pattern. + pub fn data(&self) -> Option<&Cx::PatData> { + self.data.as_ref() } pub fn iter_fields<'a>( @@ -83,7 +87,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { let wildcard_sub_tys = || { let tys = pcx.ctor_sub_tys(other_ctor); tys.iter() - .map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default())) + .map(|ty| DeconstructedPat::wildcard(*ty)) .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_) .collect() }; @@ -160,7 +164,8 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics /// purposes. As such they don't use interning and can be cloned. -#[derive(Debug, Clone)] +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] pub struct WitnessPat { ctor: Constructor, pub(crate) fields: Vec>, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d2cfb9a8b068c..adaa2ecbe4fd0 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -416,7 +416,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty::Tuple(fs) => { ctor = Struct; let mut wilds: SmallVec<[_; 2]> = - fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); + fs.iter().map(|ty| DeconstructedPat::wildcard(ty)).collect(); for pat in subpatterns { wilds[pat.field.index()] = self.lower_pat(&pat.pattern); } @@ -439,7 +439,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { let pat = if let Some(pat) = pattern { self.lower_pat(&pat.pattern) } else { - DeconstructedPat::wildcard(args.type_at(0), pat.span) + DeconstructedPat::wildcard(args.type_at(0)) }; ctor = Struct; fields = singleton(pat); @@ -464,7 +464,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty }); let mut wilds: SmallVec<[_; 2]> = - tys.map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); + tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); for pat in subpatterns { if let Some(i) = field_id_to_id[pat.field.index()] { wilds[i] = self.lower_pat(&pat.pattern); diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 6b9fbd7300327..a7cd944c0f1bd 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -569,8 +569,10 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { } /// Context that provides information local to a place under investigation. -#[derive(Clone)] +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] pub(crate) struct PlaceCtxt<'a, 'p, Cx: TypeCx> { + #[derivative(Debug = "ignore")] pub(crate) mcx: MatchCtxt<'a, 'p, Cx>, /// Type of the place under investigation. pub(crate) ty: Cx::Ty, @@ -596,14 +598,6 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> { } } -impl<'a, 'p, Cx: TypeCx> Copy for PlaceCtxt<'a, 'p, Cx> {} - -impl<'a, 'p, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, 'p, Cx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PlaceCtxt").field("ty", &self.ty).finish() - } -} - /// Serves two purposes: /// - in a wildcard, tracks whether the wildcard matches only valid values (i.e. is a binding `_a`) /// or also invalid values (i.e. is a true `_` pattern). @@ -670,7 +664,8 @@ impl fmt::Display for ValidityConstraint { // - 'a allocated by us // - 'p coming from the input // - Cx global compilation context -#[derive(Clone)] +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""))] struct PatStack<'a, 'p, Cx: TypeCx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. pats: SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]>, @@ -845,8 +840,7 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> { scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Self { - let wild_pattern = - wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty, Default::default())); + let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); let wildcard_row = PatStack::from_pattern(wild_pattern); let mut matrix = Matrix { rows: Vec::with_capacity(arms.len()), @@ -1022,7 +1016,8 @@ impl<'a, 'p, Cx: TypeCx> fmt::Debug for Matrix<'a, 'p, Cx> { /// The final `Pair(Some(_), true)` is then the resulting witness. /// /// See the top of the file for more detailed explanations and examples. -#[derive(Debug, Clone)] +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] struct WitnessStack(Vec>); impl WitnessStack { @@ -1069,7 +1064,8 @@ impl WitnessStack { /// /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single /// column, which contains the patterns that are missing for the match to be exhaustive. -#[derive(Debug, Clone)] +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] struct WitnessMatrix(Vec>); impl WitnessMatrix { diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 0561fd147a919..982b9ee94da9f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -4,7 +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, Level}; +use rustc_errors::{DiagCtxt, Diagnostic, DiagnosticBuilder, Level}; use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::Span; @@ -559,7 +559,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { pub(crate) fn report_cycle<'a>( sess: &'a Session, CycleError { usage, cycle: stack }: &CycleError, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'a> { assert!(!stack.is_empty()); let span = stack[0].query.default_span(stack[1 % stack.len()].span); diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 41638b38c742d..3e29574c87107 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -19,7 +19,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lock; #[cfg(parallel_compiler)] use rustc_data_structures::{outline, sync}; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError, StashKey}; +use rustc_errors::{DiagnosticBuilder, FatalError, StashKey}; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; use std::collections::hash_map::Entry; @@ -112,7 +112,7 @@ fn handle_cycle_error( query: Q, qcx: Qcx, cycle_error: &CycleError, - mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, + mut error: DiagnosticBuilder<'_>, ) -> Q::Value where Q: QueryConfig, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 542aff69e3459..af0c5b56d7343 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -551,7 +551,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, span: Span, resolution_error: ResolutionError<'a>, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { match resolution_error { ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => { use errs::GenericParamsFromOuterItemLabel as Label; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bd4a2998e2d44..4bef67be3ef24 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3693,7 +3693,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); // overwrite all properties with the parent's error message - err.message = take(&mut parent_err.message); + err.messages = take(&mut parent_err.messages); err.code = take(&mut parent_err.code); swap(&mut err.span, &mut parent_err.span); err.children = take(&mut parent_err.children); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 5a02e7f326995..e410e76abf473 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -424,7 +424,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { span: Span, source: PathSource<'_>, res: Option, - ) -> (DiagnosticBuilder<'tcx, ErrorGuaranteed>, Vec) { + ) -> (DiagnosticBuilder<'tcx>, Vec) { debug!(?res, ?source); let base_error = self.make_base_error(path, span, source, res); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 75ec594eb9b98..a14f3d494fb4d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -37,7 +37,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; -use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -704,7 +704,7 @@ struct PrivacyError<'a> { #[derive(Debug)] struct UseError<'a> { - err: DiagnosticBuilder<'a, ErrorGuaranteed>, + err: DiagnosticBuilder<'a>, /// Candidates which user could `use` to access the missing type. candidates: Vec, /// The `DefId` of the module to place the use-statements in. diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0c21e4eb43e78..0d731e330f3d9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1594,7 +1594,7 @@ pub(super) fn build_target_config( |t| Ok((t, TargetWarnings::empty())), ); let (target, target_warnings) = target_result.unwrap_or_else(|e| { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "Error loading target specification: {e}. \ Run `rustc --print target-list` for a list of built-in targets" )) @@ -1604,7 +1604,7 @@ pub(super) fn build_target_config( } if !matches!(target.pointer_width, 16 | 32 | 64) { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "target specification was invalid: unrecognized target-pointer-width {}", target.pointer_width )) @@ -1869,7 +1869,7 @@ pub fn get_cmd_lint_options( let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) - .unwrap_or_else(|| early_dcx.early_error(format!("unknown lint level: `{cap}`"))) + .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`"))) }); (lint_opts, describe_lints, lint_cap) @@ -1884,7 +1884,7 @@ pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Col None => ColorConfig::Auto, - Some(arg) => early_dcx.early_error(format!( + Some(arg) => early_dcx.early_fatal(format!( "argument for `--color` must be auto, \ always or never (instead was `{arg}`)" )), @@ -1942,7 +1942,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json // won't actually be emitting any colors and anything colorized is // embedded in a diagnostic message anyway. if matches.opt_str("color").is_some() { - early_dcx.early_error("cannot specify the `--color` option with `--json`"); + early_dcx.early_fatal("cannot specify the `--color` option with `--json`"); } for sub_option in option.split(',') { @@ -1953,7 +1953,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, "future-incompat" => json_future_incompat = true, - s => early_dcx.early_error(format!("unknown `--json` option `{s}`")), + s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")), } } } @@ -1993,7 +1993,7 @@ pub fn parse_error_format( early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable( HumanReadableErrorType::Default(color), )); - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{arg}`)" )) @@ -2010,7 +2010,7 @@ pub fn parse_error_format( // `--error-format=json`. This means that `--json` is specified we // should actually be emitting JSON blobs. _ if !matches.opt_strs("json").is_empty() => { - early_dcx.early_error("using `--json` requires also using `--error-format=json`"); + early_dcx.early_fatal("using `--json` requires also using `--error-format=json`"); } _ => {} @@ -2022,7 +2022,7 @@ pub fn parse_error_format( pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition { let edition = match matches.opt_str("edition") { Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "argument for `--edition` must be one of: \ {EDITION_NAME_LIST}. (instead was `{arg}`)" )) @@ -2039,7 +2039,7 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches } else { format!("edition {edition} is unstable and only available with -Z unstable-options") }; - early_dcx.early_error(msg) + early_dcx.early_fatal(msg) } edition @@ -2057,7 +2057,7 @@ fn check_error_format_stability( pretty: false, json_rendered, }); - early_dcx.early_error("`--error-format=pretty-json` is unstable"); + early_dcx.early_fatal("`--error-format=pretty-json` is unstable"); } if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = error_format @@ -2066,7 +2066,7 @@ fn check_error_format_stability( pretty: false, json_rendered, }); - early_dcx.early_error("`--error-format=human-annotate-rs` is unstable"); + early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable"); } } } @@ -2082,7 +2082,7 @@ fn parse_output_types( for output_type in list.split(',') { let (shorthand, path) = split_out_file_name(output_type); let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "unknown emission type: `{shorthand}` - expected one of: {display}", display = OutputType::shorthands_display(), )) @@ -2144,7 +2144,7 @@ fn should_override_cgus_and_disable_thinlto( } if codegen_units == Some(0) { - early_dcx.early_error("value for codegen units must be a positive non-zero integer"); + early_dcx.early_fatal("value for codegen units must be a positive non-zero integer"); } (disable_local_thinlto, codegen_units) @@ -2204,7 +2204,7 @@ fn collect_print_requests( if unstable_opts.unstable_options { PrintKind::TargetSpec } else { - early_dcx.early_error( + early_dcx.early_fatal( "the `-Z unstable-options` flag must also be passed to \ enable the target-spec-json print option", ); @@ -2214,7 +2214,7 @@ fn collect_print_requests( if unstable_opts.unstable_options { PrintKind::AllTargetSpecs } else { - early_dcx.early_error( + early_dcx.early_fatal( "the `-Z unstable-options` flag must also be passed to \ enable the all-target-specs-json print option", ); @@ -2225,7 +2225,7 @@ fn collect_print_requests( let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); let prints = prints.join(", "); - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "unknown print request `{req}`. Valid print requests are: {prints}" )); } @@ -2234,7 +2234,7 @@ fn collect_print_requests( let out = out.unwrap_or(OutFileName::Stdout); if let OutFileName::Real(path) = &out { if !printed_paths.insert(path.clone()) { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "cannot print multiple outputs to the same path: {}", path.display(), )); @@ -2252,7 +2252,7 @@ pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches Some(target) if target.ends_with(".json") => { let path = Path::new(&target); TargetTriple::from_path(path).unwrap_or_else(|_| { - early_dcx.early_error(format!("target file {path:?} does not exist")) + early_dcx.early_fatal(format!("target file {path:?} does not exist")) }) } Some(target) => TargetTriple::TargetTriple(target), @@ -2291,7 +2291,7 @@ fn parse_opt_level( "s" => OptLevel::Size, "z" => OptLevel::SizeMin, arg => { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "optimization level needs to be \ between 0-3, s or z (instead was `{arg}`)" )); @@ -2321,7 +2321,7 @@ fn parse_assert_incr_state( Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), Some(s) => { - early_dcx.early_error(format!("unexpected incremental state assertion value: {s}")) + early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}")) } None => None, } @@ -2348,11 +2348,11 @@ fn parse_native_lib_kind( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_dcx.early_error(format!("library kind `link-arg` is unstable{why}")) + early_dcx.early_fatal(format!("library kind `link-arg` is unstable{why}")) } NativeLibKind::LinkArg } - _ => early_dcx.early_error(format!( + _ => early_dcx.early_fatal(format!( "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" )), }; @@ -2372,7 +2372,7 @@ fn parse_native_lib_modifiers( for modifier in modifiers.split(',') { let (modifier, value) = match modifier.strip_prefix(['+', '-']) { Some(m) => (m, modifier.starts_with('+')), - None => early_dcx.early_error( + None => early_dcx.early_fatal( "invalid linking modifier syntax, expected '+' or '-' prefix \ before one of: bundle, verbatim, whole-archive, as-needed", ), @@ -2385,20 +2385,20 @@ fn parse_native_lib_modifiers( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_dcx.early_error(format!("linking modifier `{modifier}` is unstable{why}")) + early_dcx.early_fatal(format!("linking modifier `{modifier}` is unstable{why}")) } }; let assign_modifier = |dst: &mut Option| { if dst.is_some() { let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - early_dcx.early_error(msg) + early_dcx.early_fatal(msg) } else { *dst = Some(value); } }; match (modifier, &mut kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle), - ("bundle", _) => early_dcx.early_error( + ("bundle", _) => early_dcx.early_fatal( "linking modifier `bundle` is only compatible with `static` linking kind", ), @@ -2407,7 +2407,7 @@ fn parse_native_lib_modifiers( ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { assign_modifier(whole_archive) } - ("whole-archive", _) => early_dcx.early_error( + ("whole-archive", _) => early_dcx.early_fatal( "linking modifier `whole-archive` is only compatible with `static` linking kind", ), @@ -2416,14 +2416,14 @@ fn parse_native_lib_modifiers( report_unstable_modifier(); assign_modifier(as_needed) } - ("as-needed", _) => early_dcx.early_error( + ("as-needed", _) => early_dcx.early_fatal( "linking modifier `as-needed` is only compatible with \ `dylib` and `framework` linking kinds", ), // Note: this error also excludes the case with empty modifier // string, like `modifiers = ""`. - _ => early_dcx.early_error(format!( + _ => early_dcx.early_fatal(format!( "unknown linking modifier `{modifier}`, expected one \ of: bundle, verbatim, whole-archive, as-needed" )), @@ -2457,7 +2457,7 @@ fn parse_libs(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Vec (name.to_string(), Some(new_name.to_owned())), }; if name.is_empty() { - early_dcx.early_error("library name must not be empty"); + early_dcx.early_fatal("library name must not be empty"); } NativeLib { name, new_name, kind, verbatim } }) @@ -2493,7 +2493,7 @@ pub fn parse_externs( }; if !is_ascii_ident(&name) { - let mut error = early_dcx.early_struct_error(format!( + let mut error = early_dcx.early_struct_fatal(format!( "crate name `{name}` passed to `--extern` is not a valid ASCII identifier" )); let adjusted_name = name.replace('-', "_"); @@ -2555,7 +2555,7 @@ pub fn parse_externs( let mut force = false; if let Some(opts) = options { if !is_unstable_enabled { - early_dcx.early_error( + early_dcx.early_fatal( "the `-Z unstable-options` flag must also be passed to \ enable `--extern` options", ); @@ -2567,14 +2567,14 @@ pub fn parse_externs( if let ExternLocation::ExactPaths(_) = &entry.location { add_prelude = false; } else { - early_dcx.early_error( + early_dcx.early_fatal( "the `noprelude` --extern option requires a file path", ); } } "nounused" => nounused_dep = true, "force" => force = true, - _ => early_dcx.early_error(format!("unknown --extern option `{opt}`")), + _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")), } } } @@ -2602,7 +2602,7 @@ fn parse_remap_path_prefix( .into_iter() .map(|remap| match remap.rsplit_once('=') { None => { - early_dcx.early_error("--remap-path-prefix must contain '=' between FROM and TO") + early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO") } Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) @@ -2627,7 +2627,7 @@ fn parse_logical_env( if let Some((name, val)) = arg.split_once('=') { vars.insert(name.to_string(), val.to_string()); } else { - early_dcx.early_error(format!("`--env`: specify value for variable `{arg}`")); + early_dcx.early_fatal(format!("`--env`: specify value for variable `{arg}`")); } } @@ -2653,12 +2653,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M early_dcx.abort_if_error_and_set_error_format(error_format); let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { - early_dcx.early_error("`--diagnostic-width` must be an positive integer"); + early_dcx.early_fatal("`--diagnostic-width` must be an positive integer"); }); let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) - .unwrap_or_else(|e| early_dcx.early_error(e)); + .unwrap_or_else(|e| early_dcx.early_fatal(e)); let mut unstable_opts = UnstableOptions::build(early_dcx, matches); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); @@ -2666,7 +2666,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M check_error_format_stability(early_dcx, &unstable_opts, error_format, json_rendered); if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { - early_dcx.early_error( + early_dcx.early_fatal( "the `-Z unstable-options` flag must also be passed to enable \ the flag `--json=unused-externs`", ); @@ -2683,15 +2683,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); if unstable_opts.threads == 0 { - early_dcx.early_error("value for threads must be a positive non-zero integer"); + early_dcx.early_fatal("value for threads must be a positive non-zero integer"); } let fuel = unstable_opts.fuel.is_some() || unstable_opts.print_fuel.is_some(); if fuel && unstable_opts.threads > 1 { - early_dcx.early_error("optimization fuel is incompatible with multiple threads"); + early_dcx.early_fatal("optimization fuel is incompatible with multiple threads"); } if fuel && cg.incremental.is_some() { - early_dcx.early_error("optimization fuel is incompatible with incremental compilation"); + early_dcx.early_fatal("optimization fuel is incompatible with incremental compilation"); } let incremental = cg.incremental.as_ref().map(PathBuf::from); @@ -2699,25 +2699,25 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state); if unstable_opts.profile && incremental.is_some() { - early_dcx.early_error("can't instrument with gcov profiling when compiling incrementally"); + early_dcx.early_fatal("can't instrument with gcov profiling when compiling incrementally"); } if unstable_opts.profile { match codegen_units { Some(1) => {} None => codegen_units = Some(1), Some(_) => early_dcx - .early_error("can't instrument with gcov profiling with multiple codegen units"), + .early_fatal("can't instrument with gcov profiling with multiple codegen units"), } } if cg.profile_generate.enabled() && cg.profile_use.is_some() { - early_dcx.early_error("options `-C profile-generate` and `-C profile-use` are exclusive"); + early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive"); } if unstable_opts.profile_sample_use.is_some() && (cg.profile_generate.enabled() || cg.profile_use.is_some()) { - early_dcx.early_error( + early_dcx.early_fatal( "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`", ); } @@ -2730,7 +2730,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // Unstable values: Some(SymbolManglingVersion::Legacy) => { if !unstable_opts.unstable_options { - early_dcx.early_error( + early_dcx.early_fatal( "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", ); } @@ -2747,7 +2747,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M | InstrumentCoverage::ExceptUnusedFunctions | InstrumentCoverage::ExceptUnusedGenerics => { if !unstable_opts.unstable_options { - early_dcx.early_error( + early_dcx.early_fatal( "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \ require `-Z unstable-options`", ); @@ -2757,7 +2757,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M if cg.instrument_coverage != InstrumentCoverage::Off { if cg.profile_generate.enabled() || cg.profile_use.is_some() { - early_dcx.early_error( + early_dcx.early_fatal( "option `-C instrument-coverage` is not compatible with either `-C profile-use` \ or `-C profile-generate`", ); @@ -2787,7 +2787,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M match cg.lto { LtoCli::No | LtoCli::Unspecified => {} LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => { - early_dcx.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible") + early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible") } } } @@ -2799,7 +2799,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let uses_unstable_self_contained_option = cg.link_self_contained.are_unstable_variants_set(); if uses_unstable_self_contained_option { - early_dcx.early_error( + early_dcx.early_fatal( "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \ the `-Z unstable-options` flag must also be passed to use the unstable values", ); @@ -2807,7 +2807,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M if let Some(flavor) = cg.linker_flavor { if flavor.is_unstable() { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "the linker flavor `{}` is unstable, the `-Z unstable-options` \ flag must also be passed to use the unstable values", flavor.desc() @@ -2824,7 +2824,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M .map(|c| c.as_str().unwrap()) .intersperse(", ") .collect(); - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "some `-C link-self-contained` components were both enabled and disabled: {names}" )); } @@ -2871,7 +2871,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // query-dep-graph is required if dump-dep-graph is given #106736 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph { - early_dcx.early_error("can't dump dependency graph without `-Z query-dep-graph`"); + early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`"); } let logical_env = parse_logical_env(early_dcx, matches); @@ -2905,7 +2905,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { - early_dcx.early_error(format!("Current directory is invalid: {e}")); + early_dcx.early_fatal(format!("Current directory is invalid: {e}")); }); let remap = file_path_mapping(remap_path_prefix.clone(), &unstable_opts); @@ -2980,7 +2980,7 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O "mir" => Mir, "stable-mir" => StableMir, "mir-cfg" => MirCFG, - name => early_dcx.early_error(format!( + name => early_dcx.early_fatal(format!( "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ @@ -3060,7 +3060,7 @@ pub mod nightly_options { continue; } if opt.name != "Z" && !has_z_unstable_option { - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "the `-Z unstable-options` flag must also be passed to enable \ the flag `{}`", opt.name @@ -3076,7 +3076,7 @@ pub mod nightly_options { "the option `{}` is only accepted on the nightly compiler", opt.name ); - let _ = early_dcx.early_error_no_abort(msg); + let _ = early_dcx.early_err(msg); } OptionStability::Stable => {} } @@ -3086,7 +3086,7 @@ pub mod nightly_options { .early_help("consider switching to a nightly toolchain: `rustup default nightly`"); early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see "); early_dcx.early_note("for more information about Rust's stability policy, see "); - early_dcx.early_error(format!( + early_dcx.early_fatal(format!( "{} nightly option{} were parsed", nightly_options_on_stable, if nightly_options_on_stable > 1 { "s" } else { "" } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 8ab31f6f3825d..9f7d918d98b9c 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -4,8 +4,7 @@ use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, - Level, MultiSpan, + error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, }; use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; @@ -18,11 +17,7 @@ pub struct FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] - fn into_diagnostic( - self, - dcx: &'a DiagCtxt, - level: Level, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { let mut diag = DiagnosticBuilder::new(dcx, level, self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 06b554e8e63b1..10a4bdb94d46f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -337,12 +337,12 @@ fn build_options( Some((_, setter, type_desc, _)) => { if !setter(&mut op, value) { match value { - None => early_dcx.early_error( + None => early_dcx.early_fatal( format!( "{outputname} option `{key}` requires {type_desc} ({prefix} {key}=)" ), ), - Some(value) => early_dcx.early_error( + Some(value) => early_dcx.early_fatal( format!( "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected" ), @@ -350,7 +350,7 @@ fn build_options( } } } - None => early_dcx.early_error(format!("unknown {outputname} option: `{key}`")), + None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")), } } return op; @@ -1694,6 +1694,8 @@ options! { "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), + lint_mir: bool = (false, parse_bool, [UNTRACKED], + "lint MIR before and after each transformation"), llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], "a list of module flags to pass to LLVM (space separated)"), llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index b33cc83f9cf35..52a637b74e7a2 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -83,7 +83,7 @@ pub fn feature_err( feature: Symbol, span: impl Into, explain: impl Into, -) -> DiagnosticBuilder<'_, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_> { feature_err_issue(sess, feature, span, GateIssue::Language, explain) } @@ -98,7 +98,7 @@ pub fn feature_err_issue( span: impl Into, issue: GateIssue, explain: impl Into, -) -> DiagnosticBuilder<'_, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_> { let span = span.into(); // Cancel an earlier warning for this same error, if it exists. @@ -318,10 +318,7 @@ impl ParseSess { } #[track_caller] - pub fn create_err<'a>( - &'a self, - err: impl IntoDiagnostic<'a>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { err.into_diagnostic(&self.dcx, Level::Error { lint: false }) } @@ -371,10 +368,7 @@ impl ParseSess { #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_err( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> { self.dcx.struct_err(msg) } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 8ed50f6a14f15..9b913c76998e0 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -61,7 +61,7 @@ impl SearchPath { (PathKind::All, path) }; if path.is_empty() { - early_dcx.early_error("empty search path given via `-L`"); + early_dcx.early_fatal("empty search path given via `-L`"); } let dir = PathBuf::from(path); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index c9f0f74b0b21e..272e231d3edc1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -321,16 +321,6 @@ impl Session { } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_span_warn_with_expectation>( - &self, - sp: S, - msg: impl Into, - id: lint::LintExpectationId, - ) -> DiagnosticBuilder<'_, ()> { - self.dcx().struct_span_warn_with_expectation(sp, msg, id) - } - #[rustc_lint_diagnostics] - #[track_caller] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -346,24 +336,6 @@ impl Session { } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_warn_with_expectation( - &self, - msg: impl Into, - id: lint::LintExpectationId, - ) -> DiagnosticBuilder<'_, ()> { - self.dcx().struct_warn_with_expectation(msg, id) - } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_allow>( - &self, - sp: S, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ()> { - self.dcx().struct_span_allow(sp, msg) - } - #[rustc_lint_diagnostics] - #[track_caller] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.dcx().struct_allow(msg) } @@ -382,7 +354,7 @@ impl Session { &self, sp: S, msg: impl Into, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { self.dcx().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] @@ -392,16 +364,13 @@ impl Session { sp: S, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { self.dcx().struct_span_err_with_code(sp, msg, code) } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_err( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> { self.parse_sess.struct_err(msg) } #[track_caller] @@ -410,7 +379,7 @@ impl Session { &self, msg: impl Into, code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'_> { self.dcx().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] @@ -491,10 +460,7 @@ impl Session { self.dcx().err(msg) } #[track_caller] - pub fn create_err<'a>( - &'a self, - err: impl IntoDiagnostic<'a>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { self.parse_sess.create_err(err) } #[track_caller] @@ -502,10 +468,10 @@ impl Session { &'a self, err: impl IntoDiagnostic<'a>, feature: Symbol, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'a> { let mut err = self.parse_sess.create_err(err); if err.code.is_none() { - err.code = std::option::Option::Some(error_code!(E0658)); + err.code(error_code!(E0658)); } add_feature_diagnostics(&mut err, &self.parse_sess, feature); err @@ -1393,7 +1359,7 @@ pub fn build_session( let target_cfg = config::build_target_config(&early_dcx, &sopts, target_override, &sysroot); let host_triple = TargetTriple::from_triple(config::host_triple()); let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { - early_dcx.early_error(format!("Error loading host specification: {e}")) + early_dcx.early_fatal(format!("Error loading host specification: {e}")) }); for warning in target_warnings.warning_messages() { early_dcx.early_warn(warning) @@ -1768,19 +1734,19 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] - pub fn early_error_no_abort(&self, msg: impl Into) -> ErrorGuaranteed { + pub fn early_err(&self, msg: impl Into) -> ErrorGuaranteed { self.dcx.struct_err(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn early_error(&self, msg: impl Into) -> ! { + pub fn early_fatal(&self, msg: impl Into) -> ! { self.dcx.struct_fatal(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn early_struct_error( + pub fn early_struct_fatal( &self, msg: impl Into, ) -> DiagnosticBuilder<'_, FatalAbort> { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 8b7b26f969c96..5f505ac181cad 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -41,17 +41,26 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use rustc_hir::CoroutineKind; + use rustc_hir::{CoroutineDesugaring, CoroutineKind}; match self { - CoroutineKind::Async(source) => { - stable_mir::mir::CoroutineKind::Async(source.stable(tables)) + CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => { + stable_mir::mir::CoroutineKind::Desugared( + stable_mir::mir::CoroutineDesugaring::Async, + source.stable(tables), + ) } - CoroutineKind::Gen(source) => { - stable_mir::mir::CoroutineKind::Gen(source.stable(tables)) + CoroutineKind::Desugared(CoroutineDesugaring::Gen, source) => { + stable_mir::mir::CoroutineKind::Desugared( + stable_mir::mir::CoroutineDesugaring::Gen, + source.stable(tables), + ) } CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine, - CoroutineKind::AsyncGen(source) => { - stable_mir::mir::CoroutineKind::AsyncGen(source.stable(tables)) + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => { + stable_mir::mir::CoroutineKind::Desugared( + stable_mir::mir::CoroutineDesugaring::AsyncGen, + source.stable(tables), + ) } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 0190d5ab4be03..676b40850b1ee 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -1,7 +1,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::Node; use rustc_middle::ty::{self, Ty}; @@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> { found_args: Vec, is_closure: bool, closure_pipe_span: Option, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` /// in that order, and returns the generic type corresponding to the @@ -118,7 +118,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { found_args: Vec, is_closure: bool, closure_arg_span: Option, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let kind = if is_closure { "closure" } else { "function" }; let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a1b896d225125..e84c5b7642119 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, Style, SuggestionStyle, + MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; -use rustc_hir::{CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -207,7 +207,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ); @@ -220,7 +220,7 @@ pub trait TypeErrCtxtExt<'tcx> { cause: &ObligationCauseCode<'tcx>, found_node: Option>, param_env: ty::ParamEnv<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; fn note_conflicting_fn_args( &self, @@ -234,7 +234,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn note_conflicting_closure_bounds( &self, cause: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'tcx>, ); fn suggest_fully_qualified_path( @@ -1384,7 +1384,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if has_custom_message { err.note(msg); } else { - err.message = + err.messages = vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)]; } let mut file = None; @@ -1920,7 +1920,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { match obligation.cause.code().peel_derives() { @@ -1961,7 +1961,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { cause: &ObligationCauseCode<'tcx>, found_node: Option>, param_env: ty::ParamEnv<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -2187,7 +2187,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn note_conflicting_closure_bounds( &self, cause: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut DiagnosticBuilder<'tcx>, ) { // First, look for an `ExprBindingObligation`, which means we can get // the unsubstituted predicate list of the called function. And check @@ -2578,7 +2578,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .and_then(|coroutine_did| { Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() { CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"), - CoroutineKind::Async(CoroutineSource::Fn) => self + CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Fn, + ) => self .tcx .parent(coroutine_did) .as_local() @@ -2587,13 +2590,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|name| { format!("future returned by `{name}` is not {trait_name}") })?, - CoroutineKind::Async(CoroutineSource::Block) => { + CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block, + ) => { format!("future created by async block is not {trait_name}") } - CoroutineKind::Async(CoroutineSource::Closure) => { + CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Closure, + ) => { format!("future created by async closure is not {trait_name}") } - CoroutineKind::AsyncGen(CoroutineSource::Fn) => self + CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + CoroutineSource::Fn, + ) => self .tcx .parent(coroutine_did) .as_local() @@ -2602,27 +2614,40 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|name| { format!("async iterator returned by `{name}` is not {trait_name}") })?, - CoroutineKind::AsyncGen(CoroutineSource::Block) => { + CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + CoroutineSource::Block, + ) => { format!("async iterator created by async gen block is not {trait_name}") } - CoroutineKind::AsyncGen(CoroutineSource::Closure) => { + CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + CoroutineSource::Closure, + ) => { format!( "async iterator created by async gen closure is not {trait_name}" ) } - CoroutineKind::Gen(CoroutineSource::Fn) => self - .tcx - .parent(coroutine_did) - .as_local() - .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) - .map(|name| { - format!("iterator returned by `{name}` is not {trait_name}") - })?, - CoroutineKind::Gen(CoroutineSource::Block) => { + CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Fn) => { + self.tcx + .parent(coroutine_did) + .as_local() + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| { + format!("iterator returned by `{name}` is not {trait_name}") + })? + } + CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + CoroutineSource::Block, + ) => { format!("iterator created by gen block is not {trait_name}") } - CoroutineKind::Gen(CoroutineSource::Closure) => { + CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + CoroutineSource::Closure, + ) => { format!("iterator created by gen closure is not {trait_name}") } }) @@ -3145,9 +3170,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let what = match self.tcx.coroutine_kind(coroutine_def_id) { None | Some(hir::CoroutineKind::Coroutine) - | Some(hir::CoroutineKind::Gen(_)) => "yield", - Some(hir::CoroutineKind::Async(..)) => "await", - Some(hir::CoroutineKind::AsyncGen(_)) => "yield`/`await", + | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => { + "yield" + } + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + "await" + } + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => { + "yield`/`await" + } }; err.note(format!( "all values live across `{what}` must have a statically known size" @@ -3535,7 +3566,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) { if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let body = self.tcx.hir().body(body_id); - if let Some(hir::CoroutineKind::Async(_)) = body.coroutine_kind { + if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) = + body.coroutine_kind + { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 9ee091bbd1e6d..a495f8399b9f1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength :( + use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; @@ -59,7 +61,7 @@ pub trait TypeErrCtxtExt<'tcx> { predicate: &T, span: Span, suggest_increasing_limit: bool, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + ) -> DiagnosticBuilder<'tcx> where T: fmt::Display + TypeFoldable> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; @@ -118,7 +120,7 @@ pub trait TypeErrCtxtExt<'tcx> { &self, ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; } impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -263,7 +265,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate: &T, span: Span, suggest_increasing_limit: bool, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + ) -> DiagnosticBuilder<'tcx> where T: fmt::Display + TypeFoldable> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, { @@ -1226,7 +1228,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let span = obligation.cause.span; let mut diag = match ty.kind() { @@ -1491,7 +1493,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; fn report_type_parameter_mismatch_cyclic_type_error( &self, @@ -1499,13 +1501,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> { found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; fn report_opaque_type_auto_trait_leakage( &self, obligation: &PredicateObligation<'tcx>, def_id: DefId, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> DiagnosticBuilder<'tcx>; fn report_type_parameter_mismatch_error( &self, @@ -1513,13 +1515,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> { span: Span, found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Option>; + ) -> Option>; fn report_not_const_evaluatable_error( &self, obligation: &PredicateObligation<'tcx>, span: Span, - ) -> Option>; + ) -> Option>; } impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -1926,15 +1928,42 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> { self.tcx.hir().body(body_id).coroutine_kind.map(|coroutine_source| match coroutine_source { hir::CoroutineKind::Coroutine => "a coroutine", - hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block", - hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function", - hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure", - hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Block) => "an async gen block", - hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Fn) => "an async gen function", - hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Closure) => "an async gen closure", - hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "a gen block", - hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "a gen function", - hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "a gen closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) => "an async block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + ) => "an async function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + ) => "an async closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + ) => "an async gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + ) => "an async gen function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + ) => "an async gen closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + ) => "a gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + ) => "a gen function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + ) => "a gen closure", }) } @@ -3305,7 +3334,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let closure_span = self.tcx.def_span(closure_def_id); let mut err = ClosureKindMismatch { @@ -3347,7 +3376,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let self_ty = found_trait_ref.self_ty().skip_binder(); let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() { ( @@ -3367,7 +3396,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, def_id: DefId, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx> { let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { "opaque type".to_string() @@ -3409,7 +3438,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span: Span, found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Option> { + ) -> Option> { let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); @@ -3515,7 +3544,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, span: Span, - ) -> Option> { + ) -> Option> { if !self.tcx.features().generic_const_exprs { let mut err = self .tcx diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index a5f11ca23e124..86501b5a72d15 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -114,13 +114,13 @@ fn fn_sig_for_fn_abi<'tcx>( let pin_adt_ref = tcx.adt_def(pin_did); let pin_args = tcx.mk_args(&[env_ty.into()]); let env_ty = match coroutine_kind { - hir::CoroutineKind::Gen(_) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. env_ty } - hir::CoroutineKind::Async(_) - | hir::CoroutineKind::AsyncGen(_) + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) | hir::CoroutineKind::Coroutine => Ty::new_adt(tcx, pin_adt_ref, pin_args), }; @@ -131,7 +131,7 @@ fn fn_sig_for_fn_abi<'tcx>( // or the `Iterator::next(...) -> Option` function in case this is a // special coroutine backing a gen construct. let (resume_ty, ret_ty) = match coroutine_kind { - hir::CoroutineKind::Async(_) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` assert_eq!(sig.yield_ty, tcx.types.unit); @@ -156,7 +156,7 @@ fn fn_sig_for_fn_abi<'tcx>( (Some(context_mut_ref), ret_ty) } - hir::CoroutineKind::Gen(_) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { // The signature should be `Iterator::next(_) -> Option` let option_did = tcx.require_lang_item(LangItem::Option, None); let option_adt_ref = tcx.adt_def(option_did); @@ -168,7 +168,7 @@ fn fn_sig_for_fn_abi<'tcx>( (None, ret_ty) } - hir::CoroutineKind::AsyncGen(_) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { // The signature should be // `AsyncIterator::poll_next(_, &mut Context<'_>) -> Poll>` assert_eq!(sig.return_ty, tcx.types.unit); diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index b8fd9370aa618..89d75569ce3db 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -288,27 +288,33 @@ impl AssertMessage { AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine) => { Ok("coroutine resumed after completion") } - AssertMessage::ResumedAfterReturn(CoroutineKind::Async(_)) => { - Ok("`async fn` resumed after completion") - } - AssertMessage::ResumedAfterReturn(CoroutineKind::Gen(_)) => { - Ok("`async gen fn` resumed after completion") - } - AssertMessage::ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => { - Ok("`gen fn` should just keep returning `AssertMessage::None` after completion") - } + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after completion"), + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after completion"), + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"), AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine) => { Ok("coroutine resumed after panicking") } - AssertMessage::ResumedAfterPanic(CoroutineKind::Async(_)) => { - Ok("`async fn` resumed after panicking") - } - AssertMessage::ResumedAfterPanic(CoroutineKind::Gen(_)) => { - Ok("`async gen fn` resumed after panicking") - } - AssertMessage::ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => { - Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking") - } + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after panicking"), + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after panicking"), + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"), AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"), AssertMessage::MisalignedPointerDereference { .. } => { @@ -392,10 +398,8 @@ pub enum UnOp { #[derive(Clone, Debug, Eq, PartialEq)] pub enum CoroutineKind { - Async(CoroutineSource), + Desugared(CoroutineDesugaring, CoroutineSource), Coroutine, - Gen(CoroutineSource), - AsyncGen(CoroutineSource), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -405,6 +409,15 @@ pub enum CoroutineSource { Fn, } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum CoroutineDesugaring { + Async, + + Gen, + + AsyncGen, +} + pub(crate) type LocalDefId = Opaque; /// The rustc coverage data structures are heavily tied to internal details of the /// coverage implementation that are likely to change, and are unlikely to be diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index a7512ef6a24f3..db71a286b6dd0 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -135,3 +135,26 @@ impl Poll> { #[lang = "AsyncGenFinished"] pub const FINISHED: Self = Poll::Ready(None); } + +/// Convert something into an async iterator +#[unstable(feature = "async_iterator", issue = "79024")] +pub trait IntoAsyncIterator { + /// The type of the item yielded by the iterator + type Item; + /// The type of the resulting iterator + type IntoAsyncIter: AsyncIterator; + + /// Converts `self` into an async iterator + #[cfg_attr(not(bootstrap), lang = "into_async_iter_into_iter")] + fn into_async_iter(self) -> Self::IntoAsyncIter; +} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl IntoAsyncIterator for I { + type Item = I::Item; + type IntoAsyncIter = I; + + fn into_async_iter(self) -> Self::IntoAsyncIter { + self + } +} diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/async_iter/mod.rs index 0c6f637711b37..e1f1c9075823d 100644 --- a/library/core/src/async_iter/mod.rs +++ b/library/core/src/async_iter/mod.rs @@ -124,5 +124,5 @@ mod async_iter; mod from_iter; -pub use async_iter::AsyncIterator; +pub use async_iter::{AsyncIterator, IntoAsyncIterator}; pub use from_iter::{from_iter, FromIter}; diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs new file mode 100644 index 0000000000000..0c30bd1dfeac9 --- /dev/null +++ b/library/core/tests/async_iter/mod.rs @@ -0,0 +1,17 @@ +use core::async_iter::{self, AsyncIterator, IntoAsyncIterator}; +use core::pin::pin; +use core::task::Poll; + +#[test] +fn into_async_iter() { + let async_iter = async_iter::from_iter(0..3); + let mut async_iter = pin!(async_iter.into_async_iter()); + + let waker = core::task::Waker::noop(); + let mut cx = &mut core::task::Context::from_waker(&waker); + + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(0))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(2))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(None)); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index fabdd4ee25d45..b53cf4592445c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,6 +4,8 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] +#![feature(async_iter_from_iter)] +#![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] @@ -55,6 +57,7 @@ #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(min_specialization)] +#![feature(noop_waker)] #![feature(numfmt)] #![feature(num_midpoint)] #![feature(isqrt)] @@ -125,6 +128,7 @@ mod any; mod array; mod ascii; mod asserting; +mod async_iter; mod atomic; mod bool; mod cell; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index fb09d399b9868..f3d63fad71154 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -403,7 +403,7 @@ impl Options { && !matches.opt_present("show-coverage") && !nightly_options::is_unstable_enabled(matches) { - early_dcx.early_error( + early_dcx.early_fatal( "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", ); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 52803c2b00507..19db429ad8af6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -194,10 +194,10 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) { Ok("always") => true, Ok("never") => false, Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(), - Ok(value) => early_dcx.early_error(format!( + Ok(value) => early_dcx.early_fatal(format!( "invalid log color value '{value}': expected one of always, never, or auto", )), - Err(VarError::NotUnicode(value)) => early_dcx.early_error(format!( + Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!( "invalid log color value '{}': expected one of always, never, or auto", value.to_string_lossy() )), @@ -727,7 +727,7 @@ fn main_args( let matches = match options.parse(&args) { Ok(m) => m, Err(err) => { - early_dcx.early_error(err.to_string()); + early_dcx.early_fatal(err.to_string()); } }; diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index ce42b9c204b82..53c7f0f6e15dd 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -161,7 +161,7 @@ impl Emitter for BufferEmitter { let fluent_args = to_fluent_args(diag.args()); let translated_main_message = self - .translate_message(&diag.message[0].0, &fluent_args) + .translate_message(&diag.messages[0].0, &fluent_args) .unwrap_or_else(|e| panic!("{e}")); buffer.messages.push(format!("error from rustc: {translated_main_message}")); diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 3e5a01c45df1d..28e6614f03fb6 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; +use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -45,10 +45,9 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use CoroutineSource::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 9894a1639618d..dff6e884fa118 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{Body, CoroutineKind, CoroutineSource}; +use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::impl_lint_pass; @@ -194,8 +194,7 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use CoroutineSource::{Block, Closure, Fn}; - if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { self.check_interior_types(cx, coroutine_layout); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index eaaaea0be9f89..8982ce5e196ec 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -178,7 +178,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr && let closure_body = cx.tcx.hir().body(body) - && closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)) + && closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) { return Some(closure_body); } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index a4d3aaf0de988..350707d3a1361 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -3,7 +3,7 @@ use clippy_utils::path_res; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -86,7 +86,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 19d9d64b31e3c..4b3fe9c0bb556 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) - && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) + && matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) { cx.typeck_results() .closure_min_captures diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 8bac2e40e0128..9312a9c89b789 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -67,7 +67,7 @@ fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) // checks whether it is `async || whatever_expression` - && let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind + && let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind { true } else { diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 9c8c44c0a16df..f71fe4e1e92e1 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -86,7 +86,13 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); + let is_async_block = matches!( + b.coroutine_kind, + Some(rustc_hir::CoroutineKind::Desugared( + rustc_hir::CoroutineDesugaring::Async, + _ + )) + ); if is_async_block { self.async_depth += 1; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 5d53a4d28f2e2..ca80328f3ac03 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2445,6 +2445,7 @@ impl<'test> TestCx<'test> { "-Copt-level=1", &zdump_arg, "-Zvalidate-mir", + "-Zlint-mir", "-Zdump-mir-exclude-pass-number", ]); if let Some(pass) = &self.props.mir_unit_test { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index a70a9d4602ebd..4c284ff81ee81 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU64; use log::trace; -use rustc_errors::DiagnosticMessage; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, Level}; use rustc_span::{SpanData, Symbol, DUMMY_SP}; use rustc_target::abi::{Align, Size}; @@ -453,11 +453,13 @@ pub fn report_msg<'tcx>( ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let sess = machine.tcx.sess; - let mut err = match diag_level { - DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(), - DiagLevel::Warning => sess.struct_span_warn(span, title), - DiagLevel::Note => sess.dcx().struct_span_note(span, title), + let level = match diag_level { + DiagLevel::Error => Level::Error { lint: false }, + DiagLevel::Warning => Level::Warning(None), + DiagLevel::Note => Level::Note, }; + let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title); + err.set_span(span); // Show main message. if span != DUMMY_SP { diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index e8f7b422adaa6..8303c03e1eb4c 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -370,7 +370,7 @@ mod tests { fn build_diagnostic(level: DiagnosticLevel, span: Option) -> Diagnostic { let mut diag = Diagnostic::new(level, ""); - diag.message.clear(); + diag.messages.clear(); if let Some(span) = span { diag.span = span; } diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs index 1b9c8fe15c25e..8adfbb4535b9a 100644 --- a/tests/mir-opt/reference_prop.rs +++ b/tests/mir-opt/reference_prop.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zlint-mir=no // unit-test: ReferencePropagation // needs-unwind diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr index 866a53f57fc23..2fceeb15ea983 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -33,7 +33,14 @@ error[E0223]: ambiguous associated type --> $DIR/issue-109071.rs:15:22 | LL | fn T() -> Option {} - | ^^^^^^^^^^ help: use fully-qualified syntax: ` as IntoIterator>::Item` + | ^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | fn T() -> Option< as IntoAsyncIterator>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | fn T() -> Option< as IntoIterator>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/for-await-consumes-iter.stderr b/tests/ui/async-await/for-await-consumes-iter.stderr index 48b2e8a51d830..a3e5bbcabf5d0 100644 --- a/tests/ui/async-await/for-await-consumes-iter.stderr +++ b/tests/ui/async-await/for-await-consumes-iter.stderr @@ -5,22 +5,17 @@ LL | let iter = core::async_iter::from_iter(0..3); | ---- move occurs because `iter` has type `FromIter>`, which does not implement the `Copy` trait LL | let mut count = 0; LL | for await i in iter { - | ------------------- - | | | - | | value moved here - | inside of this loop + | ---- `iter` moved due to this method call ... LL | for await i in iter { | ^^^^ value used here after move | -help: consider cloning the value if the performance cost is acceptable +note: `into_async_iter` takes ownership of the receiver `self`, which moves `iter` + --> $SRC_DIR/core/src/async_iter/async_iter.rs:LL:COL +help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | for await i in iter.clone() { | ++++++++ -help: borrow this binding in the pattern to avoid moving the value - | -LL | for await i in ref iter { - | +++ error: aborting due to 1 previous error diff --git a/tests/ui/mir/lint/no-storage.rs b/tests/ui/mir/lint/no-storage.rs new file mode 100644 index 0000000000000..246a0b34e5db8 --- /dev/null +++ b/tests/ui/mir/lint/no-storage.rs @@ -0,0 +1,30 @@ +// compile-flags: -Zlint-mir --crate-type=lib -Ztreat-err-as-bug +// failure-status: 101 +// dont-check-compiler-stderr +// regex-error-pattern: use of local .*, which has no storage here +#![feature(custom_mir, core_intrinsics)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "built")] +pub fn f(a: bool) { + mir!( + let b: (); + { + match a { true => bb1, _ => bb2 } + } + bb1 = { + StorageLive(b); + Goto(bb3) + } + bb2 = { + Goto(bb3) + } + bb3 = { + b = (); + RET = b; + StorageDead(b); + Return() + } + ) +} diff --git a/tests/ui/mir/validate/storage-live.rs b/tests/ui/mir/lint/storage-live.rs similarity index 93% rename from tests/ui/mir/validate/storage-live.rs rename to tests/ui/mir/lint/storage-live.rs index ed3c26ed6da5a..f34a2c7de37f8 100644 --- a/tests/ui/mir/validate/storage-live.rs +++ b/tests/ui/mir/lint/storage-live.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zvalidate-mir -Ztreat-err-as-bug +// compile-flags: -Zlint-mir -Ztreat-err-as-bug // failure-status: 101 // error-pattern: broken MIR in // error-pattern: StorageLive(_1) which already has storage here diff --git a/tests/ui/mir/validate/storage-live.stderr b/tests/ui/mir/lint/storage-live.stderr similarity index 100% rename from tests/ui/mir/validate/storage-live.stderr rename to tests/ui/mir/lint/storage-live.stderr diff --git a/tests/ui/mir/lint/storage-return.rs b/tests/ui/mir/lint/storage-return.rs new file mode 100644 index 0000000000000..a2f63b449b4d5 --- /dev/null +++ b/tests/ui/mir/lint/storage-return.rs @@ -0,0 +1,19 @@ +// compile-flags: -Zlint-mir -Ztreat-err-as-bug +// failure-status: 101 +// dont-check-compiler-stderr +// error-pattern: has storage when returning +#![feature(custom_mir, core_intrinsics)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "built")] +fn main() { + mir!( + let a: (); + { + StorageLive(a); + RET = a; + Return() + } + ) +} diff --git a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr index c0f0c41422736..cabaa76a8867d 100644 --- a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -2,7 +2,14 @@ error[E0223]: ambiguous associated type --> $DIR/suggest-trait-in-ufcs-in-hrtb.rs:5:38 | LL | impl Foo for Bar where for<'a> <&'a S>::Item: Foo {} - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'a S as IntoIterator>::Item` + | ^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | impl Foo for Bar where for<'a> <&'a S as IntoAsyncIterator>::Item: Foo {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | impl Foo for Bar where for<'a> <&'a S as IntoIterator>::Item: Foo {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/typeck/issue-110052.stderr b/tests/ui/typeck/issue-110052.stderr index b25b6c0c0b78c..5eb10d9a30e86 100644 --- a/tests/ui/typeck/issue-110052.stderr +++ b/tests/ui/typeck/issue-110052.stderr @@ -2,7 +2,14 @@ error[E0223]: ambiguous associated type --> $DIR/issue-110052.rs:6:30 | LL | for<'iter> dyn Validator<<&'iter I>::Item>:, - | ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'iter I as IntoIterator>::Item` + | ^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | for<'iter> dyn Validator<<&'iter I as IntoAsyncIterator>::Item>:, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | for<'iter> dyn Validator<<&'iter I as IntoIterator>::Item>:, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error