Merge from rustc

This commit is contained in:
The Miri Conjob Bot
2023-12-24 05:00:43 +00:00
329 changed files with 5139 additions and 4558 deletions
+2 -1
View File
@@ -289,8 +289,9 @@ jobs:
os: ubuntu-20.04-4core-16gb
env: {}
- name: x86_64-gnu-integration
env:
CI_ONLY_WHEN_CHANNEL: nightly
os: ubuntu-20.04-16core-64gb
env: {}
- name: x86_64-gnu-debug
os: ubuntu-20.04-8core-32gb
env: {}
+1
View File
@@ -4340,6 +4340,7 @@ dependencies = [
name = "rustc_pattern_analysis"
version = "0.0.0"
dependencies = [
"derivative",
"rustc_apfloat",
"rustc_arena",
"rustc_data_structures",
+634 -584
View File
@@ -11,6 +11,24 @@
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<FieldIdx, F>) -> bool
where
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + 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<TargetDataLayout>;
@@ -162,24 +180,6 @@ fn layout_of_struct_or_enum<
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<FieldIdx, F>| {
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 @@ fn layout_of_struct_or_enum<
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<FieldIdx: Idx, VariantIdx: Idx> {
layout: LayoutS<FieldIdx, VariantIdx>,
variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
}
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
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::<Option<IndexVec<VariantIdx, _>>>()?;
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::<Option<IndexVec<VariantIdx, _>>>()?;
// 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 well 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
// 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 {
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")
}
}
}
// 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 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 {
scalar_unit(prim)
} else {
// Common prim might be uninit.
Scalar::Union { value: prim }
};
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(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<FieldIdx, VariantIdx>| {
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 @@ fn layout_of_union<
}
}
/// 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<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
is_unsafe_cell: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
always_sized: bool,
dl: &TargetDataLayout,
present_first: VariantIdx,
) -> Option<LayoutS<FieldIdx, VariantIdx>>
where
LC: LayoutCalculator + ?Sized,
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + 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<VariantIdx, IndexVec<FieldIdx, F>>,
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
dont_niche_optimize_enum: bool,
dl: &TargetDataLayout,
) -> Option<LayoutS<FieldIdx, VariantIdx>>
where
LC: LayoutCalculator + ?Sized,
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + 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<FieldIdx: Idx, VariantIdx: Idx> {
layout: LayoutS<FieldIdx, VariantIdx>,
variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
}
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
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::<Option<IndexVec<VariantIdx, _>>>()?;
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::<Option<IndexVec<VariantIdx, _>>>()?;
// 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 well 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::<FieldIdx, VariantIdx>(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<FieldIdx, VariantIdx>| {
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,
+71 -41
View File
@@ -286,41 +286,16 @@ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
/// A modifier on a bound, e.g., `?Trait` or `~const Trait`.
///
/// Negative bounds should also be handled here.
/// Modifiers on a trait bound like `~const`, `?` and `!`.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
pub enum TraitBoundModifier {
/// No modifiers
None,
/// `!Trait`
Negative,
/// `?Trait`
Maybe,
/// `~const Trait`
MaybeConst(Span),
/// `~const !Trait`
//
// This parses but will be rejected during AST validation.
MaybeConstNegative,
/// `~const ?Trait`
//
// This parses but will be rejected during AST validation.
MaybeConstMaybe,
pub struct TraitBoundModifiers {
pub constness: BoundConstness,
pub polarity: BoundPolarity,
}
impl TraitBoundModifier {
pub fn to_constness(self) -> Const {
match self {
Self::MaybeConst(span) => Const::Yes(span),
_ => Const::No,
}
}
impl TraitBoundModifiers {
pub const NONE: Self =
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
}
/// The AST represents all type param bounds as types.
@@ -329,7 +304,7 @@ pub fn to_constness(self) -> Const {
/// detects `Copy`, `Send` and `Sync`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum GenericBound {
Trait(PolyTraitRef, TraitBoundModifier),
Trait(PolyTraitRef, TraitBoundModifiers),
Outlives(Lifetime),
}
@@ -779,8 +754,7 @@ pub enum PatKind {
Ident(BindingAnnotation, Ident, Option<P<Pat>>),
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
/// The `bool` is `true` in the presence of a `..`.
Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, /* recovered */ bool),
Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, PatFieldsRest),
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>),
@@ -837,6 +811,15 @@ pub enum PatKind {
MacCall(P<MacCall>),
}
/// Whether the `..` is present in a struct fields pattern.
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
pub enum PatFieldsRest {
/// `module::StructName { field, ..}`
Rest,
/// `module::StructName { field }`
None,
}
/// The kind of borrow in an `AddrOf` expression,
/// e.g., `&place` or `&raw const place`.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -1193,7 +1176,7 @@ pub fn to_bound(&self) -> Option<GenericBound> {
match &self.kind {
ExprKind::Path(None, path) => Some(GenericBound::Trait(
PolyTraitRef::new(ThinVec::new(), path.clone(), self.span),
TraitBoundModifier::None,
TraitBoundModifiers::NONE,
)),
_ => None,
}
@@ -1274,7 +1257,7 @@ pub fn precedence(&self) -> ExprPrecedence {
ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1436,10 +1419,10 @@ pub enum ExprKind {
While(P<Expr>, P<Block>, Option<Label>),
/// A `for` loop, with an optional label.
///
/// `'label: for pat in expr { block }`
/// `'label: for await? pat in iter { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// `'label: loop { block }`
@@ -1542,6 +1525,13 @@ pub enum ExprKind {
Err,
}
/// Used to differentiate between `for` loops and `for await` loops.
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum ForLoopKind {
For,
ForAwait,
}
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum GenBlockKind {
@@ -2491,6 +2481,15 @@ pub enum Const {
No,
}
impl From<BoundConstness> for Const {
fn from(constness: BoundConstness) -> Self {
match constness {
BoundConstness::Maybe(span) => Self::Yes(span),
BoundConstness::Never => Self::No,
}
}
}
/// Item defaultness.
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -2516,7 +2515,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
/// The polarity of a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(HashStable_Generic)]
pub enum BoundPolarity {
/// `Type: Trait`
Positive,
@@ -2526,6 +2527,35 @@ pub enum BoundPolarity {
Maybe(Span),
}
impl BoundPolarity {
pub fn as_str(self) -> &'static str {
match self {
Self::Positive => "",
Self::Negative(_) => "!",
Self::Maybe(_) => "?",
}
}
}
/// The constness of a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(HashStable_Generic)]
pub enum BoundConstness {
/// `Type: Trait`
Never,
/// `Type: ~const Trait`
Maybe(Span),
}
impl BoundConstness {
pub fn as_str(self) -> &'static str {
match self {
Self::Never => "",
Self::Maybe(_) => "~const",
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum FnRetTy {
/// Returns type is not specified.
@@ -3259,7 +3289,7 @@ mod size_asserts {
static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24);
static_assert_size!(GenericArg, 24);
static_assert_size!(GenericBound, 64);
static_assert_size!(GenericBound, 72);
static_assert_size!(Generics, 40);
static_assert_size!(Impl, 136);
static_assert_size!(Item, 136);
+1 -1
View File
@@ -1389,7 +1389,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_block(body);
visit_opt(label, |label| vis.visit_label(label));
}
ExprKind::ForLoop(pat, iter, body, label) => {
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
vis.visit_pat(pat);
vis.visit_expr(iter);
vis.visit_block(body);
+11 -3
View File
@@ -19,7 +19,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
| ast::ExprKind::Block(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::TryBlock(..)
| ast::ExprKind::ConstBlock(..)
)
@@ -48,8 +48,16 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
Closure(closure) => {
expr = &closure.body;
}
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
Gen(..)
| Block(..)
| ForLoop { .. }
| If(..)
| Loop(..)
| Match(..)
| Struct(..)
| TryBlock(..)
| While(..)
| ConstBlock(_) => break Some(expr),
// FIXME: These can end in `}`, but changing these would break stable code.
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
+5 -5
View File
@@ -844,11 +844,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
ExprKind::ForLoop(pattern, subexpression, block, opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_pat(pattern);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
walk_list!(visitor, visit_label, label);
visitor.visit_pat(pat);
visitor.visit_expr(iter);
visitor.visit_block(body);
}
ExprKind::Loop(block, opt_label, _) => {
walk_list!(visitor, visit_label, opt_label);
+136 -42
View File
@@ -56,12 +56,12 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
return ex;
}
// Desugar `ExprForLoop`
// from: `[opt_ident]: for <pat> in <head> <body>`
// from: `[opt_ident]: for await? <pat> in <iter> <body>`
//
// This also needs special handling because the HirId of the returned `hir::Expr` will not
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
ExprKind::ForLoop(pat, head, body, opt_label) => {
return self.lower_expr_for(e, pat, head, body, *opt_label);
ExprKind::ForLoop { pat, iter, body, label, kind } => {
return self.lower_expr_for(e, pat, iter, body, *label, *kind);
}
_ => (),
}
@@ -337,7 +337,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
),
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
unreachable!("already handled")
}
@@ -670,7 +670,10 @@ pub(super) fn make_async_expr(
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 @@ pub(super) fn make_gen_expr(
});
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 @@ pub(super) fn make_async_gen_expr(
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);
@@ -874,12 +883,25 @@ pub(super) fn maybe_forward_track_caller(
/// }
/// ```
fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
let expr = self.arena.alloc(self.lower_expr_mut(expr));
self.make_lowered_await(await_kw_span, expr, FutureKind::Future)
}
/// Takes an expr that has already been lowered and generates a desugared await loop around it
fn make_lowered_await(
&mut self,
await_kw_span: Span,
expr: &'hir hir::Expr<'hir>,
await_kind: FutureKind,
) -> hir::ExprKind<'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,
@@ -887,13 +909,16 @@ fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKin
}
};
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
let features = match await_kind {
FutureKind::Future => None,
FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
};
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
full_span,
Some(self.allow_gen_future.clone()),
);
let expr = self.lower_expr_mut(expr);
let expr_hir_id = expr.hir_id;
// Note that the name of this binding must not be changed to something else because
@@ -934,11 +959,18 @@ fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKin
hir::LangItem::GetContext,
arena_vec![self; task_context],
);
let call = self.expr_call_lang_item_fn(
span,
hir::LangItem::FuturePoll,
arena_vec![self; new_unchecked, get_context],
);
let call = match await_kind {
FutureKind::Future => self.expr_call_lang_item_fn(
span,
hir::LangItem::FuturePoll,
arena_vec![self; new_unchecked, get_context],
),
FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
span,
hir::LangItem::AsyncIteratorPollNext,
arena_vec![self; new_unchecked, get_context],
),
};
self.arena.alloc(self.expr_unsafe(call))
};
@@ -1020,11 +1052,16 @@ fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKin
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
let into_future_expr = self.expr_call_lang_item_fn(
span,
hir::LangItem::IntoFutureIntoFuture,
arena_vec![self; expr],
);
let into_future_expr = match await_kind {
FutureKind::Future => self.expr_call_lang_item_fn(
span,
hir::LangItem::IntoFutureIntoFuture,
arena_vec![self; *expr],
),
// Not needed for `for await` because we expect to have already called
// `IntoAsyncIterator::into_async_iter` on it.
FutureKind::AsyncIterator => expr,
};
// match <into_future_expr> {
// mut __awaitee => loop { .. }
@@ -1097,9 +1134,9 @@ fn coroutine_movability_for_fn(
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");
}
@@ -1612,9 +1649,9 @@ fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'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 }),
);
@@ -1685,6 +1722,7 @@ fn lower_expr_for(
head: &Expr,
body: &Block,
opt_label: Option<Label>,
loop_kind: ForLoopKind,
) -> hir::Expr<'hir> {
let head = self.lower_expr_mut(head);
let pat = self.lower_pat(pat);
@@ -1713,17 +1751,41 @@ fn lower_expr_for(
let (iter_pat, iter_pat_nid) =
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
// `match Iterator::next(&mut iter) { ... }`
let match_expr = {
let iter = self.expr_ident(head_span, iter, iter_pat_nid);
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
let next_expr = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
);
let next_expr = match loop_kind {
ForLoopKind::For => {
// `Iterator::next(&mut iter)`
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
)
}
ForLoopKind::ForAwait => {
// we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this
// to make_lowered_await with `FutureKind::AsyncIterator` which will generator
// calls to `poll_next`. In user code, this would probably be a call to
// `Pin::as_mut` but here it's easy enough to do `new_unchecked`.
// `&mut iter`
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));
let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
}
};
let arms = arena_vec![self; none_arm, some_arm];
// `match $next_expr { ... }`
self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
};
let match_stmt = self.stmt_expr(for_span, match_expr);
@@ -1743,13 +1805,34 @@ fn lower_expr_for(
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
let into_iter_expr = match loop_kind {
ForLoopKind::For => {
// `::std::iter::IntoIterator::into_iter(<head>)`
self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
}
// ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }`
ForLoopKind::ForAwait => {
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
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(
@@ -2152,3 +2235,14 @@ pub(super) fn arm(
}
}
}
/// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
/// of future we are awaiting.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum FutureKind {
/// We are awaiting a normal future
Future,
/// We are awaiting something that's known to be an AsyncIterator (i.e. we are in the header of
/// a `for await` loop)
AsyncIterator,
}
+7 -1
View File
@@ -1372,7 +1372,13 @@ fn lower_generics<T>(
// need to compute this at all unless there is a Maybe bound.
let mut is_param: Option<bool> = None;
for bound in &bound_pred.bounds {
if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
if !matches!(
*bound,
GenericBound::Trait(
_,
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }
)
) {
continue;
}
let is_param = *is_param.get_or_insert_with(compute_is_param);
+29 -26
View File
@@ -130,6 +130,7 @@ struct LoweringContext<'a, 'hir> {
allow_try_trait: Lrc<[Symbol]>,
allow_gen_future: Lrc<[Symbol]>,
allow_async_iterator: Lrc<[Symbol]>,
allow_for_await: Lrc<[Symbol]>,
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
@@ -174,6 +175,7 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
} else {
[sym::gen_future].into()
},
allow_for_await: [sym::async_iterator].into(),
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
// interact with `gen`/`async gen` blocks
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
@@ -1425,19 +1427,16 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait(
ty,
modifier @ (TraitBoundModifier::None
| TraitBoundModifier::MaybeConst(_)
| TraitBoundModifier::Negative),
) => {
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
}
// `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
TraitBoundModifiers {
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
constness,
},
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
// We can safely ignore constness here, since AST validation
// will take care of invalid modifier combinations.
GenericBound::Trait(
_,
TraitBoundModifier::Maybe
| TraitBoundModifier::MaybeConstMaybe
| TraitBoundModifier::MaybeConstNegative,
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. },
) => None,
GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() {
@@ -2028,9 +2027,9 @@ fn lower_param_bound(
itctx: &ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
self.lower_trait_bound_modifier(*modifier),
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
self.lower_trait_bound_modifiers(*modifiers),
),
GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
@@ -2316,25 +2315,29 @@ fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
}
}
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
match f {
TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst,
TraitBoundModifier::Negative => {
fn lower_trait_bound_modifiers(
&mut self,
modifiers: TraitBoundModifiers,
) -> hir::TraitBoundModifier {
match (modifiers.constness, modifiers.polarity) {
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
if self.tcx.features().negative_bounds {
hir::TraitBoundModifier::Negative
} else {
hir::TraitBoundModifier::None
}
}
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
// placeholder for compilation to proceed.
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
hir::TraitBoundModifier::Maybe
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
hir::TraitBoundModifier::MaybeConst
}
// Invalid modifier combinations will cause an error during AST validation.
// Arbitrarily pick a placeholder for compilation to proceed.
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
hir::TraitBoundModifier::MaybeConst
}
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
}
}
+1 -1
View File
@@ -82,7 +82,7 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
span: self.lower_span(f.span),
}
}));
break hir::PatKind::Struct(qpath, fs, *etc);
break hir::PatKind::Struct(qpath, fs, *etc == ast::PatFieldsRest::Rest);
}
PatKind::Tuple(pats) => {
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
+2 -2
View File
@@ -152,6 +152,8 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features
ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
.because = {$annotation} because of this
.type = inherent impl for this type
@@ -195,8 +197,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
.help = use `auto trait Trait {"{}"}` instead
ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
+17 -16
View File
@@ -1196,18 +1196,18 @@ fn visit_generic_param(&mut self, param: &'a GenericParam) {
}
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
if let GenericBound::Trait(poly, modify) = bound {
match (ctxt, modify) {
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
if let GenericBound::Trait(poly, modifiers) = bound {
match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path),
});
}
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
}
(_, &TraitBoundModifier::MaybeConst(span))
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
if let Some(reason) = &self.disallow_tilde_const =>
{
let reason = match reason {
@@ -1235,16 +1235,15 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
};
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
}
(_, TraitBoundModifier::MaybeConstMaybe) => {
self.dcx().emit_err(errors::OptionalConstExclusive {
(
_,
BoundConstness::Maybe(_),
BoundPolarity::Maybe(_) | BoundPolarity::Negative(_),
) => {
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
span: bound.span(),
modifier: "?",
});
}
(_, TraitBoundModifier::MaybeConstNegative) => {
self.dcx().emit_err(errors::OptionalConstExclusive {
span: bound.span(),
modifier: "!",
left: modifiers.constness.as_str(),
right: modifiers.polarity.as_str(),
});
}
_ => {}
@@ -1252,7 +1251,8 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
}
// Negative trait bounds are not allowed to have associated constraints
if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
if let GenericBound::Trait(trait_ref, modifiers) = bound
&& let BoundPolarity::Negative(_) = modifiers.polarity
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
{
@@ -1494,7 +1494,8 @@ fn deny_equality_constraints(
for param in &generics.params {
if param.ident == potential_param.ident {
for bound in &param.bounds {
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
bound
{
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
let assoc = pprust::path_to_string(&ast::Path::from_ident(
+4 -3
View File
@@ -580,11 +580,12 @@ pub enum TildeConstReason {
}
#[derive(Diagnostic)]
#[diag(ast_passes_optional_const_exclusive)]
pub struct OptionalConstExclusive {
#[diag(ast_passes_incompatible_trait_bound_modifiers)]
pub struct IncompatibleTraitBoundModifiers {
#[primary_span]
pub span: Span,
pub modifier: &'static str,
pub left: &'static str,
pub right: &'static str,
}
#[derive(Diagnostic)]
@@ -527,6 +527,7 @@ macro_rules! gate_all {
"async closures are unstable",
"to use an async block, remove the `||`: `async {`"
);
gate_all!(async_for_loop, "`for await` loops are experimental");
gate_all!(
closure_lifetime_binder,
"`for<...>` binders for closures are experimental",
+1
View File
@@ -4,6 +4,7 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![feature(box_patterns)]
#![feature(let_chains)]
#![recursion_limit = "256"]
mod helpers;
+15 -21
View File
@@ -17,7 +17,7 @@
use rustc_ast::util::parser;
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{GenericArg, GenericBound, SelfKind};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_span::edition::Edition;
@@ -1427,7 +1427,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
}
self.nbsp();
self.word("{");
let empty = fields.is_empty() && !etc;
let empty = fields.is_empty() && *etc == ast::PatFieldsRest::None;
if !empty {
self.space();
}
@@ -1445,7 +1445,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
},
|f| f.pat.span,
);
if *etc {
if *etc == ast::PatFieldsRest::Rest {
if !fields.is_empty() {
self.word_space(",");
}
@@ -1559,26 +1559,20 @@ pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
match bound {
GenericBound::Trait(tref, modifier) => {
match modifier {
TraitBoundModifier::None => {}
TraitBoundModifier::Negative => {
self.word("!");
}
TraitBoundModifier::Maybe => {
self.word("?");
}
TraitBoundModifier::MaybeConst(_) => {
self.word_space("~const");
}
TraitBoundModifier::MaybeConstNegative => {
self.word_space("~const");
self.word("!");
}
TraitBoundModifier::MaybeConstMaybe => {
self.word_space("~const");
self.word("?");
match modifier.constness {
ast::BoundConstness::Never => {}
ast::BoundConstness::Maybe(_) => {
self.word_space(modifier.constness.as_str());
}
}
match modifier.polarity {
ast::BoundPolarity::Positive => {}
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
self.word(modifier.polarity.as_str());
}
}
self.print_poly_trait_ref(tref);
}
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
@@ -1,5 +1,6 @@
use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::ForLoopKind;
use itertools::{Itertools, Position};
use rustc_ast::ptr::P;
use rustc_ast::token;
@@ -418,20 +419,23 @@ pub(super) fn print_expr_outer_attr_style(
self.space();
self.print_block_with_attrs(blk, attrs);
}
ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => {
if let Some(label) = opt_label {
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
if let Some(label) = label {
self.print_ident(label.ident);
self.word_space(":");
}
self.cbox(0);
self.ibox(0);
self.word_nbsp("for");
if kind == &ForLoopKind::ForAwait {
self.word_nbsp("await");
}
self.print_pat(pat);
self.space();
self.word_space("in");
self.print_expr_as_cond(iter);
self.space();
self.print_block_with_attrs(blk, attrs);
self.print_block_with_attrs(body, attrs);
}
ast::ExprKind::Loop(blk, opt_label, _) => {
if let Some(label) = opt_label {
@@ -5,7 +5,6 @@
use ast::StaticItem;
use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::GenericBound;
use rustc_ast::ModKind;
use rustc_span::symbol::Ident;
@@ -338,19 +337,9 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
self.word_nbsp("trait");
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() {
if let GenericBound::Trait(ptr, ast::TraitBoundModifier::Maybe) = b {
self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
real_bounds.push(b.clone());
}
}
if !real_bounds.is_empty() {
if !bounds.is_empty() {
self.word_nbsp(":");
self.print_type_bounds(&real_bounds);
self.print_type_bounds(bounds);
}
self.print_where_clause(&generics.where_clause);
self.word(" ");
+14 -13
View File
@@ -2,7 +2,8 @@
use rustc_ast as ast;
use rustc_errors::{
error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
Level,
};
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
@@ -50,14 +51,12 @@ pub(crate) struct UnknownMetaItem<'a> {
}
// Manual implementation to be able to format `expected` items correctly.
impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
let mut diag = dcx.struct_span_err_with_code(
self.span,
fluent::attr_unknown_meta_item,
error_code!(E0541),
);
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item);
diag.set_span(self.span);
diag.code(error_code!(E0541));
diag.set_arg("item", self.item);
diag.set_arg("expected", expected.join(", "));
diag.span_label(self.span, fluent::attr_label);
@@ -200,10 +199,11 @@ pub(crate) struct UnsupportedLiteral {
pub start_point_span: Span,
}
impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = dcx.struct_span_err_with_code(
self.span,
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = DiagnosticBuilder::new(
dcx,
level,
match self.reason {
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
@@ -214,8 +214,9 @@ fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaran
fluent::attr_unsupported_literal_deprecated_kv_pair
}
},
error_code!(E0565),
);
diag.set_span(self.span);
diag.code(error_code!(E0565));
if self.is_bytestr {
diag.span_suggestion(
self.start_point_span,
+26 -30
View File
@@ -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 @@ pub(crate) fn cannot_move_when_borrowed(
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 @@ pub(crate) fn cannot_use_when_mutably_borrowed(
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 @@ pub(crate) fn cannot_mutably_borrow_multiply(
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
) -> 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 @@ pub(crate) fn cannot_uniquely_borrow_by_two_closures(
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
self,
new_loan_span,
@@ -130,7 +130,7 @@ pub(crate) fn cannot_uniquely_borrow_by_one_closure(
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
@@ -162,7 +162,7 @@ pub(crate) fn cannot_reborrow_already_uniquely_borrowed(
old_opt_via: &str,
previous_end_span: Option<Span>,
second_borrow_desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
@@ -194,7 +194,7 @@ pub(crate) fn cannot_reborrow_already_borrowed(
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
) -> 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 @@ pub(crate) fn cannot_assign_to_borrowed(
span: Span,
borrow_span: Span,
desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
@@ -254,16 +254,12 @@ pub(crate) fn cannot_reassign_immutable(
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 @@ pub(crate) fn cannot_move_out_of(
&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 @@ pub(crate) fn cannot_move_out_of_interior_noncopy(
move_from_span: Span,
ty: Ty<'_>,
is_index: Option<bool>,
) -> 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 @@ pub(crate) fn cannot_move_out_of_interior_of_drop(
&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 @@ pub(crate) fn cannot_act_on_moved_value(
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'tcx> {
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
struct_span_err!(
@@ -342,7 +338,7 @@ pub(crate) fn cannot_borrow_path_as_mutable_because(
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 @@ pub(crate) fn cannot_mutate_in_immutable_section(
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 @@ pub(crate) fn cannot_borrow_across_coroutine_yield(
&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 @@ pub(crate) fn cannot_borrow_across_coroutine_yield(
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 @@ pub(crate) fn path_does_not_live_long_enough(
&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 @@ pub(crate) fn cannot_return_reference_to_local(
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 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
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 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
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 @@ pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
sp: S,
msg: impl Into<DiagnosticMessage>,
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,
@@ -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 @@ fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tc
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 @@ fn nice_error(
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
) -> Option<DiagnosticBuilder<'tcx>>;
#[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 @@ fn nice_error(
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
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<TyCtxt<'tcx>> + '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 @@ fn nice_error(
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
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 @@ fn nice_error(
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
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 @@ fn nice_error(
}
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 @@ fn nice_error(
_cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
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<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
// 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,14 +387,19 @@ 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<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
let placeholder_universe = match placeholder_region.kind() {
ty::RePlaceholder(p) => p.universe,
ty::ReVar(vid) => universe_of_region(vid),
_ => ty::UniverseIndex::ROOT,
};
let matches =
|a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
_ => a_region == b_region,
};
let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
match *constraint {
let mut check =
|constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
Constraint::RegSubReg(sub, sup)
if ((exact && sup == placeholder_region)
|| (!exact && matches(sup, placeholder_region)))
@@ -422,16 +407,16 @@ fn try_extract_error_from_region_constraints<'tcx>(
{
Some((sub, cause.clone()))
}
// FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup)
if ((exact && sup == placeholder_region)
|| (!exact && matches(sup, placeholder_region))) =>
if (exact
&& sup == placeholder_region
&& !universe_of_region(vid).can_name(placeholder_universe))
|| (!exact && matches(sup, placeholder_region)) =>
{
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
}
_ => None,
}
};
};
let mut info = region_constraints
.constraints
.iter()
@@ -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 @@ fn suggest_ref_or_clone(
&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 @@ fn report_use_of_uninitialized(
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 @@ pub(crate) fn report_use_while_mutably_borrowed(
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 @@ pub(crate) fn report_conflicting_borrow(
(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 @@ fn report_local_value_does_not_live_long_enough(
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 @@ fn report_thread_local_value_does_not_live_long_enough(
&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 @@ fn report_temporary_value_does_not_live_long_enough(
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 @@ fn try_report_cannot_return_reference_to_local(
return_span: Span,
category: ConstraintCategory<'tcx>,
opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'cx>> {
let return_kind = match category {
ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield",
@@ -2490,7 +2488,7 @@ fn report_escaping_closure_capture(
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 @@ fn report_escaping_closure_capture(
};
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 @@ fn report_escaping_closure_capture(
}
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 @@ fn report_escaping_data(
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());
@@ -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 @@ fn report_cannot_move_from_static(
&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 @@ fn report_cannot_move_from_borrowed_content(
deref_target_place: Place<'tcx>,
span: Span,
use_spans: Option<UseSpans<'tcx>>,
) -> 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.
@@ -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 @@ fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
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 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &st
}
}
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 @@ fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed
}
}
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) =
@@ -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 @@ fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
// 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 @@ fn report_fnmut_error(
&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 @@ fn report_fnmut_error(
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 @@ fn report_escaping_data_error(
/// | ^^^^^^^^^^^^^^ 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 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
..
}) => {
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());
}
}
@@ -684,39 +684,46 @@ fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Opti
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 => {
+8 -13
View File
@@ -2407,8 +2407,8 @@ pub struct BorrowckErrors<'tcx> {
/// 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<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
@@ -2426,7 +2426,7 @@ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
}
}
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 @@ pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
}
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 @@ pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
pub fn buffer_move_error(
&mut self,
move_out_indices: Vec<MoveOutIndex>,
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 @@ pub fn buffer_move_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 @@ pub fn has_buffered_errors(&self) -> bool {
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)
}
}
@@ -303,7 +303,7 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
| ExprKind::Continue(_)
| ExprKind::Err
| ExprKind::Field(_, _)
| ExprKind::ForLoop(_, _, _, _)
| ExprKind::ForLoop { .. }
| ExprKind::FormatArgs(_)
| ExprKind::IncludedBytes(..)
| ExprKind::InlineAsm(_)
+12 -8
View File
@@ -1,6 +1,6 @@
use rustc_errors::{
AddToDiagnostic, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
SingleLabelManySpans,
AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level,
MultiSpan, SingleLabelManySpans,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol};
@@ -446,14 +446,14 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
}
// Hand-written implementation to support custom user messages.
impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
#[track_caller]
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
#[expect(
rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages"
)]
let mut diag = dcx.struct_err(self.msg_from_user.to_string());
let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
diag.set_span(self.span);
diag
}
@@ -801,9 +801,13 @@ pub(crate) struct AsmClobberNoReg {
pub(crate) clobbers: Vec<Span>,
}
impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = dcx.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = DiagnosticBuilder::new(
dcx,
level,
crate::fluent_generated::builtin_macros_asm_clobber_no_reg,
);
diag.set_span(self.spans.clone());
// eager translation as `span_labels` takes `AsRef<str>`
let lbl1 = dcx.eagerly_translate_to_string(
+2 -5
View File
@@ -8,9 +8,7 @@
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<DiagnosticBuilder<'a, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'a>> {
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.
+6 -7
View File
@@ -5,7 +5,7 @@
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,
+26 -26
View File
@@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76eb38f2af690b5a4411d9a8782b6d77dabff3ca939e0518453ab9f9a4392d41"
checksum = "7c22542c0b95bd3302f7ed6839869c561f2324bac2fd5e7e99f5cfa65fdc8b92"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39526c036b92912417e8931f52c1e235796688068d3efdbbd8b164f299d19156"
checksum = "6b3db903ef2e9c8a4de2ea6db5db052c7857282952f9df604aa55d169e6000d8"
dependencies = [
"bumpalo",
"cranelift-bforest",
@@ -75,39 +75,39 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb0deedc9fccf2db53a5a3c9c9d0163e44143b0d004dca9bf6ab6a0024cd79a"
checksum = "6590feb5a1d6438f974bf6a5ac4dddf69fca14e1f07f3265d880f69e61a94463"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea2d1b274e45aa8e61e9103efa1ba82d4b5a19d12bd1fd10744c3b7380ba3ff"
checksum = "7239038c56fafe77fddc8788fc8533dd6c474dc5bdc5637216404f41ba807330"
[[package]]
name = "cranelift-control"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea5977559a71e63db79a263f0e81a89b996e8a38212c4281e37dd1dbaa8b65c"
checksum = "f7dc9c595341404d381d27a3d950160856b35b402275f0c3990cd1ad683c8053"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f871ada808b58158d84dfc43a6a2e2d2756baaf4ed1c51fd969ca8330e6ca5c"
checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7"
[[package]]
name = "cranelift-frontend"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8e6890f587ef59824b3debe577e68fdf9b307b3808c54b8d93a18fd0b70941b"
checksum = "a612c94d09e653662ec37681dc2d6fd2b9856e6df7147be0afc9aabb0abf19df"
dependencies = [
"cranelift-codegen",
"log",
@@ -117,15 +117,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d5fc6d5d3b52d1917002b17a8ecce448c2621b5bf394bb4e77e2f676893537"
checksum = "85db9830abeb1170b7d29b536ffd55af1d4d26ac8a77570b5d1aca003bf225cc"
[[package]]
name = "cranelift-jit"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a2d7744f743f59d9646d7589ad22ea17ed0d71e04906eb77c31e99bc13bd8b"
checksum = "4946271f1055e26544ef8c90fa24776f201566419dfac4b3962c39d5a804ff67"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -143,9 +143,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96cb196334698e612c197d7d0ae59af5e07667306ec20d7be414717db400873"
checksum = "cb7e3bdae2597556e59edeb8ecb62eb32c7e054c4f042d393732902979db69c3"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -154,9 +154,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e10c2e7faa65d4ae7de9a83b44f2c31aca7dc638e17d0a79572fdf8103d720b"
checksum = "301ef0edafeaeda5771a5d2db64ac53e1818ae3111220a185677025fe91db4a1"
dependencies = [
"cranelift-codegen",
"libc",
@@ -165,9 +165,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.102.0"
version = "0.103.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83ce94e18756058af8a66e3c0ba1123ae15517c72162d8060d0cb0974642adf2"
checksum = "59e0ee3d013728903e0c513c31afa389b559bfd4fe8a44f80335c799e3132a41"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "15.0.0"
version = "16.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b73ad1395eda136baec5ece7e079e0536a82ef73488e345456cc9b89858ad0ec"
checksum = "6b6d197fcc34ad32ed440e1f9552fd57d1f377d9699d31dee1b5b457322c1f8a"
dependencies = [
"cfg-if",
"libc",
+6 -6
View File
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.102", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.102" }
cranelift-module = { version = "0.102" }
cranelift-native = { version = "0.102" }
cranelift-jit = { version = "0.102", optional = true }
cranelift-object = { version = "0.102" }
cranelift-codegen = { version = "0.103", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.103" }
cranelift-module = { version = "0.103" }
cranelift-native = { version = "0.103" }
cranelift-jit = { version = "0.103", optional = true }
cranelift-object = { version = "0.103" }
target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
@@ -538,261 +538,38 @@ pub enum E1 {
pub enum E2<X> {
V1 { f: bool },
/*_00*/ _01(X),
_02(X),
_03(X),
_04(X),
_05(X),
_06(X),
_07(X),
_08(X),
_09(X),
_0A(X),
_0B(X),
_0C(X),
_0D(X),
_0E(X),
_0F(X),
_10(X),
_11(X),
_12(X),
_13(X),
_14(X),
_15(X),
_16(X),
_17(X),
_18(X),
_19(X),
_1A(X),
_1B(X),
_1C(X),
_1D(X),
_1E(X),
_1F(X),
_20(X),
_21(X),
_22(X),
_23(X),
_24(X),
_25(X),
_26(X),
_27(X),
_28(X),
_29(X),
_2A(X),
_2B(X),
_2C(X),
_2D(X),
_2E(X),
_2F(X),
_30(X),
_31(X),
_32(X),
_33(X),
_34(X),
_35(X),
_36(X),
_37(X),
_38(X),
_39(X),
_3A(X),
_3B(X),
_3C(X),
_3D(X),
_3E(X),
_3F(X),
_40(X),
_41(X),
_42(X),
_43(X),
_44(X),
_45(X),
_46(X),
_47(X),
_48(X),
_49(X),
_4A(X),
_4B(X),
_4C(X),
_4D(X),
_4E(X),
_4F(X),
_50(X),
_51(X),
_52(X),
_53(X),
_54(X),
_55(X),
_56(X),
_57(X),
_58(X),
_59(X),
_5A(X),
_5B(X),
_5C(X),
_5D(X),
_5E(X),
_5F(X),
_60(X),
_61(X),
_62(X),
_63(X),
_64(X),
_65(X),
_66(X),
_67(X),
_68(X),
_69(X),
_6A(X),
_6B(X),
_6C(X),
_6D(X),
_6E(X),
_6F(X),
_70(X),
_71(X),
_72(X),
_73(X),
_74(X),
_75(X),
_76(X),
_77(X),
_78(X),
_79(X),
_7A(X),
_7B(X),
_7C(X),
_7D(X),
_7E(X),
_7F(X),
_80(X),
_81(X),
_82(X),
_83(X),
_84(X),
_85(X),
_86(X),
_87(X),
_88(X),
_89(X),
_8A(X),
_8B(X),
_8C(X),
_8D(X),
_8E(X),
_8F(X),
_90(X),
_91(X),
_92(X),
_93(X),
_94(X),
_95(X),
_96(X),
_97(X),
_98(X),
_99(X),
_9A(X),
_9B(X),
_9C(X),
_9D(X),
_9E(X),
_9F(X),
_A0(X),
_A1(X),
_A2(X),
_A3(X),
_A4(X),
_A5(X),
_A6(X),
_A7(X),
_A8(X),
_A9(X),
_AA(X),
_AB(X),
_AC(X),
_AD(X),
_AE(X),
_AF(X),
_B0(X),
_B1(X),
_B2(X),
_B3(X),
_B4(X),
_B5(X),
_B6(X),
_B7(X),
_B8(X),
_B9(X),
_BA(X),
_BB(X),
_BC(X),
_BD(X),
_BE(X),
_BF(X),
_C0(X),
_C1(X),
_C2(X),
_C3(X),
_C4(X),
_C5(X),
_C6(X),
_C7(X),
_C8(X),
_C9(X),
_CA(X),
_CB(X),
_CC(X),
_CD(X),
_CE(X),
_CF(X),
_D0(X),
_D1(X),
_D2(X),
_D3(X),
_D4(X),
_D5(X),
_D6(X),
_D7(X),
_D8(X),
_D9(X),
_DA(X),
_DB(X),
_DC(X),
_DD(X),
_DE(X),
_DF(X),
_E0(X),
_E1(X),
_E2(X),
_E3(X),
_E4(X),
_E5(X),
_E6(X),
_E7(X),
_E8(X),
_E9(X),
_EA(X),
_EB(X),
_EC(X),
_ED(X),
_EE(X),
_EF(X),
_F0(X),
_F1(X),
_F2(X),
_F3(X),
_F4(X),
_F5(X),
_F6(X),
_F7(X),
_F8(X),
_F9(X),
_FA(X),
_FB(X),
_FC(X),
_FD(X),
_FE(X),
_FF(X),
/*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
_08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
_10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
_18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
_20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
_28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
_30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
_38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
_40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
_48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
_50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
_58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
_60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
_68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
_70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
_78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
_80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
_88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
_90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
_98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
_A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
_A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
_B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
_B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
_C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
_C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
_D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
_D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
_E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
_E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
_F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
_F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
V3,
V4,
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-12-19"
channel = "nightly-2023-12-24"
components = ["rust-src", "rustc-dev", "llvm-tools"]
@@ -31,6 +31,7 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
# FIXME add needs-unwind to these tests
rm -r tests/run-make/libtest-junit
rm tests/ui/asm/may_unwind.rs
rm tests/ui/stable-mir-print/basic_function.rs
# extra warning about -Cpanic=abort for proc macros
rm tests/ui/proc-macro/crt-static.rs
@@ -44,7 +45,6 @@ rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
# vendor intrinsics
rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
rm tests/ui/simd/masked-load-store.rs
# exotic linkages
rm tests/ui/issues/issue-33992.rs # unsupported linkages
@@ -80,6 +80,7 @@ rm -r tests/run-make/codegen-options-parsing
rm -r tests/run-make/lto-*
rm -r tests/run-make/reproducible-build-2
rm -r tests/run-make/issue-109934-lto-debuginfo
rm -r tests/run-make/no-builtins-lto
# optimization tests
# ==================
+1 -1
View File
@@ -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
));
@@ -962,6 +962,37 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
}
sym::simd_masked_store => {
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(val_lane_count, mask_lane_count);
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
let ptr_val = ptr.load_scalar(fx);
for lane_idx in 0..val_lane_count {
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
let if_enabled = fx.bcx.create_block();
let next = fx.bcx.create_block();
fx.bcx.ins().brif(mask_lane, if_enabled, &[], next, &[]);
fx.bcx.seal_block(if_enabled);
fx.bcx.switch_to_block(if_enabled);
let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32;
fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_val, Offset32::new(offset));
fx.bcx.ins().jump(next, &[]);
fx.bcx.seal_block(next);
fx.bcx.switch_to_block(next);
fx.bcx.ins().nop();
}
}
sym::simd_gather => {
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
@@ -1057,7 +1088,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
sym::simd_scatter => {
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+3 -3
View File
@@ -1,6 +1,6 @@
#![cfg_attr(all(doc, not(bootstrap)), allow(internal_features))]
#![cfg_attr(all(doc, not(bootstrap)), feature(rustdoc_internals))]
#![cfg_attr(all(doc, not(bootstrap)), doc(rust_logo))]
#![cfg_attr(doc, allow(internal_features))]
#![cfg_attr(doc, feature(rustdoc_internals))]
#![cfg_attr(doc, doc(rust_logo))]
#![feature(rustc_private)]
// Note: please avoid adding other feature gates where possible
#![warn(rust_2018_idioms)]
+9 -5
View File
@@ -1,6 +1,6 @@
use rustc_errors::{
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
IntoDiagnosticArg,
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
IntoDiagnosticArg, Level,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@@ -111,9 +111,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
#[help(codegen_gcc_missing_features)]
pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = dcx.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(
dcx,
level,
fluent::codegen_gcc_target_feature_disable_or_enable
);
if let Some(span) = self.span {
diag.set_span(span);
};
+16 -13
View File
@@ -4,9 +4,7 @@
use crate::fluent_generated as fluent;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{
DiagCtxt, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, IntoDiagnostic,
};
use rustc_errors::{DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@@ -101,13 +99,14 @@ pub(crate) struct DlltoolFailImportLibrary<'a> {
pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, FatalError> {
let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(dcx);
let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
impl<G: EmissionGuarantee> 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.messages().first().expect("`LlvmError` with no message");
let message = dcx.eagerly_translate_to_string(message.clone(), diag.args());
let mut diag = dcx.struct_almost_fatal(fluent::codegen_llvm_parse_target_machine_config);
let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config);
diag.set_arg("error", message);
diag
}
@@ -123,9 +122,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
#[help(codegen_llvm_missing_features)]
pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = dcx.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(
dcx,
level,
fluent::codegen_llvm_target_feature_disable_or_enable,
);
if let Some(span) = self.span {
diag.set_span(span);
};
@@ -184,7 +187,7 @@ pub enum LlvmError<'a> {
pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, G> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
use LlvmError::*;
let msg_with_llvm_err = match &self.0 {
WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
@@ -201,7 +204,7 @@ fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, G> {
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
};
let mut diag = self.0.into_diagnostic(dcx);
let mut diag = self.0.into_diagnostic(dcx, level);
diag.set_primary_message(msg_with_llvm_err);
diag.set_arg("llvm_err", self.1);
diag
-1
View File
@@ -8,7 +8,6 @@
#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![cfg_attr(bootstrap, feature(c_str_literals))]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(hash_raw_entry)]
+11 -11
View File
@@ -15,7 +15,7 @@
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(crate) enum Message<B: WriteBackendMethods> {
type DiagnosticArgName<'source> = Cow<'source, str>;
struct Diagnostic {
msg: Vec<(DiagnosticMessage, Style)>,
msgs: Vec<(DiagnosticMessage, Style)>,
args: FxHashMap<DiagnosticArgName<'static>, rustc_errors::DiagnosticArgValue<'static>>,
code: Option<DiagnosticId>,
lvl: Level,
@@ -1799,14 +1799,14 @@ fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
let args: FxHashMap<Cow<'_, str>, 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 @@ pub fn check(&self, sess: &Session, blocking: bool) {
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 @@ pub fn check(&self, sess: &Session, blocking: bool) {
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 {
@@ -15,7 +15,7 @@
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<CoroutineKind>) -> &'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",
}
+48 -47
View File
@@ -4,8 +4,8 @@
use crate::back::command::Command;
use crate::fluent_generated as fluent;
use rustc_errors::{
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
IntoDiagnosticArg,
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
IntoDiagnosticArg, Level,
};
use rustc_macros::Diagnostic;
use rustc_middle::ty::layout::LayoutError;
@@ -209,192 +209,193 @@ pub enum LinkRlibError {
pub struct ThorinErrorWrapper(pub thorin::Error);
impl IntoDiagnostic<'_> for ThorinErrorWrapper {
fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let build = |msg| DiagnosticBuilder::new(dcx, level, msg);
let mut diag;
match self.0 {
thorin::Error::ReadInput(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
diag = build(fluent::codegen_ssa_thorin_read_input_failure);
diag
}
thorin::Error::ParseFileKind(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
diag = build(fluent::codegen_ssa_thorin_parse_input_file_kind);
diag
}
thorin::Error::ParseObjectFile(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
diag = build(fluent::codegen_ssa_thorin_parse_input_object_file);
diag
}
thorin::Error::ParseArchiveFile(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
diag = build(fluent::codegen_ssa_thorin_parse_input_archive_file);
diag
}
thorin::Error::ParseArchiveMember(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
diag = build(fluent::codegen_ssa_thorin_parse_archive_member);
diag
}
thorin::Error::InvalidInputKind => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
diag = build(fluent::codegen_ssa_thorin_invalid_input_kind);
diag
}
thorin::Error::DecompressData(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_decompress_data);
diag = build(fluent::codegen_ssa_thorin_decompress_data);
diag
}
thorin::Error::NamelessSection(_, offset) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_without_name);
diag = build(fluent::codegen_ssa_thorin_section_without_name);
diag.set_arg("offset", format!("0x{offset:08x}"));
diag
}
thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
diag.set_arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}"));
diag
}
thorin::Error::MultipleRelocations(section, offset) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
diag = build(fluent::codegen_ssa_thorin_multiple_relocations);
diag.set_arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}"));
diag
}
thorin::Error::UnsupportedRelocation(section, offset) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
diag = build(fluent::codegen_ssa_thorin_unsupported_relocation);
diag.set_arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}"));
diag
}
thorin::Error::MissingDwoName(id) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
diag = build(fluent::codegen_ssa_thorin_missing_dwo_name);
diag.set_arg("id", format!("0x{id:08x}"));
diag
}
thorin::Error::NoCompilationUnits => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
diag = build(fluent::codegen_ssa_thorin_no_compilation_units);
diag
}
thorin::Error::NoDie => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_die);
diag = build(fluent::codegen_ssa_thorin_no_die);
diag
}
thorin::Error::TopLevelDieNotUnit => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
diag = build(fluent::codegen_ssa_thorin_top_level_die_not_unit);
diag
}
thorin::Error::MissingRequiredSection(section) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
diag = build(fluent::codegen_ssa_thorin_missing_required_section);
diag.set_arg("section", section);
diag
}
thorin::Error::ParseUnitAbbreviations(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
diag = build(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
diag
}
thorin::Error::ParseUnitAttribute(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
diag = build(fluent::codegen_ssa_thorin_parse_unit_attribute);
diag
}
thorin::Error::ParseUnitHeader(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
diag = build(fluent::codegen_ssa_thorin_parse_unit_header);
diag
}
thorin::Error::ParseUnit(_) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit);
diag = build(fluent::codegen_ssa_thorin_parse_unit);
diag
}
thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
diag = build(fluent::codegen_ssa_thorin_incompatible_index_version);
diag.set_arg("section", section);
diag.set_arg("actual", actual);
diag.set_arg("format", format);
diag
}
thorin::Error::OffsetAtIndex(_, index) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
diag = build(fluent::codegen_ssa_thorin_offset_at_index);
diag.set_arg("index", index);
diag
}
thorin::Error::StrAtOffset(_, offset) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
diag = build(fluent::codegen_ssa_thorin_str_at_offset);
diag.set_arg("offset", format!("0x{offset:08x}"));
diag
}
thorin::Error::ParseIndex(_, section) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_index);
diag = build(fluent::codegen_ssa_thorin_parse_index);
diag.set_arg("section", section);
diag
}
thorin::Error::UnitNotInIndex(unit) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
diag = build(fluent::codegen_ssa_thorin_unit_not_in_index);
diag.set_arg("unit", format!("0x{unit:08x}"));
diag
}
thorin::Error::RowNotInIndex(_, row) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
diag = build(fluent::codegen_ssa_thorin_row_not_in_index);
diag.set_arg("row", row);
diag
}
thorin::Error::SectionNotInRow => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
diag = build(fluent::codegen_ssa_thorin_section_not_in_row);
diag
}
thorin::Error::EmptyUnit(unit) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_empty_unit);
diag = build(fluent::codegen_ssa_thorin_empty_unit);
diag.set_arg("unit", format!("0x{unit:08x}"));
diag
}
thorin::Error::MultipleDebugInfoSection => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
diag = build(fluent::codegen_ssa_thorin_multiple_debug_info_section);
diag
}
thorin::Error::MultipleDebugTypesSection => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
diag = build(fluent::codegen_ssa_thorin_multiple_debug_types_section);
diag
}
thorin::Error::NotSplitUnit => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
diag = build(fluent::codegen_ssa_thorin_not_split_unit);
diag
}
thorin::Error::DuplicateUnit(unit) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
diag = build(fluent::codegen_ssa_thorin_duplicate_unit);
diag.set_arg("unit", format!("0x{unit:08x}"));
diag
}
thorin::Error::MissingReferencedUnit(unit) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit);
diag.set_arg("unit", format!("0x{unit:08x}"));
diag
}
thorin::Error::NoOutputObjectCreated => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
diag = build(fluent::codegen_ssa_thorin_not_output_object_created);
diag
}
thorin::Error::MixedInputEncodings => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
diag = build(fluent::codegen_ssa_thorin_mixed_input_encodings);
diag
}
thorin::Error::Io(e) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_io);
diag = build(fluent::codegen_ssa_thorin_io);
diag.set_arg("error", format!("{e}"));
diag
}
thorin::Error::ObjectRead(e) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_read);
diag = build(fluent::codegen_ssa_thorin_object_read);
diag.set_arg("error", format!("{e}"));
diag
}
thorin::Error::ObjectWrite(e) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_write);
diag = build(fluent::codegen_ssa_thorin_object_write);
diag.set_arg("error", format!("{e}"));
diag
}
thorin::Error::GimliRead(e) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_read);
diag = build(fluent::codegen_ssa_thorin_gimli_read);
diag.set_arg("error", format!("{e}"));
diag
}
thorin::Error::GimliWrite(e) => {
diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_write);
diag = build(fluent::codegen_ssa_thorin_gimli_write);
diag.set_arg("error", format!("{e}"));
diag
}
@@ -410,9 +411,9 @@ pub struct LinkingFailed<'a> {
pub escaped_output: String,
}
impl IntoDiagnostic<'_> for LinkingFailed<'_> {
fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = dcx.struct_err(fluent::codegen_ssa_linking_failed);
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> {
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_ssa_linking_failed);
diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
diag.set_arg("exit_status", format!("{}", self.exit_status));
@@ -6,7 +6,7 @@
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<FrameNote>),
F: FnOnce(Span, Vec<FrameNote>) -> E,
E: IntoDiagnostic<'tcx, ErrorGuaranteed>,
E: IntoDiagnostic<'tcx>,
{
// Special handling for certain errors
match error {
+5 -2
View File
@@ -1,6 +1,6 @@
use rustc_errors::{
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee,
IntoDiagnostic,
IntoDiagnostic, Level,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -875,7 +875,10 @@ fn add_args<G: EmissionGuarantee>(
| InvalidProgramInfo::AlreadyReported(_)
| InvalidProgramInfo::ConstPropNonsense => {}
InvalidProgramInfo::Layout(e) => {
let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(dcx);
// The level doesn't matter, `diag` is consumed without it being used.
let dummy_level = Level::Bug;
let diag: DiagnosticBuilder<'_, ()> =
e.into_diagnostic().into_diagnostic(dcx, dummy_level);
for (name, val) in diag.args() {
builder.set_arg(name.clone(), val.clone());
}
@@ -165,6 +165,8 @@ pub fn global_base_pointer(
// We need to handle `extern static`.
match self.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
// Thread-local statics do not have a constant address. They *must* be accessed via
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
bug!("global memory cannot point to thread-local static")
}
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => {
@@ -539,6 +541,8 @@ fn get_global_alloc(
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
// Thread-local statics do not have a constant address. They *must* be accessed via
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
assert!(!self.tcx.is_thread_local_static(def_id));
// Notice that every static has two `AllocId` that will resolve to the same
// thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID,
@@ -740,6 +744,8 @@ pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
match self.tcx.try_get_global_alloc(id) {
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
// Thread-local statics do not have a constant address. They *must* be accessed via
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
assert!(!self.tcx.is_thread_local_static(def_id));
// Use size and align of the type.
let ty = self
@@ -5,17 +5,15 @@
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{TraitRef, TypeVisitableExt};
use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt};
use rustc_mir_dataflow::Analysis;
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
use std::mem;
@@ -464,8 +462,12 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
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));
}
@@ -752,143 +754,43 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
infcx.err_ctxt().report_fulfillment_errors(errors);
}
let mut is_trait = false;
// Attempting to call a trait method?
// FIXME(effects) do we need this?
if let Some(trait_id) = tcx.trait_of_item(callee) {
if tcx.trait_of_item(callee).is_some() {
trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
// trait method calls are only permitted when `effects` is enabled.
// we don't error, since that is handled by typeck. We try to resolve
// the trait into the concrete method, and uses that for const stability
// checks.
// FIXME(effects) we might consider moving const stability checks to typeck as well.
if tcx.features().effects {
is_trait = true;
if let Ok(Some(instance)) =
Instance::resolve(tcx, param_env, callee, fn_args)
&& let InstanceDef::Item(def) = instance.def
{
// Resolve a trait method call to its concrete implementation, which may be in a
// `const` trait impl. This is only used for the const stability check below, since
// we want to look at the concrete impl's stability.
fn_args = instance.args;
callee = def;
}
} else {
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: Some(sym::const_trait_impl),
feature: Some(if tcx.features().const_trait_impl {
sym::effects
} else {
sym::const_trait_impl
}),
});
return;
}
let trait_ref = TraitRef::from_method(tcx, trait_id, fn_args);
let obligation =
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
let implsrc = {
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
};
match implsrc {
Ok(Some(ImplSource::Param(_))) if tcx.features().effects => {
debug!(
"const_trait_impl: provided {:?} via where-clause in {:?}",
trait_ref, param_env
);
return;
}
// Closure: Fn{Once|Mut}
Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _)))
if trait_ref.self_ty().is_closure()
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
{
let ty::Closure(closure_def_id, fn_args) = *trait_ref.self_ty().kind()
else {
unreachable!()
};
if !tcx.is_const_fn_raw(closure_def_id) {
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: None,
});
return;
}
}
Ok(Some(ImplSource::UserDefined(data))) => {
let callee_name = tcx.item_name(callee);
if let hir::Constness::NotConst = tcx.constness(data.impl_def_id) {
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: None,
});
return;
}
if let Some(&did) = tcx
.associated_item_def_ids(data.impl_def_id)
.iter()
.find(|did| tcx.item_name(**did) == callee_name)
{
// using internal args is ok here, since this is only
// used for the `resolve` call below
fn_args = GenericArgs::identity_for_item(tcx, did);
callee = did;
}
}
_ if !tcx.is_const_fn_raw(callee) => {
// At this point, it is only legal when the caller is in a trait
// marked with #[const_trait], and the callee is in the same trait.
let mut nonconst_call_permission = false;
if let Some(callee_trait) = tcx.trait_of_item(callee)
&& tcx.has_attr(callee_trait, sym::const_trait)
&& Some(callee_trait) == tcx.trait_of_item(caller.to_def_id())
// Can only call methods when it's `<Self as TheTrait>::f`.
&& tcx.types.self_param == fn_args.type_at(0)
{
nonconst_call_permission = true;
}
if !nonconst_call_permission {
let obligation = Obligation::new(
tcx,
ObligationCause::dummy_with_span(*fn_span),
param_env,
trait_ref,
);
// improve diagnostics by showing what failed. Our requirements are stricter this time
// as we are going to error again anyways.
let infcx = tcx.infer_ctxt().build();
if let Err(e) = implsrc {
infcx.err_ctxt().report_selection_error(
obligation.clone(),
&obligation,
&e,
);
}
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: None,
});
return;
}
}
_ => {}
}
// Resolve a trait method call to its concrete implementation, which may be in a
// `const` trait impl.
let instance = Instance::resolve(tcx, param_env, callee, fn_args);
debug!("Resolving ({:?}) -> {:?}", callee, instance);
if let Ok(Some(func)) = instance {
if let InstanceDef::Item(def) = func.def {
callee = def;
}
}
}
// At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -921,21 +823,16 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
return;
}
if !tcx.is_const_fn_raw(callee) {
if !tcx.is_const_default_method(callee) {
// To get to here we must have already found a const impl for the
// trait, but for it to still be non-const can be that the impl is
// using default method bodies.
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: None,
});
return;
}
if !tcx.is_const_fn_raw(callee) && !is_trait {
self.check_op(ops::FnCallNonConst {
caller,
callee,
args: fn_args,
span: *fn_span,
call_source: *call_source,
feature: None,
});
return;
}
// If the `const fn` we are trying to call is not const-stable, ensure that we have
@@ -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 @@ fn importance(&self) -> DiagnosticImportance {
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 @@ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
}
}
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 @@ fn build_error(
#[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 @@ macro_rules! error {
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
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 @@ fn build_error(
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 @@ fn build_error(
#[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 @@ fn build_error(
#[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 @@ fn importance(&self) -> DiagnosticImportance {
// 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 @@ fn build_error(
/// 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 @@ fn importance(&self) -> DiagnosticImportance {
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 @@ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
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 @@ fn importance(&self) -> DiagnosticImportance {
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 @@ fn build_error(
#[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 @@ fn build_error(
#[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 @@ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
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 @@ fn build_error(
#[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 @@ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
}
}
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 @@ fn build_error(
#[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 @@ fn importance(&self) -> DiagnosticImportance {
}
}
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,
@@ -8,9 +8,6 @@
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 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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<BasicBlock>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
place_cache: FxHashSet<PlaceRef<'tcx>>,
value_cache: FxHashSet<u128>,
// If `false`, then the MIR must not contain `UnwindAction::Continue` or
@@ -294,28 +283,13 @@ fn is_critical_call_edge(&self, target: Option<BasicBlock>, unwind: UnwindAction
}
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 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
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
@@ -81,150 +81,6 @@
/// E::A,
/// }
/// ```
#[cfg(bootstrap)]
#[macro_export]
macro_rules! impl_tag {
(
impl Tag for $Self:ty;
$(
$($path:ident)::* $( { $( $fields:tt )* })?,
)*
) => {
// Safety:
// `bits_for_tags` is called on the same `${index()}`-es as
// `into_usize` returns, thus `BITS` constant is correct.
unsafe impl $crate::tagged_ptr::Tag for $Self {
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
$(
${index()},
$( ${ignore(path)} )*
)*
]);
#[inline]
fn into_usize(self) -> usize {
// This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
// (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
#[forbid(unreachable_patterns)]
match self {
// `match` is doing heavy lifting here, by requiring exhaustiveness
$(
$($path)::* $( { $( $fields )* } )? => ${index()},
)*
}
}
#[inline]
unsafe fn from_usize(tag: usize) -> Self {
match tag {
$(
${index()} => $($path)::* $( { $( $fields )* } )?,
)*
// Safety:
// `into_usize` only returns `${index()}` of the same
// repetition as we are filtering above, thus if this is
// reached, the safety contract of this function was
// already breached.
_ => unsafe {
debug_assert!(
false,
"invalid tag: {tag}\
(this is a bug in the caller of `from_usize`)"
);
std::hint::unreachable_unchecked()
},
}
}
}
};
}
/// Implements [`Tag`] for a given type.
///
/// You can use `impl_tag` on structs and enums.
/// You need to specify the type and all its possible values,
/// which can only be paths with optional fields.
///
/// [`Tag`]: crate::tagged_ptr::Tag
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
///
/// #[derive(Copy, Clone, PartialEq, Debug)]
/// enum SomeTag {
/// A,
/// B,
/// X { v: bool },
/// Y(bool, bool),
/// }
///
/// impl_tag! {
/// // The type for which the `Tag` will be implemented
/// impl Tag for SomeTag;
/// // You need to specify all possible tag values:
/// SomeTag::A, // 0
/// SomeTag::B, // 1
/// // For variants with fields, you need to specify the fields:
/// SomeTag::X { v: true }, // 2
/// SomeTag::X { v: false }, // 3
/// // For tuple variants use named syntax:
/// SomeTag::Y { 0: true, 1: true }, // 4
/// SomeTag::Y { 0: false, 1: true }, // 5
/// SomeTag::Y { 0: true, 1: false }, // 6
/// SomeTag::Y { 0: false, 1: false }, // 7
/// }
///
/// // Tag values are assigned in order:
/// assert_eq!(SomeTag::A.into_usize(), 0);
/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
///
/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
/// ```
///
/// Structs are supported:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// struct Flags { a: bool, b: bool }
///
/// impl_tag! {
/// impl Tag for Flags;
/// Flags { a: true, b: true },
/// Flags { a: false, b: true },
/// Flags { a: true, b: false },
/// Flags { a: false, b: false },
/// }
/// ```
///
/// Not specifying all values results in a compile error:
///
/// ```compile_fail,E0004
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// enum E {
/// A,
/// B,
/// }
///
/// impl_tag! {
/// impl Tag for E;
/// E::A,
/// }
/// ```
#[cfg(not(bootstrap))]
#[macro_export]
macro_rules! impl_tag {
(
+1 -1
View File
@@ -28,7 +28,7 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<Stri
for arg in at_args {
match arg_expand(arg.clone()) {
Ok(arg) => 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
+11 -12
View File
@@ -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<geto
.map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
_ => 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::<Vec<_>>();
@@ -1 +1,2 @@
#### This error code is internal to the compiler and will not be emitted with normal Rust code.
#### Note: this error code is no longer emitted by the compiler.
@@ -60,7 +60,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
self.emit_messages_default(
&diag.level,
&diag.message,
&diag.messages,
&fluent_args,
&diag.code,
&primary_span,
+25 -54
View File
@@ -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<DiagnosticId>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
@@ -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<MultiSpan>,
}
#[derive(Debug, PartialEq, Eq)]
@@ -216,14 +215,14 @@ pub fn content(&self) -> &str {
impl Diagnostic {
#[track_caller]
pub fn new<M: Into<DiagnosticMessage>>(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 @@ pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>
}
}
#[track_caller]
pub(crate) fn new_with_code<M: Into<DiagnosticMessage>>(
level: Level,
code: Option<DiagnosticId>,
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 @@ pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut
/// Add a note attached to this diagnostic.
#[rustc_lint_diagnostics]
pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new(), None);
self.sub(Level::Note, msg, MultiSpan::new());
self
}
@@ -453,14 +432,14 @@ fn highlighted_note<M: Into<SubdiagnosticMessage>>(
&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<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
self.sub(Level::OnceNote, msg, MultiSpan::new());
self
}
@@ -472,7 +451,7 @@ pub fn span_note<S: Into<MultiSpan>>(
sp: S,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Note, msg, sp.into(), None);
self.sub(Level::Note, msg, sp.into());
self
}
@@ -483,14 +462,14 @@ pub fn span_note_once<S: Into<MultiSpan>>(
sp: S,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::Warning(None), msg, MultiSpan::new(), None);
self.sub(Level::Warning(None), msg, MultiSpan::new());
self
}
@@ -502,27 +481,27 @@ pub fn span_warn<S: Into<MultiSpan>>(
sp: S,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<SubdiagnosticMessage>) -> &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<SubdiagnosticMessage>) -> &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 @@ pub fn span_help<S: Into<MultiSpan>>(
sp: S,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Help, msg, sp.into(), None);
self.sub(Level::Help, msg, sp.into());
self
}
@@ -925,7 +904,7 @@ pub fn get_code(&self) -> Option<DiagnosticId> {
}
pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.message[0] = (msg.into(), Style::NoStyle);
self.messages[0] = (msg.into(), Style::NoStyle);
self
}
@@ -952,8 +931,8 @@ pub fn replace_args(
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 @@ fn subdiagnostic_message_to_diagnostic_message(
attr: impl Into<SubdiagnosticMessage>,
) -> 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 @@ fn subdiagnostic_message_to_diagnostic_message(
/// public methods above.
///
/// Used by `proc_macro_server` for implementing `server::Diagnostic`.
pub fn sub(
&mut self,
level: Level,
message: impl Into<SubdiagnosticMessage>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
pub fn sub(&mut self, level: Level, message: impl Into<SubdiagnosticMessage>, 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 @@ pub fn sub(
fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
&mut self,
level: Level,
message: Vec<(M, Style)>,
messages: Vec<(M, Style)>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
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 @@ fn keys(
) {
(
&self.level,
&self.message,
&self.messages,
self.args().collect(),
&self.code,
&self.span,
+77 -191
View File
@@ -15,13 +15,13 @@
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> {
/// Write out as a diagnostic out of `DiagCtxt`.
#[must_use]
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G>;
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>;
}
impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
@@ -29,8 +29,8 @@ impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
T: IntoDiagnostic<'a, G>,
G: EmissionGuarantee,
{
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(dcx);
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(dcx, level);
diag.set_span(self.span);
diag
}
@@ -43,24 +43,7 @@ fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G> {
/// extending `DiagCtxtFlags`.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a, G: EmissionGuarantee> {
inner: DiagnosticBuilderInner<'a>,
_marker: PhantomData<G>,
}
/// This type exists only for `DiagnosticBuilder::forget_guarantee`, because it:
/// 1. lacks the `G` parameter and therefore `DiagnosticBuilder<G1>` can be
/// converted into `DiagnosticBuilder<G2>` 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<Diagnostic>,
_marker: PhantomData<G>,
}
#[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`,
@@ -101,47 +86,50 @@ enum DiagnosticBuilderState<'a> {
/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
/// (or "proof") token that the emission happened.
pub trait EmissionGuarantee: Sized {
/// This exists so that bugs and fatal errors can both result in `!` (an
/// abort) when emitted, but have different aborting behaviour.
type EmitResult = Self;
/// Implementation of `DiagnosticBuilder::emit`, fully controlled by each
/// `impl` of `EmissionGuarantee`, to make it impossible to create a value
/// of `Self` without actually performing the emission.
/// of `Self::EmitResult` without actually performing the emission.
#[track_caller]
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self;
/// Creates a new `DiagnosticBuilder` that will return this type of guarantee.
#[track_caller]
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self>;
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult;
}
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 }
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.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
dcx.emit_diagnostic_without_consuming(&mut self.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
}
}
// FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`.
impl EmissionGuarantee for ErrorGuaranteed {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
// Contrast this with `emit_producing_nothing`.
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<ErrorGuaranteed>`",
db.inner.diagnostic.level,
db.diagnostic.level,
);
guar.unwrap()
}
@@ -153,152 +141,58 @@ fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Se
// 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<ErrorGuaranteed>`'s diagnostic \
became non-error ({:?}), after original `.emit()`",
db.inner.diagnostic.level,
db.diagnostic.level,
);
#[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
}
}
}
#[track_caller]
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Error { lint: false }, msg)
}
}
// FIXME(eddyb) should there be a `Option<ErrorGuaranteed>` impl as well?
impl EmissionGuarantee for () {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
}
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Warning(None), msg)
}
}
/// Marker type which enables implementation of `create_note` and `emit_note` functions for
/// note-without-error struct diagnostics.
#[derive(Copy, Clone)]
pub struct Noted;
impl EmissionGuarantee for Noted {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
Noted
}
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Note, msg)
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
db.emit_producing_nothing();
}
}
/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
/// bug struct diagnostics.
/// bug diagnostics.
#[derive(Copy, Clone)]
pub struct Bug;
pub struct BugAbort;
impl EmissionGuarantee for Bug {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
impl EmissionGuarantee for BugAbort {
type EmitResult = !;
dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
// Then panic. No need to return the marker type.
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
db.emit_producing_nothing();
panic::panic_any(ExplicitBug);
}
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Bug, msg)
}
}
impl EmissionGuarantee for ! {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
/// fatal diagnostics.
#[derive(Copy, Clone)]
pub struct FatalAbort;
dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
// Then fatally error, returning `!`
impl EmissionGuarantee for FatalAbort {
type EmitResult = !;
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
db.emit_producing_nothing();
crate::FatalError.raise()
}
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Fatal, msg)
}
}
impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&DiagCtxt` is still available.
DiagnosticBuilderState::Emittable(dcx) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
// Then fatally error..
fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
db.emit_producing_nothing();
rustc_span::fatal_error::FatalError
}
fn make_diagnostic_builder(
dcx: &DiagCtxt,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new(dcx, Level::Fatal, msg)
}
}
/// In general, the `DiagnosticBuilder` uses deref to allow access to
@@ -318,7 +212,7 @@ pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self
$(#[$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
}
};
@@ -328,27 +222,21 @@ impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> {
type Target = Diagnostic;
fn deref(&self) -> &Diagnostic {
&self.inner.diagnostic
&self.diagnostic
}
}
impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
fn deref_mut(&mut self) -> &mut Diagnostic {
&mut self.inner.diagnostic
&mut self.diagnostic
}
}
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`DiagCtxt`].
#[rustc_lint_diagnostics]
#[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
dcx: &'a DiagCtxt,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new(level, message);
Self::new_diagnostic(dcx, diagnostic)
pub fn new<M: Into<DiagnosticMessage>>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self {
Self::new_diagnostic(dcx, Diagnostic::new(level, message))
}
/// Creates a new `DiagnosticBuilder` with an already constructed
@@ -357,10 +245,8 @@ pub(crate) fn new<M: Into<DiagnosticMessage>>(
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,
}
}
@@ -369,8 +255,8 @@ pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diagnostic: Diagnostic) -> Self
/// but there are various places that rely on continuing to use `self`
/// after calling `emit`.
#[track_caller]
pub fn emit(&mut self) -> G {
G::diagnostic_builder_emit_producing_guarantee(self)
pub fn emit(&mut self) -> G::EmitResult {
G::emit_producing_guarantee(self)
}
/// Emit the diagnostic unless `delay` is true,
@@ -378,7 +264,7 @@ pub fn emit(&mut self) -> G {
///
/// See `emit` and `delay_as_bug` for details.
#[track_caller]
pub fn emit_unless(&mut self, delay: bool) -> G {
pub fn emit_unless(&mut self, delay: bool) -> G::EmitResult {
if delay {
self.downgrade_to_delayed_bug();
}
@@ -392,7 +278,7 @@ pub fn emit_unless(&mut self, delay: bool) -> 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);
}
@@ -400,17 +286,17 @@ pub fn cancel(mut self) {
/// later stage of the compiler. The diagnostic can be accessed with
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
///
/// As with `buffer`, this is unless the handler has disabled such buffering.
/// As with `buffer`, this is unless the dcx has disabled such buffering.
pub fn stash(self, span: Span, key: StashKey) {
if let Some((diag, handler)) = self.into_diagnostic() {
handler.stash_diagnostic(span, key, diag);
if let Some((diag, dcx)) = self.into_diagnostic() {
dcx.stash_diagnostic(span, key, diag);
}
}
/// Converts the builder to a `Diagnostic` for later emission,
/// unless handler has disabled such buffering, or `.emit()` was called.
/// unless dcx has disabled such buffering, or `.emit()` was called.
pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
let dcx = match self.inner.state {
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.
@@ -428,7 +314,7 @@ pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
// 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();
@@ -442,14 +328,14 @@ pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
/// 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,
}
}
/// Buffers the diagnostic for later emission,
/// unless handler has disabled such buffering.
/// unless dcx has disabled such buffering.
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
}
@@ -465,7 +351,7 @@ pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
/// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense.
#[track_caller]
pub fn delay_as_bug(&mut self) -> G {
pub fn delay_as_bug(&mut self) -> G::EmitResult {
self.downgrade_to_delayed_bug();
self.emit()
}
@@ -630,13 +516,13 @@ pub fn span_labels(
impl<G: EmissionGuarantee> 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<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> {
fn drop(&mut self) {
match self.state {
// No `.emit()` or `.cancel()` calls.
+26 -27
View File
@@ -1,10 +1,12 @@
use crate::diagnostic::DiagnosticLocation;
use crate::{fluent_generated as fluent, AddToDiagnostic};
use crate::{DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnostic, IntoDiagnosticArg};
use crate::{
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
IntoDiagnosticArg, Level,
};
use rustc_ast as ast;
use rustc_ast_pretty::pprust;
use rustc_hir as hir;
use rustc_lint_defs::Level;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_span::Span;
@@ -216,7 +218,7 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
}
}
impl IntoDiagnosticArg for Level {
impl IntoDiagnosticArg for rustc_lint_defs::Level {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
}
@@ -245,19 +247,20 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
}
}
impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, !> {
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> {
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag;
match self {
TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
diag = dcx.struct_fatal(fluent::errors_target_invalid_address_space);
diag =
DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space);
diag.set_arg("addr_space", addr_space);
diag.set_arg("cause", cause);
diag.set_arg("err", err);
diag
}
TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
diag = dcx.struct_fatal(fluent::errors_target_invalid_bits);
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits);
diag.set_arg("kind", kind);
diag.set_arg("bit", bit);
diag.set_arg("cause", cause);
@@ -265,31 +268,39 @@ fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, !> {
diag
}
TargetDataLayoutErrors::MissingAlignment { cause } => {
diag = dcx.struct_fatal(fluent::errors_target_missing_alignment);
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment);
diag.set_arg("cause", cause);
diag
}
TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
diag = dcx.struct_fatal(fluent::errors_target_invalid_alignment);
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment);
diag.set_arg("cause", cause);
diag.set_arg("err_kind", err.diag_ident());
diag.set_arg("align", err.align());
diag
}
TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
diag = dcx.struct_fatal(fluent::errors_target_inconsistent_architecture);
diag = DiagnosticBuilder::new(
dcx,
level,
fluent::errors_target_inconsistent_architecture,
);
diag.set_arg("dl", dl);
diag.set_arg("target", target);
diag
}
TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
diag = dcx.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
diag = DiagnosticBuilder::new(
dcx,
level,
fluent::errors_target_inconsistent_pointer_width,
);
diag.set_arg("pointer_size", pointer_size);
diag.set_arg("target", target);
diag
}
TargetDataLayoutErrors::InvalidBitsSize { err } => {
diag = dcx.struct_fatal(fluent::errors_target_invalid_bits_size);
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size);
diag.set_arg("err", err);
diag
}
@@ -301,25 +312,13 @@ fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, !> {
pub struct SingleLabelManySpans {
pub spans: Vec<Span>,
pub label: &'static str,
pub kind: LabelKind,
}
impl AddToDiagnostic for SingleLabelManySpans {
fn add_to_diagnostic_with<F>(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 {
@@ -362,9 +361,9 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
pub struct InvalidFlushedDelayedDiagnosticLevel {
#[primary_span]
pub span: Span,
pub level: rustc_errors::Level,
pub level: Level,
}
impl IntoDiagnosticArg for rustc_errors::Level {
impl IntoDiagnosticArg for Level {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::from(self.to_string()))
}
+18 -19
View File
@@ -350,9 +350,8 @@ fn fix_multispans_in_extern_macros_and_render_macro_backtrace(
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 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
self.emit_messages_default(
&diag.level,
&diag.message,
&diag.messages,
&fluent_args,
&diag.code,
&primary_span,
@@ -1228,10 +1227,10 @@ fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) ->
/// 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 @@ fn style_or_override(style: Style, override_: Option<Style>) -> Style {
// 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 @@ fn style_or_override(style: Style, override_: Option<Style>) -> Style {
// 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::<Vec<_>>();
@@ -1303,10 +1302,10 @@ fn style_or_override(style: Style, override_: Option<Style>) -> Style {
}
#[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<DiagnosticId>,
level: &Level,
@@ -1327,7 +1326,7 @@ fn emit_message_default(
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 @@ fn emit_message_default(
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 @@ fn emit_suggestion_default(
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 @@ fn emit_suggestion_default(
fn emit_messages_default(
&mut self,
level: &Level,
message: &[(DiagnosticMessage, Style)],
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<DiagnosticId>,
span: &MultiSpan,
@@ -2089,9 +2088,9 @@ fn emit_messages_default(
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 @@ fn emit_messages_default(
}
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 @@ fn emit_messages_default(
// 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,
+3 -7
View File
@@ -398,7 +398,7 @@ fn reset(&mut self) -> io::Result<()> {
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 @@ fn from_sub_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,
}
+192 -211
View File
@@ -6,6 +6,7 @@
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![feature(array_windows)]
#![feature(associated_type_defaults)]
#![feature(extract_if)]
#![feature(if_let_guard)]
#![feature(let_chains)]
@@ -26,26 +27,42 @@
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;
@@ -55,9 +72,7 @@
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;
@@ -75,10 +90,7 @@
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<T, PErr<'a>>;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
@@ -162,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,
}
@@ -189,7 +201,7 @@ fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
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<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
@@ -386,8 +398,6 @@ fn push_trailing(
}
}
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;
@@ -396,20 +406,7 @@ fn push_trailing(
/// 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::{DiagnosticBuilder, EmissionGuarantee, Noted};
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 {
@@ -446,7 +443,7 @@ struct DiagCtxtInner {
emitted_diagnostic_codes: FxIndexSet<DiagnosticId>,
/// 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<Hash128>,
@@ -676,7 +673,7 @@ pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
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;
@@ -700,7 +697,7 @@ pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBu
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;
@@ -722,21 +719,6 @@ pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_stashed_diagnostics()
}
/// Construct a builder with the `msg` at the level appropriate for the
/// specific `EmissionGuarantee`.
///
/// Note: this is necessary for `derive(Diagnostic)`, but shouldn't be used
/// outside of that. Instead use `struct_err`, `struct_warn`, etc., which
/// make the diagnostic kind clearer.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_diagnostic<G: EmissionGuarantee>(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, G> {
G::make_diagnostic_builder(self, msg)
}
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
///
/// Attempting to `.emit()` the builder will only emit if either:
@@ -754,37 +736,6 @@ pub fn struct_span_warn(
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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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]
@@ -808,29 +759,14 @@ pub fn struct_span_warn_with_code(
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> 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<DiagnosticMessage>,
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<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Allow, msg)
DiagnosticBuilder::new(self, Allow, msg)
}
/// Construct a builder at the `Expect` level with the `msg`.
@@ -841,7 +777,7 @@ pub fn struct_expect(
msg: impl Into<DiagnosticMessage>,
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`.
@@ -851,7 +787,7 @@ pub fn struct_span_err(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg);
result.set_span(span);
result
@@ -865,7 +801,7 @@ pub fn struct_span_err_with_code(
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_span_err(span, msg);
result.code(code);
result
@@ -875,18 +811,8 @@ pub fn struct_span_err_with_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<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Error { lint: false }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
@@ -896,7 +822,7 @@ pub fn struct_err_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg);
result.code(code);
result
@@ -922,7 +848,7 @@ pub fn struct_span_fatal(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, !> {
) -> DiagnosticBuilder<'_, FatalAbort> {
let mut result = self.struct_fatal(msg);
result.set_span(span);
result
@@ -936,7 +862,7 @@ pub fn struct_span_fatal_with_code(
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, !> {
) -> DiagnosticBuilder<'_, FatalAbort> {
let mut result = self.struct_span_fatal(span, msg);
result.code(code);
result
@@ -945,8 +871,11 @@ pub fn struct_span_fatal_with_code(
/// Construct a builder at the `Fatal` level with the `msg`.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new(self, Level::Fatal, msg)
pub fn struct_fatal(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, FatalAbort> {
DiagnosticBuilder::new(self, Fatal, msg)
}
/// Construct a builder at the `Fatal` level with the `msg`, that doesn't abort.
@@ -956,20 +885,40 @@ pub fn struct_almost_fatal(
&self,
msg: impl Into<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> DiagnosticBuilder<'_, BugAbort> {
DiagnosticBuilder::new(self, Bug, msg)
}
/// Construct a builder at the `Bug` level at the given `span` with the `msg`.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_bug(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, BugAbort> {
let mut result = self.struct_bug(msg);
result.set_span(span);
result
}
#[rustc_lint_diagnostics]
@@ -1028,7 +977,7 @@ pub fn span_warn_with_code(
}
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().span_bug(span, msg)
self.struct_span_bug(span, msg).emit()
}
/// For documentation on this, see `Session::span_delayed_bug`.
@@ -1041,20 +990,14 @@ pub fn span_delayed_bug(
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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
@@ -1062,7 +1005,7 @@ pub fn span_delayed_bug(
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
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);
}
@@ -1070,13 +1013,6 @@ pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
}
#[track_caller]
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
let mut diag = Diagnostic::new(Bug, msg);
diag.set_span(span);
self.emit_diagnostic(diag);
}
#[track_caller]
#[rustc_lint_diagnostics]
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
@@ -1115,9 +1051,9 @@ pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
DiagnosticBuilder::<diagnostic_builder::Bug>::new(self, Bug, msg).emit();
panic::panic_any(ExplicitBug);
self.struct_bug(msg).emit()
}
#[inline]
@@ -1182,10 +1118,9 @@ pub fn print_error_count(&self, registry: &Registry) {
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));
}
@@ -1217,14 +1152,12 @@ pub fn print_error_count(&self, registry: &Registry) {
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]
));
}
@@ -1274,18 +1207,16 @@ pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.create_err(err).emit()
}
pub fn create_err<'a>(
&'a self,
err: impl IntoDiagnostic<'a>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
err.into_diagnostic(self)
#[track_caller]
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)
warning.into_diagnostic(self, Warning(None))
}
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
@@ -1296,7 +1227,7 @@ pub fn create_almost_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, FatalError>,
) -> DiagnosticBuilder<'a, FatalError> {
fatal.into_diagnostic(self)
fatal.into_diagnostic(self, Fatal)
}
pub fn emit_almost_fatal<'a>(
@@ -1308,38 +1239,35 @@ pub fn emit_almost_fatal<'a>(
pub fn create_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, !>,
) -> DiagnosticBuilder<'a, !> {
fatal.into_diagnostic(self)
fatal: impl IntoDiagnostic<'a, FatalAbort>,
) -> DiagnosticBuilder<'a, FatalAbort> {
fatal.into_diagnostic(self, Fatal)
}
pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
self.create_fatal(fatal).emit()
}
pub fn create_bug<'a>(
&'a self,
bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> {
bug.into_diagnostic(self)
bug: impl IntoDiagnostic<'a, BugAbort>,
) -> DiagnosticBuilder<'a, BugAbort> {
bug.into_diagnostic(self, Bug)
}
pub fn emit_bug<'a>(
&'a self,
bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
) -> diagnostic_builder::Bug {
pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! {
self.create_bug(bug).emit()
}
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
self.create_note(note).emit()
}
pub fn create_note<'a>(
&'a self,
note: impl IntoDiagnostic<'a, Noted>,
) -> DiagnosticBuilder<'a, Noted> {
note.into_diagnostic(self)
note: impl IntoDiagnostic<'a, ()>,
) -> DiagnosticBuilder<'a, ()> {
note.into_diagnostic(self, Note)
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
@@ -1426,7 +1354,7 @@ fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
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 @@ fn emit_diagnostic_without_consuming(
&mut self,
diagnostic: &mut Diagnostic,
) -> Option<ErrorGuaranteed> {
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 @@ fn emit_diagnostic_without_consuming(
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 @@ fn emit_diagnostic_without_consuming(
}
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 @@ fn emit_diagnostic_without_consuming(
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 @@ fn emit_diagnostic_without_consuming(
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 @@ fn emit_diagnostic_without_consuming(
}
}
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 @@ fn treat_err_as_bug(&self) -> bool {
})
}
// 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 @@ fn has_errors(&self) -> bool {
self.err_count > 0
}
#[track_caller]
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
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<DiagnosticMessage>) {
self.emit_diagnostic(Diagnostic::new(FailureNote, msg));
}
fn flush_delayed(
&mut self,
bugs: impl IntoIterator<Item = DelayedDiagnostic>,
bugs: Vec<DelayedDiagnostic>,
explanation: impl Into<DiagnosticMessage> + 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 @@ fn flush_delayed(
&mut out,
"delayed span bug: {}\n{}\n",
bug.inner
.styled_message()
.messages()
.iter()
.filter_map(|(msg, _)| msg.as_str())
.collect::<String>(),
&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 @@ fn flush_delayed(
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 @@ fn decorate(mut self) -> Diagnostic {
#[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<LintExpectationId>),
/// 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 @@ pub fn to_str(self) -> &'static str {
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 @@ pub fn is_failure_note(&self) -> bool {
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
match self {
Level::Expect(id) | Level::Warning(Some(id)) => Some(*id),
Expect(id) | Warning(Some(id)) => Some(*id),
_ => None,
}
}
+6 -9
View File
@@ -1118,15 +1118,12 @@ pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> 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)
}
@@ -1159,6 +1156,7 @@ pub fn trace_macros_diag(&mut self) {
// Fixme: does this result in errors?
self.expansions.clear();
}
#[rustc_lint_diagnostics]
pub fn bug(&self, msg: &'static str) -> ! {
self.sess.dcx().bug(msg);
}
@@ -1204,11 +1202,10 @@ pub fn resolve_path(
.expect("attempting to resolve a file path in an external file"),
FileName::DocTest(path, _) => path,
other => {
return Err(errors::ResolveRelativePath {
return Err(parse_sess.dcx.create_err(errors::ResolveRelativePath {
span,
path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
}
.into_diagnostic(&parse_sess.dcx));
}));
}
};
result.pop();
@@ -1230,7 +1227,7 @@ pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
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();
+8 -5
View File
@@ -134,10 +134,13 @@ pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound {
ast::GenericBound::Trait(
self.poly_trait_ref(path.span, path),
if is_const {
ast::TraitBoundModifier::MaybeConst(DUMMY_SP)
} else {
ast::TraitBoundModifier::None
ast::TraitBoundModifiers {
polarity: ast::BoundPolarity::Positive,
constness: if is_const {
ast::BoundConstness::Maybe(DUMMY_SP)
} else {
ast::BoundConstness::Never
},
},
)
}
@@ -488,7 +491,7 @@ pub fn pat_struct(
path: ast::Path,
field_pats: ThinVec<ast::PatField>,
) -> P<ast::Pat> {
self.pat(span, PatKind::Struct(None, path, field_pats, false))
self.pat(span, PatKind::Struct(None, path, field_pats, ast::PatFieldsRest::None))
}
pub fn pat_tuple(&self, span: Span, pats: ThinVec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Tuple(pats))
-126
View File
@@ -41,132 +41,6 @@
use std::rc::Rc;
use std::{iter, mem};
#[cfg(bootstrap)]
macro_rules! ast_fragments {
(
$($Kind:ident($AstTy:ty) {
$kind_name:expr;
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
fn $make_ast:ident;
})*
) => {
/// A fragment of AST that can be produced by a single macro expansion.
/// Can also serve as an input and intermediate result for macro expansion operations.
pub enum AstFragment {
OptExpr(Option<P<ast::Expr>>),
MethodReceiverExpr(P<ast::Expr>),
$($Kind($AstTy),)*
}
/// "Discriminant" of an AST fragment.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum AstFragmentKind {
OptExpr,
MethodReceiverExpr,
$($Kind,)*
}
impl AstFragmentKind {
pub fn name(self) -> &'static str {
match self {
AstFragmentKind::OptExpr => "expression",
AstFragmentKind::MethodReceiverExpr => "expression",
$(AstFragmentKind::$Kind => $kind_name,)*
}
}
fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> {
match self {
AstFragmentKind::OptExpr =>
result.make_expr().map(Some).map(AstFragment::OptExpr),
AstFragmentKind::MethodReceiverExpr =>
result.make_expr().map(AstFragment::MethodReceiverExpr),
$(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
}
}
}
impl AstFragment {
pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
if placeholders.is_empty() {
return;
}
match self {
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
${ignore(flat_map_ast_elt)}
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
})),)?)*
_ => panic!("unexpected AST fragment kind")
}
}
pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
match self {
AstFragment::OptExpr(expr) => expr,
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
}
}
pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
match self {
AstFragment::MethodReceiverExpr(expr) => expr,
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
}
}
$(pub fn $make_ast(self) -> $AstTy {
match self {
AstFragment::$Kind(ast) => ast,
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
}
})*
fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
T::fragment_to_output(self)
}
pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
match self {
AstFragment::OptExpr(opt_expr) => {
visit_clobber(opt_expr, |opt_expr| {
if let Some(expr) = opt_expr {
vis.filter_map_expr(expr)
} else {
None
}
});
}
AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
$($(AstFragment::$Kind(ast) =>
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
}
}
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
match self {
AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
AstFragment::OptExpr(None) => {}
AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
$($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
$($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
visitor.$visit_ast_elt(ast_elt, $($args)*);
})?)*
}
}
}
impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
$(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
-> Option<$AstTy> {
Some(self.make(AstFragmentKind::$Kind).$make_ast())
})*
}
}
}
#[cfg(not(bootstrap))]
macro_rules! ast_fragments {
(
$($Kind:ident($AstTy:ty) {
+4 -4
View File
@@ -215,7 +215,7 @@ fn description() -> &'static str {
}
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 `<eof>`")
{
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 `<eof>`", ""),
+2 -2
View File
@@ -9,8 +9,8 @@
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 \
+1 -1
View File
@@ -43,7 +43,7 @@ pub enum ModError<'a> {
ModInBlock(Option<Ident>),
FileNotFound(Ident, PathBuf, PathBuf),
MultipleCandidates(Ident, PathBuf, PathBuf),
ParserError(DiagnosticBuilder<'a, ErrorGuaranteed>),
ParserError(DiagnosticBuilder<'a>),
}
pub(crate) fn parse_external_mod(
@@ -499,12 +499,7 @@ fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) {
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);
}
+2 -2
View File
@@ -77,7 +77,7 @@ macro_rules! declare_features {
/// Allows empty structs and enum variants with braces.
(accepted, braced_empty_structs, "1.8.0", Some(29720)),
/// Allows `c"foo"` literals.
(accepted, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723)),
(accepted, c_str_literals, "1.76.0", Some(105723)),
/// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
(accepted, cfg_attr_multi, "1.33.0", Some(54881)),
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
@@ -341,7 +341,7 @@ macro_rules! declare_features {
(accepted, track_caller, "1.46.0", Some(47809)),
/// Allows dyn upcasting trait objects via supertraits.
/// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
(accepted, trait_upcasting, "CURRENT_RUSTC_VERSION", Some(65991)),
(accepted, trait_upcasting, "1.76.0", Some(65991)),
/// Allows #[repr(transparent)] on univariant enums (RFC 2645).
(accepted, transparent_enums, "1.42.0", Some(60405)),
/// Allows indexing tuples.
+1 -1
View File
@@ -177,7 +177,7 @@ macro_rules! declare_features {
/// Allows using the `#[register_attr]` attribute.
(removed, register_attr, "1.65.0", Some(66080),
Some("removed in favor of `#![register_tool]`")),
(removed, rust_2018_preview, "CURRENT_RUSTC_VERSION", None,
(removed, rust_2018_preview, "1.76.0", None,
Some("2018 Edition preview is no longer relevant")),
/// Allows using the macros:
/// + `__diagnostic_used`
+6 -4
View File
@@ -204,7 +204,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
(internal, lang_items, "1.0.0", None),
/// Changes `impl Trait` to capture all lifetimes in scope.
(unstable, lifetime_capture_rules_2024, "CURRENT_RUSTC_VERSION", None),
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
(unstable, link_cfg, "1.14.0", None),
/// Allows the `multiple_supertrait_upcastable` lint.
@@ -357,6 +357,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, async_closure, "1.37.0", Some(62290)),
/// Allows `#[track_caller]` on async functions.
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
/// Allows `for await` loops.
(unstable, async_for_loop, "CURRENT_RUSTC_VERSION", Some(118898)),
/// Allows builtin # foo() syntax
(unstable, builtin_syntax, "1.71.0", Some(110680)),
/// Treat `extern "C"` function as nounwind.
@@ -468,7 +470,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
/// Allows using `#[repr(align(...))]` on function items
(unstable, fn_align, "1.53.0", Some(82232)),
/// Support delegating implementation of functions to other already implemented functions.
(incomplete, fn_delegation, "CURRENT_RUSTC_VERSION", Some(118212)),
(incomplete, fn_delegation, "1.76.0", Some(118212)),
/// Allows defining gen blocks and `gen fn`.
(unstable, gen_blocks, "1.75.0", Some(117078)),
/// Infer generic args for both consts and types.
@@ -505,7 +507,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, let_chains, "1.37.0", Some(53667)),
/// Allows using `#[link(kind = "link-arg", name = "...")]`
/// to pass custom arguments to the linker.
(unstable, link_arg_attribute, "CURRENT_RUSTC_VERSION", Some(99427)),
(unstable, link_arg_attribute, "1.76.0", Some(99427)),
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
(unstable, lint_reasons, "1.31.0", Some(54503)),
/// Give access to additional metadata about declarative macro meta-variables.
@@ -527,7 +529,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
/// Allow negative trait implementations.
(unstable, negative_impls, "1.44.0", Some(68318)),
/// Allows the `!` pattern.
(incomplete, never_patterns, "CURRENT_RUSTC_VERSION", Some(118155)),
(incomplete, never_patterns, "1.76.0", Some(118155)),
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
(unstable, never_type, "1.13.0", Some(35121)),
/// Allows diverging expressions to fall back to `!` rather than `()`.
+48 -33
View File
@@ -417,8 +417,7 @@ pub enum GenericArgsParentheses {
ParenSugar,
}
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
/// A modifier on a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum TraitBoundModifier {
None,
@@ -1352,15 +1351,8 @@ pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
/// 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,
@@ -1369,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)
}
}
}
}
@@ -1426,6 +1398,49 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
#[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.
+3
View File
@@ -307,6 +307,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
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;
OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None;
+10 -9
View File
@@ -378,7 +378,7 @@ fn create_args_for_ast_path<'a>(
assert!(self_ty.is_none());
}
let arg_count = check_generic_arg_count(
let mut arg_count = check_generic_arg_count(
tcx,
span,
def_id,
@@ -560,6 +560,14 @@ fn inferred_kind(
inferred_params: vec![],
infer_args,
};
if let ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.has_attr(def_id, sym::const_trait)
{
let e = tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
arg_count.correct =
Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
}
let args = create_args_for_parent_generic_args(
tcx,
def_id,
@@ -570,13 +578,6 @@ fn inferred_kind(
&mut args_ctx,
);
if let ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.has_attr(def_id, sym::const_trait)
{
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
}
(args, arg_count)
}
@@ -2686,7 +2687,7 @@ fn validate_late_bound_regions(
&self,
constrained_regions: FxHashSet<ty::BoundRegionKind>,
referenced_regions: FxHashSet<ty::BoundRegionKind>,
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 {
@@ -124,7 +124,10 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
if let Some(term_did) = tcx.lang_items().termination() {
let return_ty = main_fnsig.output();
let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
let return_ty = return_ty.skip_binder();
let Some(return_ty) = return_ty.no_bound_vars() else {
tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
return;
};
let infcx = tcx.infer_ctxt().build();
let cause = traits::ObligationCause::new(
return_ty_span,
@@ -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
+2 -2
View File
@@ -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<Span>,
kind: &'static str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'tcx> {
let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") };
spans.sort();
+7 -9
View File
@@ -2,8 +2,8 @@
use crate::fluent_generated as fluent;
use rustc_errors::{
error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
MultiSpan,
error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
Level, MultiSpan,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
@@ -315,14 +315,12 @@ pub struct MissingTypeParams {
}
// Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams {
#[track_caller]
fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = dcx.struct_span_err_with_code(
self.span,
fluent::hir_analysis_missing_type_params,
error_code!(E0393),
);
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params);
err.set_span(self.span);
err.code(error_code!(E0393));
err.set_arg("parameterCount", self.missing_type_params.len());
err.set_arg(
"parameters",
@@ -4,7 +4,6 @@
use rustc_middle::query::Providers;
use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
mod explicit;
@@ -49,25 +48,6 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
let predicates =
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
if tcx.has_attr(item_def_id, sym::rustc_outlives) {
let mut pred: Vec<String> = predicates
.iter()
.map(|(out_pred, _)| match out_pred.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(p) => p.to_string(),
ty::ClauseKind::TypeOutlives(p) => p.to_string(),
err => bug!("unexpected clause {:?}", err),
})
.collect();
pred.sort();
let span = tcx.def_span(item_def_id);
let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
for p in pred {
err.note(p);
}
err.emit();
}
debug!("inferred_outlives_of({:?}) = {:?}", item_def_id, predicates);
predicates
@@ -1,5 +1,4 @@
use rustc_errors::struct_span_err;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::sym;
pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
@@ -7,15 +6,23 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
if tcx.has_attr(id.owner_id, sym::rustc_outlives) {
let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
struct_span_err!(
tcx.sess,
tcx.def_span(id.owner_id),
E0640,
"{:?}",
inferred_outlives_of
)
.emit();
let predicates = tcx.inferred_outlives_of(id.owner_id);
let mut pred: Vec<String> = predicates
.iter()
.map(|(out_pred, _)| match out_pred.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(p) => p.to_string(),
ty::ClauseKind::TypeOutlives(p) => p.to_string(),
err => bug!("unexpected clause {:?}", err),
})
.collect();
pred.sort();
let span = tcx.def_span(id.owner_id);
let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
for p in pred {
err.note(p);
}
err.emit();
}
}
}
@@ -6,7 +6,7 @@
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 @@ fn diagnostic(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
}
}
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
}
}
@@ -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 @@ fn code(&self) -> DiagnosticId {
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 @@ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
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 \
@@ -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 @@ fn code(&self) -> DiagnosticId {
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 @@ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
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.
@@ -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 @@ fn create_error_message(&self) -> String {
}
}
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 @@ fn code(&self) -> DiagnosticId {
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);
+2 -22
View File
@@ -553,17 +553,7 @@ fn print_item(&mut self, item: &hir::Item<'_>) {
}
hir::ItemKind::OpaqueTy(opaque_ty) => {
self.print_item_type(item, opaque_ty.generics, |state| {
let mut real_bounds = Vec::with_capacity(opaque_ty.bounds.len());
for b in opaque_ty.bounds {
if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
state.space();
state.word_space("for ?");
state.print_trait_ref(&ptr.trait_ref);
} else {
real_bounds.push(b);
}
}
state.print_bounds("= impl", real_bounds);
state.print_bounds("= impl", opaque_ty.bounds)
});
}
hir::ItemKind::Enum(ref enum_definition, params) => {
@@ -625,17 +615,7 @@ fn print_item(&mut self, item: &hir::Item<'_>) {
self.word_nbsp("trait");
self.print_ident(item.ident);
self.print_generic_params(generics.params);
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds {
if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
real_bounds.push(b);
}
}
self.print_bounds(":", real_bounds);
self.print_bounds(":", bounds);
self.print_where_clause(generics);
self.word(" ");
self.bopen();
+4 -2
View File
@@ -305,8 +305,10 @@ fn identify_bad_closure_def_and_call(
) = (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);
+1 -1
View File
@@ -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,
+4 -3
View File
@@ -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.
+8 -4
View File
@@ -634,7 +634,10 @@ fn supplied_sig_of_closure(
// 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 @@ fn supplied_sig_of_closure(
)
}
// 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()),
},
+2 -4
View File
@@ -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 @@ fn report_return_mismatched_types<'a>(
id: hir::HirId,
expression: Option<&'tcx hir::Expr<'tcx>>,
blk_id: Option<hir::HirId>,
) -> 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);
+6 -6
View File
@@ -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 @@ pub fn demand_suptype_diag(
sp: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
}
@@ -178,7 +178,7 @@ pub fn demand_suptype_with_origin(
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
@@ -199,7 +199,7 @@ pub fn demand_eqtype_diag(
sp: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
}
@@ -208,7 +208,7 @@ pub fn demand_eqtype_with_origin(
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
@@ -246,7 +246,7 @@ pub fn demand_coerce_diag(
expected: Ty<'tcx>,
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
allow_two_phase: AllowTwoPhase,
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
let expected = self.resolve_vars_with_obligations(expected);
let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {
+4 -8
View File
@@ -722,7 +722,7 @@ fn check_expr_break(
if let [segment] = path.segments
&& segment.ident.name == sym::rust
{
fatally_break_rust(self.tcx);
fatally_break_rust(self.tcx, expr.span);
}
}
}
@@ -966,7 +966,7 @@ pub(crate) fn check_lhs_assignable(
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 @@ fn no_such_field_err(
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 @@ fn no_such_field_err(
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!(
@@ -1258,7 +1258,7 @@ fn suggest_ptr_null_mut(
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, .. }) =
@@ -17,8 +17,8 @@
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 @@ pub(in super::super) fn suggest_boxing_when_appropriate(
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
+10 -9
View File
@@ -52,7 +52,7 @@
use crate::fn_ctxt::RawTy;
use crate::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan};
use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
@@ -412,24 +412,25 @@ enum TupleArgumentsFlag {
TupleArguments,
}
fn fatally_break_rust(tcx: TyCtxt<'_>) {
fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
let dcx = tcx.sess.dcx();
dcx.span_bug_no_panic(
MultiSpan::new(),
let mut diag = dcx.struct_span_bug(
span,
"It looks like you're trying to break rust; would you like some ICE?",
);
dcx.note("the compiler expectedly panicked. this is a feature.");
dcx.note(
diag.note("the compiler expectedly panicked. this is a feature.");
diag.note(
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
dcx.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),));
diag.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),));
if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
dcx.note(format!("compiler flags: {}", flags.join(" ")));
diag.note(format!("compiler flags: {}", flags.join(" ")));
if excluded_cargo_defaults {
dcx.note("some of the compiler flags provided by cargo are hidden");
diag.note("some of the compiler flags provided by cargo are hidden");
}
}
diag.emit()
}
/// `expected` here is the expected number of explicit generic arguments on the trait.
@@ -13,8 +13,7 @@
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 @@ pub fn report_method_error(
args: Option<&'tcx [hir::Expr<'tcx>]>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'_>> {
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
return None;
@@ -261,7 +260,7 @@ fn suggest_missing_writer(
&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 @@ pub fn report_no_match_method_error(
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'_>> {
let mode = no_match_data.mode;
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+7 -7
View File
@@ -99,7 +99,7 @@ fn demand_eqtype_pat_diag(
expected: Ty<'tcx>,
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
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 @@ fn maybe_suggest_range_literal(
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 @@ fn error_tuple_variant_index_shorthand(
variant: &VariantDef,
pat: &'_ Pat<'_>,
fields: &[hir::PatField<'_>],
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'_>> {
// 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 @@ fn error_inexistent_fields(
pat: &'tcx Pat<'tcx>,
variant: &ty::VariantDef,
args: &'tcx ty::List<ty::GenericArg<'tcx>>,
) -> 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 @@ fn error_tuple_variant_as_struct_pat(
pat: &Pat<'_>,
fields: &'tcx [hir::PatField<'tcx>],
variant: &ty::VariantDef,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
) -> Option<DiagnosticBuilder<'tcx>> {
if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
(variant.ctor_kind(), &pat.kind)
{
@@ -1775,7 +1775,7 @@ fn error_no_accessible_fields(
&self,
pat: &Pat<'_>,
fields: &'tcx [hir::PatField<'tcx>],
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
) -> DiagnosticBuilder<'tcx> {
let mut err = self
.tcx
.sess
@@ -1867,7 +1867,7 @@ fn error_unmentioned_fields(
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}")
+2
View File
@@ -502,6 +502,7 @@ pub fn insert(&mut self, elem: T) -> bool {
};
#[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 @@ pub fn remove(&mut self, elem: T) -> bool {
};
#[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() };

Some files were not shown because too many files have changed in this diff Show More