Merge pull request #20779 from rust-lang/rustc-pull
minor: Rustc pull update
This commit is contained in:
commit
b5108da611
321 changed files with 3994 additions and 2802 deletions
|
|
@ -476,9 +476,6 @@
|
|||
# when the stage 0 compiler is actually built from in-tree sources.
|
||||
#build.compiletest-allow-stage0 = false
|
||||
|
||||
# Whether to use the precompiled stage0 libtest with compiletest.
|
||||
#build.compiletest-use-stage0-libtest = true
|
||||
|
||||
# Default value for the `--extra-checks` flag of tidy.
|
||||
#
|
||||
# See `./x test tidy --help` for details.
|
||||
|
|
|
|||
|
|
@ -42,22 +42,22 @@ impl Reg {
|
|||
let dl = cx.data_layout();
|
||||
match self.kind {
|
||||
RegKind::Integer => match self.size.bits() {
|
||||
1 => dl.i1_align.abi,
|
||||
2..=8 => dl.i8_align.abi,
|
||||
9..=16 => dl.i16_align.abi,
|
||||
17..=32 => dl.i32_align.abi,
|
||||
33..=64 => dl.i64_align.abi,
|
||||
65..=128 => dl.i128_align.abi,
|
||||
1 => dl.i1_align,
|
||||
2..=8 => dl.i8_align,
|
||||
9..=16 => dl.i16_align,
|
||||
17..=32 => dl.i32_align,
|
||||
33..=64 => dl.i64_align,
|
||||
65..=128 => dl.i128_align,
|
||||
_ => panic!("unsupported integer: {self:?}"),
|
||||
},
|
||||
RegKind::Float => match self.size.bits() {
|
||||
16 => dl.f16_align.abi,
|
||||
32 => dl.f32_align.abi,
|
||||
64 => dl.f64_align.abi,
|
||||
128 => dl.f128_align.abi,
|
||||
16 => dl.f16_align,
|
||||
32 => dl.f32_align,
|
||||
64 => dl.f64_align,
|
||||
128 => dl.f128_align,
|
||||
_ => panic!("unsupported float: {self:?}"),
|
||||
},
|
||||
RegKind::Vector => dl.llvmlike_vector_align(self.size).abi,
|
||||
RegKind::Vector => dl.llvmlike_vector_align(self.size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,11 +174,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
// Non-power-of-two vectors have padding up to the next power-of-two.
|
||||
// If we're a packed repr, remove the padding while keeping the alignment as close
|
||||
// to a vector as possible.
|
||||
(BackendRepr::Memory { sized: true }, AbiAlign { abi: Align::max_aligned_factor(size) })
|
||||
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
|
||||
} else {
|
||||
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
|
||||
};
|
||||
let size = size.align_to(align.abi);
|
||||
let size = size.align_to(align);
|
||||
|
||||
Ok(LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
|
|
@ -190,7 +190,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
largest_niche: elt.largest_niche,
|
||||
uninhabited: false,
|
||||
size,
|
||||
align,
|
||||
align: AbiAlign::new(align),
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: elt.align.abi,
|
||||
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
|
||||
|
|
@ -388,7 +388,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
return Err(LayoutCalculatorError::UnexpectedUnsized(*field));
|
||||
}
|
||||
|
||||
align = align.max(field.align);
|
||||
align = align.max(field.align.abi);
|
||||
max_repr_align = max_repr_align.max(field.max_repr_align);
|
||||
size = cmp::max(size, field.size);
|
||||
|
||||
|
|
@ -423,13 +423,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
}
|
||||
|
||||
if let Some(pack) = repr.pack {
|
||||
align = align.min(AbiAlign::new(pack));
|
||||
align = align.min(pack);
|
||||
}
|
||||
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
|
||||
// See documentation on `LayoutData::unadjusted_abi_align`.
|
||||
let unadjusted_abi_align = align.abi;
|
||||
let unadjusted_abi_align = align;
|
||||
if let Some(repr_align) = repr.align {
|
||||
align = align.max(AbiAlign::new(repr_align));
|
||||
align = align.max(repr_align);
|
||||
}
|
||||
// `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
|
||||
let align = align;
|
||||
|
|
@ -441,14 +441,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
Ok(Some((repr, _))) => match repr {
|
||||
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
|
||||
BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
|
||||
if repr.scalar_align(dl).unwrap() != align.abi =>
|
||||
if repr.scalar_align(dl).unwrap() != align =>
|
||||
{
|
||||
BackendRepr::Memory { sized: true }
|
||||
}
|
||||
// Vectors require at least element alignment, else disable the opt
|
||||
BackendRepr::SimdVector { element, count: _ }
|
||||
if element.align(dl).abi > align.abi =>
|
||||
{
|
||||
BackendRepr::SimdVector { element, count: _ } if element.align(dl).abi > align => {
|
||||
BackendRepr::Memory { sized: true }
|
||||
}
|
||||
// the alignment tests passed and we can use this
|
||||
|
|
@ -474,8 +472,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
backend_repr,
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
align,
|
||||
size: size.align_to(align.abi),
|
||||
align: AbiAlign::new(align),
|
||||
size: size.align_to(align),
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: combined_seed,
|
||||
|
|
@ -611,7 +609,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut max_repr_align = repr.align;
|
||||
let mut unadjusted_abi_align = align.abi;
|
||||
let mut unadjusted_abi_align = align;
|
||||
|
||||
let mut variant_layouts = variants
|
||||
.iter_enumerated()
|
||||
|
|
@ -619,7 +617,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;
|
||||
st.variants = Variants::Single { index: j };
|
||||
|
||||
align = align.max(st.align);
|
||||
align = align.max(st.align.abi);
|
||||
max_repr_align = max_repr_align.max(st.max_repr_align);
|
||||
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
|
||||
|
||||
|
|
@ -646,7 +644,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let (niche_start, niche_scalar) = niche.reserve(dl, count)?;
|
||||
let niche_offset = niche.offset;
|
||||
let niche_size = niche.value.size(dl);
|
||||
let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
|
||||
let size = variant_layouts[largest_variant_index].size.align_to(align);
|
||||
|
||||
let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
|
||||
if i == largest_variant_index {
|
||||
|
|
@ -699,7 +697,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
.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 same_align = align == variant_layouts[largest_variant_index].align.abi;
|
||||
|
||||
let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited());
|
||||
let abi = if same_size && same_align && others_zst {
|
||||
|
|
@ -746,7 +744,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
largest_niche,
|
||||
uninhabited,
|
||||
size,
|
||||
align,
|
||||
align: AbiAlign::new(align),
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: combined_seed,
|
||||
|
|
@ -818,7 +816,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut max_repr_align = repr.align;
|
||||
let mut unadjusted_abi_align = align.abi;
|
||||
let mut unadjusted_abi_align = align;
|
||||
|
||||
let mut size = Size::ZERO;
|
||||
|
||||
|
|
@ -860,7 +858,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
}
|
||||
}
|
||||
size = cmp::max(size, st.size);
|
||||
align = align.max(st.align);
|
||||
align = align.max(st.align.abi);
|
||||
max_repr_align = max_repr_align.max(st.max_repr_align);
|
||||
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
|
||||
Ok(st)
|
||||
|
|
@ -868,7 +866,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
|
||||
|
||||
// Align the maximum variant size to the largest alignment.
|
||||
size = size.align_to(align.abi);
|
||||
size = size.align_to(align);
|
||||
|
||||
// FIXME(oli-obk): deduplicate and harden these checks
|
||||
if size.bytes() >= dl.obj_size_bound() {
|
||||
|
|
@ -1042,7 +1040,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
};
|
||||
if pair_offsets[FieldIdx::new(0)] == Size::ZERO
|
||||
&& pair_offsets[FieldIdx::new(1)] == *offset
|
||||
&& align == pair.align
|
||||
&& align == pair.align.abi
|
||||
&& size == pair.size
|
||||
{
|
||||
// We can use `ScalarPair` only when it matches our
|
||||
|
|
@ -1066,7 +1064,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
// 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);
|
||||
variant.align.abi = cmp::max(variant.align.abi, align);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,7 +1090,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
largest_niche,
|
||||
uninhabited,
|
||||
backend_repr: abi,
|
||||
align,
|
||||
align: AbiAlign::new(align),
|
||||
size,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
|
|
@ -1169,7 +1167,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
// To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must
|
||||
// not depend on the layout of the tail.
|
||||
let max_field_align =
|
||||
fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1);
|
||||
fields_excluding_tail.iter().map(|f| f.align.bytes()).max().unwrap_or(1);
|
||||
let largest_niche_size = fields_excluding_tail
|
||||
.iter()
|
||||
.filter_map(|f| f.largest_niche)
|
||||
|
|
@ -1189,7 +1187,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
} else {
|
||||
// Returns `log2(effective-align)`. The calculation assumes that size is an
|
||||
// integer multiple of align, except for ZSTs.
|
||||
let align = layout.align.abi.bytes();
|
||||
let align = layout.align.bytes();
|
||||
let size = layout.size.bytes();
|
||||
let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0);
|
||||
// Group [u8; 4] with align-4 or [u8; 6] with align-2 fields.
|
||||
|
|
@ -1288,7 +1286,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
|
||||
let prefix_align =
|
||||
if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align };
|
||||
align = align.max(AbiAlign::new(prefix_align));
|
||||
align = align.max(prefix_align);
|
||||
offset = prefix_size.align_to(prefix_align);
|
||||
}
|
||||
for &i in &inverse_memory_index {
|
||||
|
|
@ -1312,7 +1310,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
field.align
|
||||
};
|
||||
offset = offset.align_to(field_align.abi);
|
||||
align = align.max(field_align);
|
||||
align = align.max(field_align.abi);
|
||||
max_repr_align = max_repr_align.max(field.max_repr_align);
|
||||
|
||||
debug!("univariant offset: {:?} field: {:#?}", offset, field);
|
||||
|
|
@ -1339,9 +1337,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
|
||||
// See documentation on `LayoutData::unadjusted_abi_align`.
|
||||
let unadjusted_abi_align = align.abi;
|
||||
let unadjusted_abi_align = align;
|
||||
if let Some(repr_align) = repr.align {
|
||||
align = align.max(AbiAlign::new(repr_align));
|
||||
align = align.max(repr_align);
|
||||
}
|
||||
// `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate.
|
||||
let align = align;
|
||||
|
|
@ -1360,7 +1358,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
|
||||
inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
|
||||
};
|
||||
let size = min_size.align_to(align.abi);
|
||||
let size = min_size.align_to(align);
|
||||
// FIXME(oli-obk): deduplicate and harden these checks
|
||||
if size.bytes() >= dl.obj_size_bound() {
|
||||
return Err(LayoutCalculatorError::SizeOverflow);
|
||||
|
|
@ -1383,8 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
layout_of_single_non_zst_field = Some(field);
|
||||
|
||||
// Field fills the struct and it has a scalar or scalar pair ABI.
|
||||
if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size
|
||||
{
|
||||
if offsets[i].bytes() == 0 && align == field.align.abi && size == field.size {
|
||||
match field.backend_repr {
|
||||
// For plain scalars, or vectors of them, we can't unpack
|
||||
// newtypes for `#[repr(C)]`, as that affects C ABIs.
|
||||
|
|
@ -1428,7 +1425,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
};
|
||||
if offsets[i] == pair_offsets[FieldIdx::new(0)]
|
||||
&& offsets[j] == pair_offsets[FieldIdx::new(1)]
|
||||
&& align == pair.align
|
||||
&& align == pair.align.abi
|
||||
&& size == pair.size
|
||||
{
|
||||
// We can use `ScalarPair` only when it matches our
|
||||
|
|
@ -1450,7 +1447,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
Some(l) => l.unadjusted_abi_align,
|
||||
None => {
|
||||
// `repr(transparent)` with all ZST fields.
|
||||
align.abi
|
||||
align
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1465,7 +1462,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
backend_repr: abi,
|
||||
largest_niche,
|
||||
uninhabited,
|
||||
align,
|
||||
align: AbiAlign::new(align),
|
||||
size,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
|
|
@ -1488,7 +1485,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
for i in layout.fields.index_by_increasing_offset() {
|
||||
let offset = layout.fields.offset(i);
|
||||
let f = &fields[FieldIdx::new(i)];
|
||||
write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap();
|
||||
write!(s, "[o{}a{}s{}", offset.bytes(), f.align.bytes(), f.size.bytes()).unwrap();
|
||||
if let Some(n) = f.largest_niche {
|
||||
write!(
|
||||
s,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use rustc_hashes::Hash64;
|
|||
use rustc_index::{Idx, IndexVec};
|
||||
|
||||
use crate::{
|
||||
BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants,
|
||||
AbiAlign, BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size,
|
||||
Variants,
|
||||
};
|
||||
|
||||
/// "Simple" layout constructors that cannot fail.
|
||||
|
|
@ -20,10 +21,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
backend_repr: BackendRepr::Memory { sized },
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
align: dl.i8_align,
|
||||
align: AbiAlign::new(dl.i8_align),
|
||||
size: Size::ZERO,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: dl.i8_align.abi,
|
||||
unadjusted_abi_align: dl.i8_align,
|
||||
randomization_seed: Hash64::new(0),
|
||||
}
|
||||
}
|
||||
|
|
@ -37,10 +38,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
backend_repr: BackendRepr::Memory { sized: true },
|
||||
largest_niche: None,
|
||||
uninhabited: true,
|
||||
align: dl.i8_align,
|
||||
align: AbiAlign::new(dl.i8_align),
|
||||
size: Size::ZERO,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: dl.i8_align.abi,
|
||||
unadjusted_abi_align: dl.i8_align,
|
||||
randomization_seed: Hash64::ZERO,
|
||||
}
|
||||
}
|
||||
|
|
@ -89,10 +90,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
|
||||
pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
|
||||
let dl = cx.data_layout();
|
||||
let b_align = b.align(dl);
|
||||
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
|
||||
let b_offset = a.size(dl).align_to(b_align.abi);
|
||||
let size = (b_offset + b.size(dl)).align_to(align.abi);
|
||||
let b_align = b.align(dl).abi;
|
||||
let align = a.align(dl).abi.max(b_align).max(dl.aggregate_align);
|
||||
let b_offset = a.size(dl).align_to(b_align);
|
||||
let size = (b_offset + b.size(dl)).align_to(align);
|
||||
|
||||
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
|
||||
// returns the last maximum.
|
||||
|
|
@ -112,10 +113,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
backend_repr: BackendRepr::ScalarPair(a, b),
|
||||
largest_niche,
|
||||
uninhabited: false,
|
||||
align,
|
||||
align: AbiAlign::new(align),
|
||||
size,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: align.abi,
|
||||
unadjusted_abi_align: align,
|
||||
randomization_seed: Hash64::new(combined_seed),
|
||||
}
|
||||
}
|
||||
|
|
@ -138,10 +139,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
backend_repr: BackendRepr::Memory { sized: true },
|
||||
largest_niche: None,
|
||||
uninhabited: true,
|
||||
align: dl.i8_align,
|
||||
align: AbiAlign::new(dl.i8_align),
|
||||
size: Size::ZERO,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: dl.i8_align.abi,
|
||||
unadjusted_abi_align: dl.i8_align,
|
||||
randomization_seed: Hash64::ZERO,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ pub struct PointerSpec {
|
|||
/// The size of the bitwise representation of the pointer.
|
||||
pointer_size: Size,
|
||||
/// The alignment of pointers for this address space
|
||||
pointer_align: AbiAlign,
|
||||
pointer_align: Align,
|
||||
/// The size of the value a pointer can be offset by in this address space.
|
||||
pointer_offset: Size,
|
||||
/// Pointers into this address space contain extra metadata
|
||||
|
|
@ -242,20 +242,20 @@ pub struct PointerSpec {
|
|||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TargetDataLayout {
|
||||
pub endian: Endian,
|
||||
pub i1_align: AbiAlign,
|
||||
pub i8_align: AbiAlign,
|
||||
pub i16_align: AbiAlign,
|
||||
pub i32_align: AbiAlign,
|
||||
pub i64_align: AbiAlign,
|
||||
pub i128_align: AbiAlign,
|
||||
pub f16_align: AbiAlign,
|
||||
pub f32_align: AbiAlign,
|
||||
pub f64_align: AbiAlign,
|
||||
pub f128_align: AbiAlign,
|
||||
pub aggregate_align: AbiAlign,
|
||||
pub i1_align: Align,
|
||||
pub i8_align: Align,
|
||||
pub i16_align: Align,
|
||||
pub i32_align: Align,
|
||||
pub i64_align: Align,
|
||||
pub i128_align: Align,
|
||||
pub f16_align: Align,
|
||||
pub f32_align: Align,
|
||||
pub f64_align: Align,
|
||||
pub f128_align: Align,
|
||||
pub aggregate_align: Align,
|
||||
|
||||
/// Alignments for vector types.
|
||||
pub vector_align: Vec<(Size, AbiAlign)>,
|
||||
pub vector_align: Vec<(Size, Align)>,
|
||||
|
||||
pub default_address_space: AddressSpace,
|
||||
pub default_address_space_pointer_spec: PointerSpec,
|
||||
|
|
@ -282,25 +282,25 @@ impl Default for TargetDataLayout {
|
|||
let align = |bits| Align::from_bits(bits).unwrap();
|
||||
TargetDataLayout {
|
||||
endian: Endian::Big,
|
||||
i1_align: AbiAlign::new(align(8)),
|
||||
i8_align: AbiAlign::new(align(8)),
|
||||
i16_align: AbiAlign::new(align(16)),
|
||||
i32_align: AbiAlign::new(align(32)),
|
||||
i64_align: AbiAlign::new(align(32)),
|
||||
i128_align: AbiAlign::new(align(32)),
|
||||
f16_align: AbiAlign::new(align(16)),
|
||||
f32_align: AbiAlign::new(align(32)),
|
||||
f64_align: AbiAlign::new(align(64)),
|
||||
f128_align: AbiAlign::new(align(128)),
|
||||
aggregate_align: AbiAlign { abi: align(8) },
|
||||
i1_align: align(8),
|
||||
i8_align: align(8),
|
||||
i16_align: align(16),
|
||||
i32_align: align(32),
|
||||
i64_align: align(32),
|
||||
i128_align: align(32),
|
||||
f16_align: align(16),
|
||||
f32_align: align(32),
|
||||
f64_align: align(64),
|
||||
f128_align: align(128),
|
||||
aggregate_align: align(8),
|
||||
vector_align: vec![
|
||||
(Size::from_bits(64), AbiAlign::new(align(64))),
|
||||
(Size::from_bits(128), AbiAlign::new(align(128))),
|
||||
(Size::from_bits(64), align(64)),
|
||||
(Size::from_bits(128), align(128)),
|
||||
],
|
||||
default_address_space: AddressSpace::ZERO,
|
||||
default_address_space_pointer_spec: PointerSpec {
|
||||
pointer_size: Size::from_bits(64),
|
||||
pointer_align: AbiAlign::new(align(64)),
|
||||
pointer_align: align(64),
|
||||
pointer_offset: Size::from_bits(64),
|
||||
_is_fat: false,
|
||||
},
|
||||
|
|
@ -360,7 +360,7 @@ impl TargetDataLayout {
|
|||
.map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
|
||||
};
|
||||
let abi = parse_bits(s, "alignment", cause)?;
|
||||
Ok(AbiAlign::new(align_from_bits(abi)?))
|
||||
Ok(align_from_bits(abi)?)
|
||||
};
|
||||
|
||||
// Parse an alignment sequence, possibly in the form `<align>[:<preferred_alignment>]`,
|
||||
|
|
@ -596,7 +596,7 @@ impl TargetDataLayout {
|
|||
|
||||
/// psABI-mandated alignment for a vector type, if any
|
||||
#[inline]
|
||||
fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAlign> {
|
||||
fn cabi_vector_align(&self, vec_size: Size) -> Option<Align> {
|
||||
self.vector_align
|
||||
.iter()
|
||||
.find(|(size, _align)| *size == vec_size)
|
||||
|
|
@ -605,10 +605,9 @@ impl TargetDataLayout {
|
|||
|
||||
/// an alignment resembling the one LLVM would pick for a vector
|
||||
#[inline]
|
||||
pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAlign {
|
||||
self.cabi_vector_align(vec_size).unwrap_or(AbiAlign::new(
|
||||
Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
|
||||
))
|
||||
pub fn llvmlike_vector_align(&self, vec_size: Size) -> Align {
|
||||
self.cabi_vector_align(vec_size)
|
||||
.unwrap_or(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
|
||||
}
|
||||
|
||||
/// Get the pointer size in the default data address space.
|
||||
|
|
@ -654,21 +653,19 @@ impl TargetDataLayout {
|
|||
/// Get the pointer alignment in the default data address space.
|
||||
#[inline]
|
||||
pub fn pointer_align(&self) -> AbiAlign {
|
||||
self.default_address_space_pointer_spec.pointer_align
|
||||
AbiAlign::new(self.default_address_space_pointer_spec.pointer_align)
|
||||
}
|
||||
|
||||
/// Get the pointer alignment in a specific address space.
|
||||
#[inline]
|
||||
pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign {
|
||||
if c == self.default_address_space {
|
||||
return self.default_address_space_pointer_spec.pointer_align;
|
||||
}
|
||||
|
||||
if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
|
||||
AbiAlign::new(if c == self.default_address_space {
|
||||
self.default_address_space_pointer_spec.pointer_align
|
||||
} else if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
|
||||
e.1.pointer_align
|
||||
} else {
|
||||
panic!("Use of unknown address space {c:?}");
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1185,13 +1182,13 @@ impl Integer {
|
|||
use Integer::*;
|
||||
let dl = cx.data_layout();
|
||||
|
||||
match self {
|
||||
AbiAlign::new(match self {
|
||||
I8 => dl.i8_align,
|
||||
I16 => dl.i16_align,
|
||||
I32 => dl.i32_align,
|
||||
I64 => dl.i64_align,
|
||||
I128 => dl.i128_align,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the largest signed value that can be represented by this Integer.
|
||||
|
|
@ -1311,12 +1308,12 @@ impl Float {
|
|||
use Float::*;
|
||||
let dl = cx.data_layout();
|
||||
|
||||
match self {
|
||||
AbiAlign::new(match self {
|
||||
F16 => dl.f16_align,
|
||||
F32 => dl.f32_align,
|
||||
F64 => dl.f64_align,
|
||||
F128 => dl.f128_align,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2159,7 +2156,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
|
||||
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
|
||||
pub fn is_1zst(&self) -> bool {
|
||||
self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1
|
||||
self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
|
||||
}
|
||||
|
||||
/// Returns `true` if the type is a ZST and not unsized.
|
||||
|
|
|
|||
|
|
@ -114,8 +114,7 @@ impl PartialEq<Symbol> for Path {
|
|||
impl PartialEq<&[Symbol]> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, names: &&[Symbol]) -> bool {
|
||||
self.segments.len() == names.len()
|
||||
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
|
||||
self.segments.iter().eq(*names)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![recursion_limit = "256"]
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ impl TokenTree {
|
|||
match (self, other) {
|
||||
(TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind,
|
||||
(TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => {
|
||||
delim == delim2
|
||||
&& tts.len() == tts2.len()
|
||||
&& tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b))
|
||||
delim == delim2 && tts.iter().eq_by(tts2.iter(), |a, b| a.eq_unspanned(b))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,15 @@ attr_parsing_deprecated_item_suggestion =
|
|||
|
||||
attr_parsing_empty_attribute =
|
||||
unused attribute
|
||||
.suggestion = remove this attribute
|
||||
.suggestion = {$valid_without_list ->
|
||||
[true] remove these parentheses
|
||||
*[other] remove this attribute
|
||||
}
|
||||
.note = {$valid_without_list ->
|
||||
[true] using `{$attr_path}` with an empty list is equivalent to not using a list at all
|
||||
*[other] using `{$attr_path}` with an empty list has no effect
|
||||
}
|
||||
|
||||
|
||||
attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
|
||||
.help = `#[{$name}]` can {$only}be applied to {$applied}
|
||||
|
|
|
|||
|
|
@ -597,7 +597,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
}
|
||||
|
||||
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
|
||||
self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
|
||||
let attr_path = self.attr_path.clone();
|
||||
let valid_without_list = self.template.word;
|
||||
self.emit_lint(
|
||||
AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list },
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,12 +43,18 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
|
|||
),
|
||||
},
|
||||
),
|
||||
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
*id,
|
||||
*first_span,
|
||||
session_diagnostics::EmptyAttributeList { attr_span: *first_span },
|
||||
),
|
||||
AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => {
|
||||
lint_emitter.emit_node_span_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
*id,
|
||||
*first_span,
|
||||
session_diagnostics::EmptyAttributeList {
|
||||
attr_span: *first_span,
|
||||
attr_path: attr_path.clone(),
|
||||
valid_without_list: *valid_without_list,
|
||||
},
|
||||
)
|
||||
}
|
||||
AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter
|
||||
.emit_node_span_lint(
|
||||
// This check is here because `deprecated` had its own lint group and removing this would be a breaking change
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl<'a> PathParser<'a> {
|
|||
}
|
||||
|
||||
pub fn segments_is(&self, segments: &[Symbol]) -> bool {
|
||||
self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
|
||||
self.segments().map(|segment| &segment.name).eq(segments)
|
||||
}
|
||||
|
||||
pub fn word(&self) -> Option<Ident> {
|
||||
|
|
|
|||
|
|
@ -503,9 +503,12 @@ pub(crate) struct EmptyConfusables {
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(attr_parsing_empty_attribute)]
|
||||
#[note]
|
||||
pub(crate) struct EmptyAttributeList {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub attr_span: Span,
|
||||
pub attr_path: AttrPath,
|
||||
pub valid_without_list: bool,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_return_reference_to_local(
|
||||
|
|
@ -480,7 +480,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2992,6 +2992,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, explanation))]
|
||||
fn report_local_value_does_not_live_long_enough(
|
||||
&self,
|
||||
location: Location,
|
||||
|
|
@ -3001,13 +3002,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> Diag<'infcx> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
location, name, borrow, drop_span, borrow_spans
|
||||
);
|
||||
|
||||
let borrow_span = borrow_spans.var_or_use_path_span();
|
||||
if let BorrowExplanation::MustBeValidFor {
|
||||
category,
|
||||
|
|
|
|||
|
|
@ -416,6 +416,26 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
{
|
||||
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
|
||||
}
|
||||
|
||||
let mut preds = path
|
||||
.iter()
|
||||
.filter_map(|constraint| match constraint.category {
|
||||
ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<Span>>();
|
||||
preds.sort();
|
||||
preds.dedup();
|
||||
if !preds.is_empty() {
|
||||
let s = if preds.len() == 1 { "" } else { "s" };
|
||||
err.span_note(
|
||||
preds,
|
||||
format!(
|
||||
"requirement{s} that the value outlives `{region_name}` introduced here"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
fn mir_borrowck(
|
||||
tcx: TyCtxt<'_>,
|
||||
def: LocalDefId,
|
||||
) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
|
||||
) -> Result<&DefinitionSiteHiddenTypes<'_>, ErrorGuaranteed> {
|
||||
assert!(!tcx.is_typeck_child(def.to_def_id()));
|
||||
let (input_body, _) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
||||
|
|
@ -130,7 +130,7 @@ fn mir_borrowck(
|
|||
Err(guar)
|
||||
} else if input_body.should_skip() {
|
||||
debug!("Skipping borrowck because of injected body");
|
||||
let opaque_types = ConcreteOpaqueTypes(Default::default());
|
||||
let opaque_types = DefinitionSiteHiddenTypes(Default::default());
|
||||
Ok(tcx.arena.alloc(opaque_types))
|
||||
} else {
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
|
||||
|
|
|
|||
|
|
@ -1382,10 +1382,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
/// The constraints we get from equating the hidden type of each use of an opaque
|
||||
/// with its final concrete type may end up getting preferred over other, potentially
|
||||
/// with its final hidden type may end up getting preferred over other, potentially
|
||||
/// longer constraint paths.
|
||||
///
|
||||
/// Given that we compute the final concrete type by relying on this existing constraint
|
||||
/// Given that we compute the final hidden type by relying on this existing constraint
|
||||
/// path, this can easily end up hiding the actual reason for why we require these regions
|
||||
/// to be equal.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
|||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory};
|
||||
use rustc_middle::mir::{Body, ConstraintCategory, DefinitionSiteHiddenTypes};
|
||||
use rustc_middle::ty::{
|
||||
self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef,
|
||||
OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable,
|
||||
|
|
@ -129,9 +129,9 @@ fn nll_var_to_universal_region<'tcx>(
|
|||
/// Collect all defining uses of opaque types inside of this typeck root. This
|
||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||
/// and errors if we end up with distinct hidden types.
|
||||
fn add_concrete_opaque_type<'tcx>(
|
||||
fn add_hidden_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
|
|
@ -139,7 +139,7 @@ fn add_concrete_opaque_type<'tcx>(
|
|||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
|
||||
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
|
||||
// only know that once we convert the generic parameters to those of the opaque type.
|
||||
if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) {
|
||||
if let Some(prev) = hidden_types.0.get_mut(&def_id) {
|
||||
if prev.ty != hidden_ty.ty {
|
||||
let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| {
|
||||
let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
|
||||
|
|
@ -151,15 +151,15 @@ fn add_concrete_opaque_type<'tcx>(
|
|||
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
|
||||
prev.span = prev.span.substitute_dummy(hidden_ty.span);
|
||||
} else {
|
||||
concrete_opaque_types.0.insert(def_id, hidden_ty);
|
||||
hidden_types.0.insert(def_id, hidden_ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_concrete_opaque_type<'tcx>(
|
||||
concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
|
||||
fn get_hidden_type<'tcx>(
|
||||
hidden_types: &DefinitionSiteHiddenTypes<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
|
||||
concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
|
||||
hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -173,22 +173,22 @@ struct DefiningUse<'tcx> {
|
|||
}
|
||||
|
||||
/// This computes the actual hidden types of the opaque types and maps them to their
|
||||
/// definition sites. Outside of registering the computed concrete types this function
|
||||
/// definition sites. Outside of registering the computed hidden types this function
|
||||
/// does not mutate the current borrowck state.
|
||||
///
|
||||
/// While it may fail to infer the hidden type and return errors, we always apply
|
||||
/// the computed concrete hidden type to all opaque type uses to check whether they
|
||||
/// the computed hidden type to all opaque type uses to check whether they
|
||||
/// are correct. This is necessary to support non-defining uses of opaques in their
|
||||
/// defining scope.
|
||||
///
|
||||
/// It also means that this whole function is not really soundness critical as we
|
||||
/// recheck all uses of the opaques regardless.
|
||||
pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
||||
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
let mut errors = Vec::new();
|
||||
|
|
@ -201,8 +201,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
// We start by checking each use of an opaque type during type check and
|
||||
// check whether the generic arguments of the opaque type are fully
|
||||
// universal, if so, it's a defining use.
|
||||
let defining_uses =
|
||||
collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors);
|
||||
let defining_uses = collect_defining_uses(&mut rcx, hidden_types, opaque_types, &mut errors);
|
||||
|
||||
// We now compute and apply member constraints for all regions in the hidden
|
||||
// types of each defining use. This mutates the region values of the `rcx` which
|
||||
|
|
@ -210,11 +209,11 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
apply_member_constraints(&mut rcx, &defining_uses);
|
||||
|
||||
// After applying member constraints, we now check whether all member regions ended
|
||||
// up equal to one of their choice regions and compute the actual concrete type of
|
||||
// up equal to one of their choice regions and compute the actual hidden type of
|
||||
// the opaque type definition. This is stored in the `root_cx`.
|
||||
compute_concrete_types_from_defining_uses(
|
||||
compute_definition_site_hidden_types_from_defining_uses(
|
||||
&rcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
&defining_uses,
|
||||
&mut errors,
|
||||
);
|
||||
|
|
@ -224,7 +223,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
#[instrument(level = "debug", skip_all, ret)]
|
||||
fn collect_defining_uses<'tcx>(
|
||||
rcx: &mut RegionCtxt<'_, 'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
) -> Vec<DefiningUse<'tcx>> {
|
||||
|
|
@ -244,9 +243,9 @@ fn collect_defining_uses<'tcx>(
|
|||
// with `TypingMode::Borrowck`.
|
||||
if infcx.tcx.use_typing_mode_borrowck() {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type(
|
||||
NonDefiningUseReason::Tainted(guar) => add_hidden_type(
|
||||
infcx.tcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(infcx.tcx, guar),
|
||||
),
|
||||
|
|
@ -277,9 +276,9 @@ fn collect_defining_uses<'tcx>(
|
|||
defining_uses
|
||||
}
|
||||
|
||||
fn compute_concrete_types_from_defining_uses<'tcx>(
|
||||
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||
rcx: &RegionCtxt<'_, 'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
defining_uses: &[DefiningUse<'tcx>],
|
||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
) {
|
||||
|
|
@ -358,9 +357,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
|
|||
},
|
||||
));
|
||||
}
|
||||
add_concrete_opaque_type(
|
||||
add_hidden_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType { span: hidden_type.span, ty },
|
||||
);
|
||||
|
|
@ -489,20 +488,20 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
|
|||
///
|
||||
/// It does this by equating the hidden type of each use with the instantiated final
|
||||
/// hidden type of the opaque.
|
||||
pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
||||
pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let mut errors = Vec::new();
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else {
|
||||
let Some(expected) = get_hidden_type(hidden_types, key.def_id) else {
|
||||
if !tcx.use_typing_mode_borrowck() {
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||
&& alias_ty.def_id == key.def_id.to_def_id()
|
||||
|
|
@ -521,12 +520,7 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
|||
hidden_type.span,
|
||||
"non-defining use in the defining scope with no defining uses",
|
||||
);
|
||||
add_concrete_opaque_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
key.def_id,
|
||||
OpaqueHiddenType::new_error(tcx, guar),
|
||||
);
|
||||
add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -566,18 +560,13 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
|||
"equating opaque types",
|
||||
),
|
||||
) {
|
||||
add_concrete_opaque_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
key.def_id,
|
||||
OpaqueHiddenType::new_error(tcx, guar),
|
||||
);
|
||||
add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
||||
/// In theory `apply_concrete_opaque_types` could introduce new uses of opaque types.
|
||||
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
|
||||
/// We do not check these new uses so this could be unsound.
|
||||
///
|
||||
/// We detect any new uses and simply delay a bug if they occur. If this results in
|
||||
|
|
@ -682,13 +671,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
///
|
||||
/// (*) C1 and C2 were introduced in the comments on
|
||||
/// `register_member_constraints`. Read that comment for more context.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `def_id`, the `impl Trait` type
|
||||
/// - `args`, the args used to instantiate this opaque type
|
||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||
/// `opaque_defn.concrete_ty`
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ use smallvec::SmallVec;
|
|||
use crate::consumers::BorrowckConsumer;
|
||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||
use crate::region_infer::opaque_types::{
|
||||
apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types,
|
||||
compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types,
|
||||
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
|
||||
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
|
||||
};
|
||||
use crate::type_check::{Locations, constraint_conversion};
|
||||
use crate::{
|
||||
ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes,
|
||||
ClosureRegionRequirements, CollectRegionConstraintsResult, DefinitionSiteHiddenTypes,
|
||||
PropagatedBorrowCheckResults, borrowck_check_region_constraints,
|
||||
borrowck_collect_region_constraints,
|
||||
};
|
||||
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: DefinitionSiteHiddenTypes<'tcx>,
|
||||
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
|
||||
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
|
||||
/// their parents.
|
||||
|
|
@ -49,7 +49,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
BorrowCheckRootCtxt {
|
||||
tcx,
|
||||
root_def_id,
|
||||
concrete_opaque_types: Default::default(),
|
||||
hidden_types: Default::default(),
|
||||
collect_region_constraints_results: Default::default(),
|
||||
propagated_borrowck_results: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
|
|
@ -72,11 +72,11 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
&self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
|
||||
}
|
||||
|
||||
pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
|
||||
pub(super) fn finalize(self) -> Result<&'tcx DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> {
|
||||
if let Some(guar) = self.tainted_by_errors {
|
||||
Err(guar)
|
||||
} else {
|
||||
Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
|
||||
Ok(self.tcx.arena.alloc(self.hidden_types))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +88,12 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
&input.universal_region_relations,
|
||||
&mut input.constraints,
|
||||
);
|
||||
input.deferred_opaque_type_errors = compute_concrete_opaque_types(
|
||||
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
|
||||
&input.infcx,
|
||||
&input.universal_region_relations,
|
||||
&input.constraints,
|
||||
Rc::clone(&input.location_map),
|
||||
&mut self.concrete_opaque_types,
|
||||
&mut self.hidden_types,
|
||||
&opaque_types,
|
||||
);
|
||||
per_body_info.push((num_entries, opaque_types));
|
||||
|
|
@ -103,14 +103,14 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
self.collect_region_constraints_results.values_mut().zip(per_body_info)
|
||||
{
|
||||
if input.deferred_opaque_type_errors.is_empty() {
|
||||
input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types(
|
||||
input.deferred_opaque_type_errors = apply_definition_site_hidden_types(
|
||||
&input.infcx,
|
||||
&input.body_owned,
|
||||
&input.universal_region_relations.universal_regions,
|
||||
&input.region_bound_pairs,
|
||||
&input.known_type_outlives_obligations,
|
||||
&mut input.constraints,
|
||||
&mut self.concrete_opaque_types,
|
||||
&mut self.hidden_types,
|
||||
&opaque_types,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,8 +377,7 @@ mod llvm_enzyme {
|
|||
(ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => {
|
||||
let a = &a.item.path;
|
||||
let b = &b.item.path;
|
||||
a.segments.len() == b.segments.len()
|
||||
&& a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident)
|
||||
a.segments.iter().eq_by(&b.segments, |a, b| a.ident == b.ident)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,21 +356,14 @@ fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool {
|
|||
bounds.iter().any(is_maybe_sized_bound)
|
||||
}
|
||||
|
||||
fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool {
|
||||
path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol)
|
||||
}
|
||||
|
||||
fn is_sized_marker(path: &ast::Path) -> bool {
|
||||
const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized];
|
||||
const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized];
|
||||
if path.segments.len() == 4 && path.is_global() {
|
||||
path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE)
|
||||
|| path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE)
|
||||
} else if path.segments.len() == 3 {
|
||||
path_segment_is_exact_match(&path.segments, &CORE_UNSIZE)
|
||||
|| path_segment_is_exact_match(&path.segments, &STD_UNSIZE)
|
||||
let segments = || path.segments.iter().map(|segment| segment.ident.name);
|
||||
if path.is_global() {
|
||||
segments().skip(1).eq(CORE_UNSIZE) || segments().skip(1).eq(STD_UNSIZE)
|
||||
} else {
|
||||
*path == sym::Sized
|
||||
segments().eq(CORE_UNSIZE) || segments().eq(STD_UNSIZE) || *path == sym::Sized
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -768,7 +768,7 @@ fn report_missing_placeholders(
|
|||
|
||||
if !found_foreign && invalid_refs.is_empty() {
|
||||
// Show example if user didn't use any format specifiers
|
||||
let show_example = used.iter().all(|used| !used);
|
||||
let show_example = !used.contains(&true);
|
||||
|
||||
if !show_example {
|
||||
if unused.len() > 1 {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>(
|
|||
format!("{:?}", local),
|
||||
format!("{:?}", ty),
|
||||
size.bytes(),
|
||||
align.abi.bytes(),
|
||||
align.bytes(),
|
||||
if extra.is_empty() { "" } else { " " },
|
||||
extra,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ pub(super) fn from_casted_value<'tcx>(
|
|||
// It may also be smaller for example when the type is a wrapper around an integer with a
|
||||
// larger alignment than the integer.
|
||||
std::cmp::max(abi_param_size, layout_size),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.bytes()).unwrap(),
|
||||
);
|
||||
let mut block_params_iter = block_params.iter().copied();
|
||||
for (offset, _) in abi_params {
|
||||
|
|
|
|||
|
|
@ -846,7 +846,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
let layout = fx.layout_of(fx.monomorphize(ty));
|
||||
let val = match null_op {
|
||||
NullOp::SizeOf => layout.size.bytes(),
|
||||
NullOp::AlignOf => layout.align.abi.bytes(),
|
||||
NullOp::AlignOf => layout.align.bytes(),
|
||||
NullOp::OffsetOf(fields) => fx
|
||||
.tcx
|
||||
.offset_of_subfield(
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ impl DebugContext {
|
|||
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
|
||||
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line));
|
||||
|
||||
entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes()));
|
||||
entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.bytes()));
|
||||
|
||||
let mut expr = Expression::new();
|
||||
expr.op_addr(address_for_data(data_id));
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ impl DebugContext {
|
|||
let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id);
|
||||
tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name)));
|
||||
tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes()));
|
||||
tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes()));
|
||||
tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.bytes()));
|
||||
|
||||
for (i, (ty, dw_ty)) in components.into_iter().enumerate() {
|
||||
let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member);
|
||||
|
|
@ -178,9 +178,7 @@ impl DebugContext {
|
|||
member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty));
|
||||
member_entry.set(
|
||||
gimli::DW_AT_alignment,
|
||||
AttributeValue::Udata(
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(),
|
||||
),
|
||||
AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.bytes()),
|
||||
);
|
||||
member_entry.set(
|
||||
gimli::DW_AT_data_member_location,
|
||||
|
|
|
|||
|
|
@ -165,6 +165,10 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
""
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"cranelift"
|
||||
}
|
||||
|
||||
fn init(&self, sess: &Session) {
|
||||
use rustc_session::config::{InstrumentCoverage, Lto};
|
||||
match sess.lto() {
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
if layout.is_sized() {
|
||||
return (
|
||||
fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64),
|
||||
fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64),
|
||||
fx.bcx.ins().iconst(fx.pointer_type, layout.align.bytes() as i64),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
// times the unit size.
|
||||
(
|
||||
fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64),
|
||||
fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64),
|
||||
fx.bcx.ins().iconst(fx.pointer_type, unit.align.bytes() as i64),
|
||||
)
|
||||
}
|
||||
ty::Foreign(_) => {
|
||||
|
|
@ -224,7 +224,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
let unsized_offset_unadjusted = layout.fields.offset(i).bytes();
|
||||
let unsized_offset_unadjusted =
|
||||
fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64);
|
||||
let sized_align = layout.align.abi.bytes();
|
||||
let sized_align = layout.align.bytes();
|
||||
let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64);
|
||||
|
||||
// Recurse to get the size of the dynamically sized field (must be
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ impl<'tcx> CPlace<'tcx> {
|
|||
|
||||
let stack_slot = fx.create_stack_slot(
|
||||
u32::try_from(layout.size.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
u32::try_from(layout.align.bytes()).unwrap(),
|
||||
);
|
||||
CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout }
|
||||
}
|
||||
|
|
@ -641,8 +641,8 @@ impl<'tcx> CPlace<'tcx> {
|
|||
let size = dst_layout.size.bytes();
|
||||
// `emit_small_memory_copy` uses `u8` for alignments, just use the maximum
|
||||
// alignment that fits in a `u8` if the actual alignment is larger.
|
||||
let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128);
|
||||
let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128);
|
||||
let src_align = src_layout.align.bytes().try_into().unwrap_or(128);
|
||||
let dst_align = dst_layout.align.bytes().try_into().unwrap_or(128);
|
||||
fx.bcx.emit_small_memory_copy(
|
||||
fx.target_config,
|
||||
to_addr,
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let layout = tcx
|
||||
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
|
||||
.unwrap();
|
||||
let align = layout.align.abi.bytes();
|
||||
let align = layout.align.bytes();
|
||||
// For types with size 1, the alignment can be 1 and only 1
|
||||
// So, we can skip the call to ``get_aligned`.
|
||||
// In the future, we can add a GCC API to query the type align,
|
||||
|
|
@ -186,9 +186,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
(i128_type, u128_type)
|
||||
} else {
|
||||
/*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap();
|
||||
let i128_align = layout.align.abi.bytes();
|
||||
let i128_align = layout.align.bytes();
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap();
|
||||
let u128_align = layout.align.abi.bytes();*/
|
||||
let u128_align = layout.align.bytes();*/
|
||||
|
||||
// TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in
|
||||
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
|
||||
|
|
|
|||
|
|
@ -184,6 +184,10 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
crate::DEFAULT_LOCALE_RESOURCE
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"gcc"
|
||||
}
|
||||
|
||||
fn init(&self, _sess: &Session) {
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ use rustc_ast::expand::allocator::{
|
|||
};
|
||||
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||
use rustc_span::sym;
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
|
||||
use crate::attributes::llfn_attrs_from_instance;
|
||||
|
|
@ -59,7 +60,26 @@ pub(crate) unsafe fn codegen(
|
|||
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
|
||||
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
|
||||
|
||||
create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false);
|
||||
let alloc_attr_flag = match method.name {
|
||||
sym::alloc => CodegenFnAttrFlags::ALLOCATOR,
|
||||
sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR,
|
||||
sym::realloc => CodegenFnAttrFlags::REALLOCATOR,
|
||||
sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED,
|
||||
_ => unreachable!("Unknown allocator method!"),
|
||||
};
|
||||
|
||||
let mut attrs = CodegenFnAttrs::new();
|
||||
attrs.flags |= alloc_attr_flag;
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
&cx,
|
||||
&from_name,
|
||||
Some(&to_name),
|
||||
&args,
|
||||
output,
|
||||
false,
|
||||
&attrs,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +92,7 @@ pub(crate) unsafe fn codegen(
|
|||
&[usize, usize], // size, align
|
||||
None,
|
||||
true,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
|
||||
unsafe {
|
||||
|
|
@ -93,6 +114,7 @@ pub(crate) unsafe fn codegen(
|
|||
&[],
|
||||
None,
|
||||
false,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +161,7 @@ fn create_wrapper_function(
|
|||
args: &[&Type],
|
||||
output: Option<&Type>,
|
||||
no_return: bool,
|
||||
attrs: &CodegenFnAttrs,
|
||||
) {
|
||||
let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
|
||||
let llfn = declare_simple_fn(
|
||||
|
|
@ -150,8 +173,7 @@ fn create_wrapper_function(
|
|||
ty,
|
||||
);
|
||||
|
||||
let attrs = CodegenFnAttrs::new();
|
||||
llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None);
|
||||
llfn_attrs_from_instance(cx, tcx, llfn, attrs, None);
|
||||
|
||||
let no_return = if no_return {
|
||||
// -> ! DIFlagNoReturn
|
||||
|
|
|
|||
|
|
@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
|
|||
|
||||
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
|
||||
|
||||
builder.store_to_place(call, dest.val);
|
||||
let fn_ret_ty = builder.cx.val_ty(call);
|
||||
if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) {
|
||||
// If we return void or an empty struct, then our caller (due to how we generated it)
|
||||
// does not expect a return value. As such, we have no pointer (or place) into which
|
||||
// we could store our value, and would store into an undef, which would cause UB.
|
||||
// As such, we just ignore the return value in those cases.
|
||||
builder.store_to_place(call, dest.val);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi);
|
||||
set_global_alignment(self, g, self.tcx.data_layout.i8_align);
|
||||
llvm::set_initializer(g, llval);
|
||||
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(g, c"__TEXT,__cstring,cstring_literals");
|
||||
|
|
@ -680,7 +680,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", methname_sym);
|
||||
});
|
||||
set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi);
|
||||
set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align);
|
||||
llvm::set_initializer(methname_g, methname_llval);
|
||||
llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use smallvec::SmallVec;
|
|||
use crate::back::write::to_llvm_code_model;
|
||||
use crate::callee::get_fn;
|
||||
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
|
||||
use crate::llvm::Metadata;
|
||||
use crate::llvm::{Metadata, MetadataKindId};
|
||||
use crate::type_::Type;
|
||||
use crate::value::Value;
|
||||
use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util};
|
||||
|
|
@ -1006,11 +1006,11 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
pub(crate) fn set_metadata<'a>(
|
||||
&self,
|
||||
val: &'a Value,
|
||||
kind_id: impl Into<llvm::MetadataKindId>,
|
||||
kind_id: MetadataKindId,
|
||||
md: &'ll Metadata,
|
||||
) {
|
||||
let node = self.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(val, kind_id.into(), node);
|
||||
llvm::LLVMSetMetadata(val, kind_id, node);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,26 +2,25 @@
|
|||
|
||||
use std::ffi::CString;
|
||||
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::coverageinfo::ffi;
|
||||
use crate::llvm;
|
||||
|
||||
pub(crate) fn covmap_var_name() -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovmapVarNameToString(s);
|
||||
}))
|
||||
.expect("covmap variable name should not contain NUL")
|
||||
}
|
||||
|
||||
pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s);
|
||||
}))
|
||||
.expect("covmap section name should not contain NUL")
|
||||
}
|
||||
|
||||
pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s);
|
||||
}))
|
||||
.expect("covfun section name should not contain NUL")
|
||||
|
|
@ -34,7 +33,7 @@ pub(crate) fn create_pgo_func_name_var<'ll>(
|
|||
unsafe {
|
||||
llvm::LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
llfn,
|
||||
mangled_fn_name.as_c_char_ptr(),
|
||||
mangled_fn_name.as_ptr(),
|
||||
mangled_fn_name.len(),
|
||||
)
|
||||
}
|
||||
|
|
@ -44,7 +43,7 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8
|
|||
let (pointers, lengths) = filenames
|
||||
.into_iter()
|
||||
.map(AsRef::as_ref)
|
||||
.map(|s: &str| (s.as_c_char_ptr(), s.len()))
|
||||
.map(|s: &str| (s.as_ptr(), s.len()))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
|
||||
llvm::build_byte_buffer(|buffer| unsafe {
|
||||
|
|
@ -89,12 +88,12 @@ pub(crate) fn write_function_mappings_to_buffer(
|
|||
/// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`,
|
||||
/// as required for parts of the LLVM coverage mapping format.
|
||||
pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
|
||||
unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) }
|
||||
unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_ptr(), bytes.len()) }
|
||||
}
|
||||
|
||||
/// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h)
|
||||
/// as a raw numeric value. For historical reasons, the numeric value is 1 less
|
||||
/// than the number in the version's name, so `Version7` is actually `6u32`.
|
||||
pub(crate) fn mapping_version() -> u32 {
|
||||
unsafe { llvm::LLVMRustCoverageMappingVersion() }
|
||||
llvm::LLVMRustCoverageMappingVersion()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1043,7 +1043,7 @@ fn create_member_type<'ll, 'tcx>(
|
|||
file_metadata,
|
||||
line_number,
|
||||
layout.size.bits(),
|
||||
layout.align.abi.bits() as u32,
|
||||
layout.align.bits() as u32,
|
||||
offset.bits(),
|
||||
flags,
|
||||
type_di_node,
|
||||
|
|
@ -1611,16 +1611,12 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
vtable,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()),
|
||||
);
|
||||
let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
|
||||
let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
vtable,
|
||||
llvm::MetadataType::MD_vcall_visibility as c_uint,
|
||||
vcall_visibility_metadata,
|
||||
);
|
||||
llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
|
|||
file_metadata,
|
||||
line_number,
|
||||
enum_type_and_layout.size.bits(),
|
||||
enum_type_and_layout.align.abi.bits() as u32,
|
||||
enum_type_and_layout.align.bits() as u32,
|
||||
DIFlags::FlagZero,
|
||||
tag_member_di_node,
|
||||
create_DIArray(DIB(cx), &[]),
|
||||
|
|
@ -449,7 +449,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
|
|||
file_di_node,
|
||||
line_number,
|
||||
enum_type_and_layout.size.bits(),
|
||||
enum_type_and_layout.align.abi.bits() as u32,
|
||||
enum_type_and_layout.align.bits() as u32,
|
||||
Size::ZERO.bits(),
|
||||
discr,
|
||||
DIFlags::FlagZero,
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
let align = if name == sym::unaligned_volatile_load {
|
||||
1
|
||||
} else {
|
||||
result.layout.align.abi.bytes() as u32
|
||||
result.layout.align.bytes() as u32
|
||||
};
|
||||
unsafe {
|
||||
llvm::LLVMSetAlignment(load, align);
|
||||
|
|
@ -1047,7 +1047,7 @@ fn codegen_emcc_try<'ll, 'tcx>(
|
|||
// create an alloca and pass a pointer to that.
|
||||
let ptr_size = bx.tcx().data_layout.pointer_size();
|
||||
let ptr_align = bx.tcx().data_layout.pointer_align().abi;
|
||||
let i8_align = bx.tcx().data_layout.i8_align.abi;
|
||||
let i8_align = bx.tcx().data_layout.i8_align;
|
||||
// Required in order for there to be no padding between the fields.
|
||||
assert!(i8_align <= ptr_align);
|
||||
let catch_data = bx.alloca(2 * ptr_size, ptr_align);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,10 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
crate::DEFAULT_LOCALE_RESOURCE
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"llvm"
|
||||
}
|
||||
|
||||
fn init(&self, sess: &Session) {
|
||||
llvm_util::init(sess); // Make sure llvm is inited
|
||||
}
|
||||
|
|
@ -350,7 +354,14 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
|
||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||
// This should produce either a finished executable or library.
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs);
|
||||
link_binary(
|
||||
sess,
|
||||
&LlvmArchiveBuilderBuilder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
outputs,
|
||||
self.name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use super::debuginfo::{
|
|||
DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
|
||||
};
|
||||
use crate::llvm;
|
||||
use crate::llvm::MetadataKindId;
|
||||
|
||||
/// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`,
|
||||
/// which has a different ABI from Rust or C++ `bool`.
|
||||
|
|
@ -513,31 +514,6 @@ pub(crate) enum FileType {
|
|||
ObjectFile,
|
||||
}
|
||||
|
||||
/// LLVMMetadataType
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")]
|
||||
pub(crate) enum MetadataType {
|
||||
MD_dbg = 0,
|
||||
MD_tbaa = 1,
|
||||
MD_prof = 2,
|
||||
MD_fpmath = 3,
|
||||
MD_range = 4,
|
||||
MD_tbaa_struct = 5,
|
||||
MD_invariant_load = 6,
|
||||
MD_alias_scope = 7,
|
||||
MD_noalias = 8,
|
||||
MD_nontemporal = 9,
|
||||
MD_mem_parallel_loop_access = 10,
|
||||
MD_nonnull = 11,
|
||||
MD_unpredictable = 15,
|
||||
MD_align = 17,
|
||||
MD_type = 19,
|
||||
MD_vcall_visibility = 28,
|
||||
MD_noundef = 29,
|
||||
MD_kcfi_type = 36,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMInlineAsmDialect`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
|
|
@ -1035,16 +1011,6 @@ pub(crate) type GetSymbolsCallback =
|
|||
unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
|
||||
pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct MetadataKindId(c_uint);
|
||||
|
||||
impl From<MetadataType> for MetadataKindId {
|
||||
fn from(value: MetadataType) -> Self {
|
||||
Self(value as c_uint)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
// Create and destroy contexts.
|
||||
pub(crate) fn LLVMContextDispose(C: &'static mut Context);
|
||||
|
|
@ -1139,7 +1105,11 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
|
||||
pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
|
||||
pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value);
|
||||
pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
|
||||
pub(crate) fn LLVMGlobalSetMetadata<'a>(
|
||||
Val: &'a Value,
|
||||
KindID: MetadataKindId,
|
||||
Metadata: &'a Metadata,
|
||||
);
|
||||
pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
|
||||
|
||||
// Operations on constants of any type
|
||||
|
|
@ -2059,7 +2029,7 @@ unsafe extern "C" {
|
|||
// Operations on all values
|
||||
pub(crate) fn LLVMRustGlobalAddMetadata<'a>(
|
||||
Val: &'a Value,
|
||||
KindID: c_uint,
|
||||
KindID: MetadataKindId,
|
||||
Metadata: &'a Metadata,
|
||||
);
|
||||
pub(crate) fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;
|
||||
|
|
@ -2256,8 +2226,11 @@ unsafe extern "C" {
|
|||
ConstraintsLen: size_t,
|
||||
) -> bool;
|
||||
|
||||
/// A list of pointer-length strings is passed as two pointer-length slices,
|
||||
/// one slice containing pointers and one slice containing their corresponding
|
||||
/// lengths. The implementation will check that both slices have the same length.
|
||||
pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer(
|
||||
Filenames: *const *const c_char,
|
||||
Filenames: *const *const c_uchar, // See "PTR_LEN_STR".
|
||||
FilenamesLen: size_t,
|
||||
Lengths: *const size_t,
|
||||
LengthsLen: size_t,
|
||||
|
|
@ -2280,18 +2253,25 @@ unsafe extern "C" {
|
|||
|
||||
pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
F: &Value,
|
||||
FuncName: *const c_char,
|
||||
FuncName: *const c_uchar, // See "PTR_LEN_STR".
|
||||
FuncNameLen: size_t,
|
||||
) -> &Value;
|
||||
pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
pub(crate) fn LLVMRustCoverageHashBytes(
|
||||
Bytes: *const c_uchar, // See "PTR_LEN_STR".
|
||||
NumBytes: size_t,
|
||||
) -> u64;
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovmapSectionNameToString(
|
||||
M: &Module,
|
||||
OutStr: &RustString,
|
||||
);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovfunSectionNameToString(
|
||||
M: &Module,
|
||||
OutStr: &RustString,
|
||||
);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub(crate) safe fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub(crate) fn LLVMRustDebugMetadataVersion() -> u32;
|
||||
pub(crate) fn LLVMRustVersionMajor() -> u32;
|
||||
pub(crate) fn LLVMRustVersionMinor() -> u32;
|
||||
|
|
|
|||
71
compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs
Normal file
71
compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use libc::c_uint;
|
||||
|
||||
pub(crate) use self::fixed_kinds::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct MetadataKindId(c_uint);
|
||||
|
||||
macro_rules! declare_fixed_metadata_kinds {
|
||||
(
|
||||
$(
|
||||
FIXED_MD_KIND($variant:ident, $value:literal)
|
||||
)*
|
||||
) => {
|
||||
// Use a submodule to group all declarations into one `#[expect(..)]`.
|
||||
#[expect(dead_code)]
|
||||
mod fixed_kinds {
|
||||
use super::MetadataKindId;
|
||||
$(
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub(crate) const $variant: MetadataKindId = MetadataKindId($value);
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Must be kept in sync with the corresponding static assertions in `RustWrapper.cpp`.
|
||||
declare_fixed_metadata_kinds! {
|
||||
FIXED_MD_KIND(MD_dbg, 0)
|
||||
FIXED_MD_KIND(MD_tbaa, 1)
|
||||
FIXED_MD_KIND(MD_prof, 2)
|
||||
FIXED_MD_KIND(MD_fpmath, 3)
|
||||
FIXED_MD_KIND(MD_range, 4)
|
||||
FIXED_MD_KIND(MD_tbaa_struct, 5)
|
||||
FIXED_MD_KIND(MD_invariant_load, 6)
|
||||
FIXED_MD_KIND(MD_alias_scope, 7)
|
||||
FIXED_MD_KIND(MD_noalias, 8)
|
||||
FIXED_MD_KIND(MD_nontemporal, 9)
|
||||
FIXED_MD_KIND(MD_mem_parallel_loop_access, 10)
|
||||
FIXED_MD_KIND(MD_nonnull, 11)
|
||||
FIXED_MD_KIND(MD_dereferenceable, 12)
|
||||
FIXED_MD_KIND(MD_dereferenceable_or_null, 13)
|
||||
FIXED_MD_KIND(MD_make_implicit, 14)
|
||||
FIXED_MD_KIND(MD_unpredictable, 15)
|
||||
FIXED_MD_KIND(MD_invariant_group, 16)
|
||||
FIXED_MD_KIND(MD_align, 17)
|
||||
FIXED_MD_KIND(MD_loop, 18)
|
||||
FIXED_MD_KIND(MD_type, 19)
|
||||
FIXED_MD_KIND(MD_section_prefix, 20)
|
||||
FIXED_MD_KIND(MD_absolute_symbol, 21)
|
||||
FIXED_MD_KIND(MD_associated, 22)
|
||||
FIXED_MD_KIND(MD_callees, 23)
|
||||
FIXED_MD_KIND(MD_irr_loop, 24)
|
||||
FIXED_MD_KIND(MD_access_group, 25)
|
||||
FIXED_MD_KIND(MD_callback, 26)
|
||||
FIXED_MD_KIND(MD_preserve_access_index, 27)
|
||||
FIXED_MD_KIND(MD_vcall_visibility, 28)
|
||||
FIXED_MD_KIND(MD_noundef, 29)
|
||||
FIXED_MD_KIND(MD_annotation, 30)
|
||||
FIXED_MD_KIND(MD_nosanitize, 31)
|
||||
FIXED_MD_KIND(MD_func_sanitize, 32)
|
||||
FIXED_MD_KIND(MD_exclude, 33)
|
||||
FIXED_MD_KIND(MD_memprof, 34)
|
||||
FIXED_MD_KIND(MD_callsite, 35)
|
||||
FIXED_MD_KIND(MD_kcfi_type, 36)
|
||||
FIXED_MD_KIND(MD_pcsections, 37)
|
||||
FIXED_MD_KIND(MD_DIAssignID, 38)
|
||||
FIXED_MD_KIND(MD_coro_outside_frame, 39)
|
||||
FIXED_MD_KIND(MD_mmra, 40)
|
||||
FIXED_MD_KIND(MD_noalias_addrspace, 41)
|
||||
}
|
||||
|
|
@ -11,13 +11,14 @@ use rustc_llvm::RustString;
|
|||
|
||||
pub(crate) use self::CallConv::*;
|
||||
pub(crate) use self::CodeGenOptSize::*;
|
||||
pub(crate) use self::MetadataType::*;
|
||||
pub(crate) use self::ffi::*;
|
||||
pub(crate) use self::metadata_kind::*;
|
||||
use crate::common::AsCCharPtr;
|
||||
|
||||
pub(crate) mod diagnostic;
|
||||
pub(crate) mod enzyme_ffi;
|
||||
mod ffi;
|
||||
mod metadata_kind;
|
||||
|
||||
pub(crate) use self::enzyme_ffi::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
|
|
@ -318,7 +318,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
|
|
@ -333,7 +333,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
unsafe {
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type as c_uint,
|
||||
llvm::MD_kcfi_type,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
|
|
@ -348,7 +348,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
unsafe {
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type as c_uint,
|
||||
llvm::MD_kcfi_type,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
|
|||
// the offset again.
|
||||
|
||||
bx.switch_to_block(maybe_reg);
|
||||
if gr_type && layout.align.abi.bytes() > 8 {
|
||||
if gr_type && layout.align.bytes() > 8 {
|
||||
reg_off_v = bx.add(reg_off_v, bx.const_i32(15));
|
||||
reg_off_v = bx.and(reg_off_v, bx.const_i32(-16));
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
|
|||
bx.inbounds_ptradd(va_list_addr, bx.const_usize(1)) // fpr
|
||||
};
|
||||
|
||||
let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align.abi);
|
||||
let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align);
|
||||
|
||||
// "Align" the register count when the type is passed as `i64`.
|
||||
if is_i64 || (is_f64 && is_soft_float_abi) {
|
||||
|
|
@ -329,7 +329,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
|
|||
// Increase the used-register count.
|
||||
let reg_incr = if is_i64 || (is_f64 && is_soft_float_abi) { 2 } else { 1 };
|
||||
let new_num_regs = bx.add(num_regs, bx.cx.const_u8(reg_incr));
|
||||
bx.store(new_num_regs, num_regs_addr, dl.i8_align.abi);
|
||||
bx.store(new_num_regs, num_regs_addr, dl.i8_align);
|
||||
|
||||
bx.br(end);
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
|
|||
let mem_addr = {
|
||||
bx.switch_to_block(in_mem);
|
||||
|
||||
bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align.abi);
|
||||
bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align);
|
||||
|
||||
// Everything in the overflow area is rounded up to a size of at least 4.
|
||||
let overflow_area_align = Align::from_bytes(4).unwrap();
|
||||
|
|
@ -761,7 +761,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
|
|||
// byte boundary if alignment needed by type exceeds 8 byte boundary.
|
||||
// It isn't stated explicitly in the standard, but in practice we use
|
||||
// alignment greater than 16 where necessary.
|
||||
if layout.layout.align.abi.bytes() > 8 {
|
||||
if layout.layout.align.bytes() > 8 {
|
||||
unreachable!("all instances of VaArgSafe have an alignment <= 8");
|
||||
}
|
||||
|
||||
|
|
@ -814,7 +814,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
|
|||
let va_ndx_offset = va_reg_offset + 4;
|
||||
let offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_ndx_offset));
|
||||
|
||||
let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi);
|
||||
let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align);
|
||||
let offset = round_up_to_alignment(bx, offset, layout.align.abi);
|
||||
|
||||
let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ pub fn link_binary(
|
|||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
codegen_backend: &'static str,
|
||||
) {
|
||||
let _timer = sess.timer("link_binary");
|
||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||
|
|
@ -154,6 +155,7 @@ pub fn link_binary(
|
|||
&codegen_results,
|
||||
&metadata,
|
||||
path.as_ref(),
|
||||
codegen_backend,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -680,6 +682,7 @@ fn link_natively(
|
|||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
tmpdir: &Path,
|
||||
codegen_backend: &'static str,
|
||||
) {
|
||||
info!("preparing {:?} to {:?}", crate_type, out_filename);
|
||||
let (linker_path, flavor) = linker_and_flavor(sess);
|
||||
|
|
@ -705,6 +708,7 @@ fn link_natively(
|
|||
codegen_results,
|
||||
metadata,
|
||||
self_contained_components,
|
||||
codegen_backend,
|
||||
);
|
||||
|
||||
linker::disable_localization(&mut cmd);
|
||||
|
|
@ -2208,6 +2212,7 @@ fn linker_with_args(
|
|||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
codegen_backend: &'static str,
|
||||
) -> Command {
|
||||
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
|
||||
let cmd = &mut *super::linker::get_linker(
|
||||
|
|
@ -2216,6 +2221,7 @@ fn linker_with_args(
|
|||
flavor,
|
||||
self_contained_components.are_any_components_enabled(),
|
||||
&codegen_results.crate_info.target_cpu,
|
||||
codegen_backend,
|
||||
);
|
||||
let link_output_kind = link_output_kind(sess, crate_type);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ pub(crate) fn get_linker<'a>(
|
|||
flavor: LinkerFlavor,
|
||||
self_contained: bool,
|
||||
target_cpu: &'a str,
|
||||
codegen_backend: &'static str,
|
||||
) -> Box<dyn Linker + 'a> {
|
||||
let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe");
|
||||
|
||||
|
|
@ -154,6 +155,7 @@ pub(crate) fn get_linker<'a>(
|
|||
is_ld: cc == Cc::No,
|
||||
is_gnu: flavor.is_gnu(),
|
||||
uses_lld: flavor.uses_lld(),
|
||||
codegen_backend,
|
||||
}) as Box<dyn Linker>,
|
||||
LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
|
||||
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
|
||||
|
|
@ -367,6 +369,7 @@ struct GccLinker<'a> {
|
|||
is_ld: bool,
|
||||
is_gnu: bool,
|
||||
uses_lld: bool,
|
||||
codegen_backend: &'static str,
|
||||
}
|
||||
|
||||
impl<'a> GccLinker<'a> {
|
||||
|
|
@ -423,9 +426,15 @@ impl<'a> GccLinker<'a> {
|
|||
if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
|
||||
self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
|
||||
};
|
||||
let prefix = if self.codegen_backend == "gcc" {
|
||||
// The GCC linker plugin requires a leading dash.
|
||||
"-"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
self.link_args(&[
|
||||
&format!("-plugin-opt={opt_level}"),
|
||||
&format!("-plugin-opt=mcpu={}", self.target_cpu),
|
||||
&format!("-plugin-opt={prefix}{opt_level}"),
|
||||
&format!("-plugin-opt={prefix}mcpu={}", self.target_cpu),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
mir::NullOp::AlignOf => {
|
||||
assert!(bx.cx().type_is_sized(ty));
|
||||
let val = layout.align.abi.bytes();
|
||||
let val = layout.align.bytes();
|
||||
bx.cx().const_usize(val)
|
||||
}
|
||||
mir::NullOp::OffsetOf(fields) => {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout);
|
||||
if layout.is_sized() {
|
||||
let size = bx.const_usize(layout.size.bytes());
|
||||
let align = bx.const_usize(layout.align.abi.bytes());
|
||||
let align = bx.const_usize(layout.align.bytes());
|
||||
return (size, align);
|
||||
}
|
||||
match t.kind() {
|
||||
|
|
@ -49,7 +49,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// All slice sizes must fit into `isize`, so this multiplication cannot
|
||||
// wrap -- neither signed nor unsigned.
|
||||
bx.unchecked_sumul(info.unwrap(), bx.const_usize(unit.size.bytes())),
|
||||
bx.const_usize(unit.align.abi.bytes()),
|
||||
bx.const_usize(unit.align.bytes()),
|
||||
)
|
||||
}
|
||||
ty::Foreign(_) => {
|
||||
|
|
@ -82,7 +82,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
|
||||
// This function does not return so we can now return whatever we want.
|
||||
let size = bx.const_usize(layout.size.bytes());
|
||||
let align = bx.const_usize(layout.align.abi.bytes());
|
||||
let align = bx.const_usize(layout.align.bytes());
|
||||
(size, align)
|
||||
}
|
||||
ty::Adt(..) | ty::Tuple(..) => {
|
||||
|
|
@ -94,7 +94,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
|
||||
let i = layout.fields.count() - 1;
|
||||
let unsized_offset_unadjusted = layout.fields.offset(i).bytes();
|
||||
let sized_align = layout.align.abi.bytes();
|
||||
let sized_align = layout.align.bytes();
|
||||
debug!(
|
||||
"DST {} offset of dyn field: {}, statically sized align: {}",
|
||||
t, unsized_offset_unadjusted, sized_align
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ pub trait CodegenBackend {
|
|||
/// Called before `init` so that all other functions are able to emit translatable diagnostics.
|
||||
fn locale_resource(&self) -> &'static str;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn init(&self, _sess: &Session) {}
|
||||
|
||||
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
||||
|
|
@ -96,7 +98,14 @@ pub trait CodegenBackend {
|
|||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs);
|
||||
link_binary(
|
||||
sess,
|
||||
&ArArchiveBuilderBuilder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
outputs,
|
||||
self.name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
if !layout.is_sized() {
|
||||
span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
|
||||
}
|
||||
let val = layout.align.abi.bytes();
|
||||
let val = layout.align.bytes();
|
||||
ImmTy::from_uint(val, usize_layout())
|
||||
}
|
||||
OffsetOf(fields) => {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ where
|
|||
debug!(
|
||||
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
|
||||
place,
|
||||
layout.align.abi.bytes(),
|
||||
layout.align.bytes(),
|
||||
pack.bytes()
|
||||
);
|
||||
false
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ fn check_validity_requirement_lax<'tcx>(
|
|||
if let Some(pointee) = this.ty.builtin_deref(false) {
|
||||
let pointee = cx.layout_of(pointee)?;
|
||||
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
|
||||
if pointee.align.abi.bytes() > 1 {
|
||||
if pointee.align.bytes() > 1 {
|
||||
// 0x01-filling is not aligned.
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
An associated type value was specified more than once.
|
||||
An associated item was specified more than once in a trait object.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -7,21 +7,15 @@ trait FooTrait {}
|
|||
trait BarTrait {}
|
||||
|
||||
// error: associated type `Item` in trait `Iterator` is specified twice
|
||||
struct Foo<T: Iterator<Item: FooTrait, Item: BarTrait>> { f: T }
|
||||
type Foo = dyn Iterator<Item = u32, Item = u32>;
|
||||
```
|
||||
|
||||
`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`.
|
||||
To fix this, create a new trait that is a combination of the desired traits and
|
||||
specify the associated type with the new trait.
|
||||
To fix this, remove the duplicate specifier:
|
||||
|
||||
Corrected example:
|
||||
|
||||
```
|
||||
trait FooTrait {}
|
||||
trait BarTrait {}
|
||||
trait FooBarTrait: FooTrait + BarTrait {}
|
||||
|
||||
struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok!
|
||||
type Foo = dyn Iterator<Item = u32>; // ok!
|
||||
```
|
||||
|
||||
For more information about associated types, see [the book][bk-at]. For more
|
||||
|
|
|
|||
|
|
@ -210,8 +210,7 @@ pub(super) fn check_meta_variables(
|
|||
guar.map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
/// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and
|
||||
/// sets `valid` to false in case of errors.
|
||||
/// Checks `lhs` as part of the LHS of a macro definition.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -306,8 +305,7 @@ fn get_binder_info<'a>(
|
|||
binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name)))
|
||||
}
|
||||
|
||||
/// Checks `rhs` as part of the RHS of a macro definition and sets `valid` to false in case of
|
||||
/// errors.
|
||||
/// Checks `rhs` as part of the RHS of a macro definition.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -372,7 +370,7 @@ enum NestedMacroState {
|
|||
}
|
||||
|
||||
/// Checks `tts` as part of the RHS of a macro definition, tries to recognize nested macro
|
||||
/// definitions, and sets `valid` to false in case of errors.
|
||||
/// definitions.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -491,8 +489,7 @@ fn check_nested_occurrences(
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks the body of nested macro, returns where the check stopped, and sets `valid` to false in
|
||||
/// case of errors.
|
||||
/// Checks the body of nested macro, returns where the check stopped.
|
||||
///
|
||||
/// The token trees are checked as long as they look like a list of (LHS) => {RHS} token trees. This
|
||||
/// check is a best-effort to detect a macro definition. It returns the position in `tts` where we
|
||||
|
|
|
|||
|
|
@ -102,9 +102,9 @@ declare_features! (
|
|||
/// Allows deriving traits as per `SmartPointer` specification
|
||||
(removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
(removed, doc_auto_cfg, "1.58.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
(removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
/// Allows `#[doc(cfg_hide(...))]`.
|
||||
(removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
(removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
/// Allows using `#[doc(keyword = "...")]`.
|
||||
(removed, doc_keyword, "1.58.0", Some(51315),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
|
||||
|
|
|
|||
|
|
@ -1298,10 +1298,7 @@ impl AttributeExt for Attribute {
|
|||
#[inline]
|
||||
fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
match &self {
|
||||
Attribute::Unparsed(n) => {
|
||||
n.path.segments.len() == name.len()
|
||||
&& n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n)
|
||||
}
|
||||
Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ pub struct AttributeLint<Id> {
|
|||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum AttributeLintKind {
|
||||
/// Copy of `IllFormedAttributeInput`
|
||||
/// specifically for the `invalid_macro_export_arguments` lint until that is removed,
|
||||
/// see <https://github.com/rust-lang/rust/pull/143857#issuecomment-3079175663>
|
||||
InvalidMacroExportArguments {
|
||||
suggestions: Vec<String>,
|
||||
},
|
||||
UnusedDuplicate {
|
||||
this: Span,
|
||||
other: Span,
|
||||
|
|
@ -41,13 +47,8 @@ pub enum AttributeLintKind {
|
|||
},
|
||||
EmptyAttribute {
|
||||
first_span: Span,
|
||||
},
|
||||
|
||||
/// Copy of `IllFormedAttributeInput`
|
||||
/// specifically for the `invalid_macro_export_arguments` lint until that is removed,
|
||||
/// see <https://github.com/rust-lang/rust/pull/143857#issuecomment-3079175663>
|
||||
InvalidMacroExportArguments {
|
||||
suggestions: Vec<String>,
|
||||
attr_path: AttrPath,
|
||||
valid_without_list: bool,
|
||||
},
|
||||
InvalidTarget {
|
||||
name: AttrPath,
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
|
||||
// `async-std` (and `pub async fn` in general).
|
||||
// Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
|
||||
// Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it!
|
||||
// See https://github.com/rust-lang/rust/issues/75100
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
return;
|
||||
|
|
@ -252,7 +252,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
|
||||
/// Check that the hidden type behind `impl Trait` actually implements `Trait`.
|
||||
///
|
||||
/// This is mostly checked at the places that specify the opaque type, but we
|
||||
/// check those cases in the `param_env` of that function, which may have
|
||||
|
|
|
|||
|
|
@ -195,11 +195,10 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Alias(ty::Free, _)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
| ty::CoroutineWitness(..) => {
|
||||
Err(self.tcx.dcx().delayed_bug("cannot define inherent `impl` for closure types"))
|
||||
}
|
||||
ty::Alias(ty::Free, _) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
|
||||
}
|
||||
// We could bail out here, but that will silence other useful errors.
|
||||
|
|
|
|||
|
|
@ -230,10 +230,12 @@ pub(crate) fn orphan_check_impl(
|
|||
ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(..) => {
|
||||
| ty::CoroutineWitness(..) => {
|
||||
return Err(tcx
|
||||
.dcx()
|
||||
.delayed_bug("cannot define inherent `impl` for closure types"));
|
||||
}
|
||||
ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
|
||||
let sp = tcx.def_span(impl_def_id);
|
||||
span_bug!(sp, "weird self type for autotrait impl")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1140,7 +1140,7 @@ fn recover_infer_ret_ty<'tcx>(
|
|||
// recursive function definition to leak out into the fn sig.
|
||||
let mut recovered_ret_ty = None;
|
||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
infer_ret_ty.span,
|
||||
"replace with the correct return type",
|
||||
suggestable_ret_ty,
|
||||
|
|
@ -1152,7 +1152,7 @@ fn recover_infer_ret_ty<'tcx>(
|
|||
tcx.param_env(def_id),
|
||||
ret_ty,
|
||||
) {
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
infer_ret_ty.span,
|
||||
"replace with an appropriate return type",
|
||||
sugg,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use super::ItemCtxt;
|
||||
use super::predicates_of::assert_only_contains_predicates_from;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter};
|
||||
|
||||
/// For associated types we include both bounds written on the type
|
||||
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
|
||||
|
|
@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>(
|
|||
|
||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
|
|
@ -347,7 +354,14 @@ fn opaque_type_bounds<'tcx>(
|
|||
ty::print::with_reduced_queries!({
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
// Implicit bounds are added to opaque types unless a `?Trait` bound is found
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter;
|
|||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::delegation::inherit_predicates_for_delegation_item;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
|
||||
|
|
@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
icx.lowerer().add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
|
|
@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
|
|
@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
|||
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
self_param_ty,
|
||||
superbounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
|
|
@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>(
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>(
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
|
|||
let tables = tcx.typeck(item_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
|
||||
} else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) {
|
||||
} else if let Some(&hidden_type) = tables.hidden_types.get(&self.def_id) {
|
||||
self.insert_found(hidden_type);
|
||||
} else {
|
||||
self.non_defining_use_in_defining_scope(item_def_id);
|
||||
|
|
@ -185,8 +185,8 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
|
|||
}
|
||||
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) {
|
||||
Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)),
|
||||
Ok(concrete_opaque_types) => {
|
||||
if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) {
|
||||
Ok(hidden_types) => {
|
||||
if let Some(&hidden_type) = hidden_types.0.get(&self.def_id) {
|
||||
debug!(?hidden_type, "found constraint");
|
||||
self.insert_found(hidden_type);
|
||||
} else if let Err(guar) = tcx
|
||||
|
|
@ -247,7 +247,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
let tables = tcx.typeck(owner_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
|
||||
} else if let Some(hidden_ty) = tables.hidden_types.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
assert!(!tcx.next_trait_solver_globally());
|
||||
|
|
@ -261,8 +261,8 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
}
|
||||
}
|
||||
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
|
||||
Ok(concrete_opaque_types) => {
|
||||
if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) {
|
||||
Ok(hidden_types) => {
|
||||
if let Some(hidden_ty) = hidden_types.0.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeV
|
|||
use rustc_span::Span;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub(crate) struct Parameter(pub u32);
|
||||
|
||||
impl From<ty::ParamTy> for Parameter {
|
||||
|
|
@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
|
|||
// which is `O(nt)` where `t` is the depth of type-parameter constraints,
|
||||
// remembering that `t` should be less than 7 in practice.
|
||||
//
|
||||
// FIXME(hkBst): the big-O bound above would be accurate for the number
|
||||
// of calls to `parameters_for`, which itself is some O(complexity of type).
|
||||
// That would make this potentially cubic instead of merely quadratic...
|
||||
// ...unless we cache those `parameters_for` calls.
|
||||
//
|
||||
// Basically, I iterate over all projections and swap every
|
||||
// "ready" projection to the start of the list, such that
|
||||
// all of the projections before `i` are topologically sorted
|
||||
// and constrain all the parameters in `input_parameters`.
|
||||
//
|
||||
// In the example, `input_parameters` starts by containing `U` - which
|
||||
// is constrained by the trait-ref - and so on the first pass we
|
||||
// In the first example, `input_parameters` starts by containing `U`,
|
||||
// which is constrained by the self type `U`. Then, on the first pass we
|
||||
// observe that `<U as Iterator>::Item = T` is a "ready" projection that
|
||||
// constrains `T` and swap it to front. As it is the sole projection,
|
||||
// constrains `T` and swap it to the front. As it is the sole projection,
|
||||
// no more swaps can take place afterwards, with the result being
|
||||
// * <U as Iterator>::Item = T
|
||||
// * T: Debug
|
||||
|
|
@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
|
|||
for j in i..predicates.len() {
|
||||
// Note that we don't have to care about binders here,
|
||||
// as the impl trait ref never contains any late-bound regions.
|
||||
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
|
||||
// Special case: watch out for some kind of sneaky attempt
|
||||
// to project out an associated type defined by this very
|
||||
// trait.
|
||||
let unbound_trait_ref = projection.projection_term.trait_ref(tcx);
|
||||
if Some(unbound_trait_ref) == impl_trait_ref {
|
||||
continue;
|
||||
}
|
||||
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() &&
|
||||
|
||||
// A projection depends on its input types and determines its output
|
||||
// type. For example, if we have
|
||||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||
// Then the projection only applies if `T` is known, but it still
|
||||
// does not determine `U`.
|
||||
let inputs = parameters_for(tcx, projection.projection_term, true);
|
||||
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
|
||||
if !relies_only_on_inputs {
|
||||
continue;
|
||||
}
|
||||
// Special case: watch out for some kind of sneaky attempt to
|
||||
// project out an associated type defined by this very trait.
|
||||
!impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) &&
|
||||
|
||||
// A projection depends on its input types and determines its output
|
||||
// type. For example, if we have
|
||||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||
// then the projection only applies if `T` is known, but it still
|
||||
// does not determine `U`.
|
||||
parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p))
|
||||
{
|
||||
input_parameters.extend(parameters_for(tcx, projection.term, false));
|
||||
} else {
|
||||
continue;
|
||||
|
||||
predicates.swap(i, j);
|
||||
i += 1;
|
||||
changed = true;
|
||||
}
|
||||
// fancy control flow to bypass borrow checker
|
||||
predicates.swap(i, j);
|
||||
i += 1;
|
||||
changed = true;
|
||||
}
|
||||
debug!(
|
||||
"setup_constraining_predicates: predicates={:?} \
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ use tracing::{debug, instrument};
|
|||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter,
|
||||
RegionInferReason,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -338,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_constraints: OverlappingAsssocItemConstraints,
|
||||
) where
|
||||
'tcx: 'hir,
|
||||
{
|
||||
|
|
@ -362,6 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
param_ty,
|
||||
bounds,
|
||||
predicate_filter,
|
||||
overlapping_assoc_constraints,
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
|
|
@ -402,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
constraint: &hir::AssocItemConstraint<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
duplicates: &mut FxIndexMap<DefId, Span>,
|
||||
duplicates: Option<&mut FxIndexMap<DefId, Span>>,
|
||||
path_span: Span,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
@ -458,17 +461,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
.expect("failed to find associated item");
|
||||
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
if let Some(duplicates) = duplicates {
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
}
|
||||
|
||||
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
|
||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||
|
|
@ -600,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
predicate_filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
PredicateFilter::SelfOnly
|
||||
|
|
|
|||
|
|
@ -134,11 +134,12 @@ fn is_valid_cmse_inputs<'tcx>(
|
|||
|
||||
// this type is only used for layout computation, which does not rely on regions
|
||||
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
||||
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
|
||||
|
||||
for (index, ty) in fn_sig.inputs().iter().enumerate() {
|
||||
let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
|
||||
|
||||
let align = layout.layout.align().abi.bytes();
|
||||
let align = layout.layout.align().bytes();
|
||||
let size = layout.layout.size().bytes();
|
||||
|
||||
accum += size;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ use tracing::{debug, instrument};
|
|||
|
||||
use super::HirTyLowerer;
|
||||
use crate::errors::SelfInTypeAlias;
|
||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Lower a trait object type from the HIR to our internal notion of a type.
|
||||
|
|
@ -60,6 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
dummy_self,
|
||||
&mut user_written_bounds,
|
||||
PredicateFilter::SelfOnly,
|
||||
OverlappingAsssocItemConstraints::Forbidden,
|
||||
);
|
||||
if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
|
||||
potential_assoc_types.extend(invalid_args);
|
||||
|
|
@ -157,10 +160,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!(
|
||||
"conflicting associated type bounds for `{item}` when \
|
||||
expanding trait alias"
|
||||
),
|
||||
format!("conflicting associated type bounds for `{item}`"),
|
||||
)
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
|
|
|
|||
|
|
@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition {
|
|||
MethodCall,
|
||||
}
|
||||
|
||||
/// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
|
||||
/// `Trait<Assoc = Ty, Assoc = Ty>`. This is forbidden in `dyn Trait<...>`
|
||||
/// but allowed everywhere else.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) enum OverlappingAsssocItemConstraints {
|
||||
Allowed,
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
/// A marker denoting that the generic arguments that were
|
||||
/// provided did not match the respective generic parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -752,6 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints,
|
||||
) -> GenericArgCountResult {
|
||||
let tcx = self.tcx();
|
||||
|
||||
|
|
@ -908,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
let mut dup_constraints = (overlapping_assoc_item_constraints
|
||||
== OverlappingAsssocItemConstraints::Forbidden)
|
||||
.then_some(FxIndexMap::default());
|
||||
|
||||
for constraint in trait_segment.args().constraints {
|
||||
// Don't register any associated item constraints for negative bounds,
|
||||
// since we should have emitted an error for them earlier, and they
|
||||
|
|
@ -927,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
poly_trait_ref,
|
||||
constraint,
|
||||
bounds,
|
||||
&mut dup_constraints,
|
||||
dup_constraints.as_mut(),
|
||||
constraint.span,
|
||||
predicate_filter,
|
||||
);
|
||||
|
|
@ -2484,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
self.add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ fn check_duplicate_params<'tcx>(
|
|||
span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let mut base_params = cgp::parameters_for(tcx, parent_args, true);
|
||||
base_params.sort_by_key(|param| param.0);
|
||||
base_params.sort_unstable();
|
||||
if let (_, [duplicate, ..]) = base_params.partition_dedup() {
|
||||
let param = impl1_args[duplicate.0 as usize];
|
||||
return Err(tcx
|
||||
|
|
|
|||
|
|
@ -611,19 +611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
typeck_results.rvalue_scopes = rvalue_scopes;
|
||||
}
|
||||
|
||||
/// Unify the inference variables corresponding to coroutine witnesses, and save all the
|
||||
/// predicates that were stalled on those inference variables.
|
||||
///
|
||||
/// This process allows to conservatively save all predicates that do depend on the coroutine
|
||||
/// interior types, for later processing by `check_coroutine_obligations`.
|
||||
///
|
||||
/// We must not attempt to select obligations after this method has run, or risk query cycle
|
||||
/// ICE.
|
||||
/// Drain all obligations that are stalled on coroutines defined in this body.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn resolve_coroutine_interiors(&self) {
|
||||
// Try selecting all obligations that are not blocked on inference variables.
|
||||
// Once we start unifying coroutine witnesses, trying to select obligations on them will
|
||||
// trigger query cycle ICEs, as doing so requires MIR.
|
||||
pub(crate) fn drain_stalled_coroutine_obligations(&self) {
|
||||
// Make as much inference progress as possible before
|
||||
// draining the stalled coroutine obligations as this may
|
||||
// change obligations from being stalled on infer vars to
|
||||
// being stalled on a coroutine.
|
||||
self.select_obligations_where_possible(|_| {});
|
||||
|
||||
let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
|
||||
|
|
|
|||
|
|
@ -2803,9 +2803,7 @@ impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> {
|
|||
if let Some((assoc, fn_sig)) = self.similar_assoc(call_name)
|
||||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(input_types.iter())
|
||||
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
.eq_by(input_types, |expected, found| self.may_coerce(*expected, found))
|
||||
{
|
||||
let assoc_name = assoc.name();
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(never_type)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
@ -242,18 +243,15 @@ fn typeck_with_inspect<'tcx>(
|
|||
|
||||
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
// This must be the last thing before `report_ambiguity_errors`.
|
||||
fcx.resolve_coroutine_interiors();
|
||||
|
||||
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
// We need to handle opaque types before emitting ambiguity errors as applying
|
||||
// defining uses may guide type inference.
|
||||
if fcx.next_trait_solver() {
|
||||
fcx.handle_opaque_type_uses_next();
|
||||
}
|
||||
|
||||
fcx.select_obligations_where_possible(|_| {});
|
||||
// This must be the last thing before `report_ambiguity_errors` below except `select_obligations_where_possible`.
|
||||
// So don't put anything after this.
|
||||
fcx.drain_stalled_coroutine_obligations();
|
||||
if fcx.infcx.tainted_by_errors().is_none() {
|
||||
fcx.report_ambiguity_errors();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1914,9 +1914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let Some(ref args) = call_args
|
||||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(args.into_iter())
|
||||
.all(|(expected, found)| self.may_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == args.len()
|
||||
.eq_by(args, |expected, found| self.may_coerce(*expected, *found))
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
item_name.span,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::FnCtxt;
|
|||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
/// This takes all the opaque type uses during HIR typeck. It first computes
|
||||
/// the concrete hidden type by iterating over all defining uses.
|
||||
/// the hidden type by iterating over all defining uses.
|
||||
///
|
||||
/// A use during HIR typeck is defining if all non-lifetime arguments are
|
||||
/// unique generic parameters and the hidden type does not reference any
|
||||
|
|
@ -35,8 +35,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
}
|
||||
debug!(?opaque_types);
|
||||
|
||||
self.compute_concrete_opaque_types(&opaque_types);
|
||||
self.apply_computed_concrete_opaque_types(&opaque_types);
|
||||
self.compute_definition_site_hidden_types(&opaque_types);
|
||||
self.apply_definition_site_hidden_types(&opaque_types);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ impl<'tcx> UsageKind<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
fn compute_concrete_opaque_types(
|
||||
fn compute_definition_site_hidden_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
|
|
@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
self.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
) {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => {
|
||||
self.typeck_results.borrow_mut().concrete_opaque_types.insert(
|
||||
self.typeck_results.borrow_mut().hidden_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(self.tcx, guar),
|
||||
);
|
||||
|
|
@ -197,20 +197,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
let prev = self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(opaque_type_key.def_id, hidden_type);
|
||||
assert!(prev.is_none());
|
||||
UsageKind::HasDefiningUse
|
||||
}
|
||||
|
||||
fn apply_computed_concrete_opaque_types(
|
||||
fn apply_definition_site_hidden_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
let expected =
|
||||
*self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
|
||||
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap();
|
||||
|
||||
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
|
||||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
|
||||
|
|
|
|||
|
|
@ -550,13 +550,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fn visit_opaque_types_next(&mut self) {
|
||||
let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() {
|
||||
for hidden_ty in fcx_typeck_results.hidden_types.values() {
|
||||
assert!(!hidden_ty.has_infer());
|
||||
}
|
||||
|
||||
assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0);
|
||||
self.typeck_results.concrete_opaque_types =
|
||||
mem::take(&mut fcx_typeck_results.concrete_opaque_types);
|
||||
assert_eq!(self.typeck_results.hidden_types.len(), 0);
|
||||
self.typeck_results.hidden_types = mem::take(&mut fcx_typeck_results.hidden_types);
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
|
@ -588,7 +587,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
hidden_type.span,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
) {
|
||||
self.typeck_results.concrete_opaque_types.insert(
|
||||
self.typeck_results.hidden_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)),
|
||||
);
|
||||
|
|
@ -600,16 +599,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
DefiningScopeKind::HirTypeck,
|
||||
);
|
||||
|
||||
if let Some(prev) = self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.insert(opaque_type_key.def_id, hidden_type)
|
||||
if let Some(prev) =
|
||||
self.typeck_results.hidden_types.insert(opaque_type_key.def_id, hidden_type)
|
||||
{
|
||||
let entry = &mut self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.get_mut(&opaque_type_key.def_id)
|
||||
.unwrap();
|
||||
let entry =
|
||||
&mut self.typeck_results.hidden_types.get_mut(&opaque_type_key.def_id).unwrap();
|
||||
if prev.ty != hidden_type.ty {
|
||||
if let Some(guar) = self.typeck_results.tainted_by_errors {
|
||||
entry.ty = Ty::new_error(tcx, guar);
|
||||
|
|
@ -628,7 +622,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
|
||||
let recursive_opaques: Vec<_> = self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.iter()
|
||||
.filter(|&(&def_id, hidden_ty)| {
|
||||
hidden_ty
|
||||
|
|
@ -636,7 +630,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
.visit_with(&mut HasRecursiveOpaque {
|
||||
def_id,
|
||||
seen: Default::default(),
|
||||
opaques: &self.typeck_results.concrete_opaque_types,
|
||||
opaques: &self.typeck_results.hidden_types,
|
||||
tcx,
|
||||
})
|
||||
.is_break()
|
||||
|
|
@ -651,7 +645,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
.with_code(E0720)
|
||||
.emit();
|
||||
self.typeck_results
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> {
|
|||
/// `$0: 'static`. This will get checked later by regionck. (We
|
||||
/// can't generally check these things right away because we have
|
||||
/// to wait until types are resolved.)
|
||||
///
|
||||
/// These are stored in a map keyed to the id of the innermost
|
||||
/// enclosing fn body / static initializer expression. This is
|
||||
/// because the location where the obligation was incurred can be
|
||||
/// relevant with respect to which sublifetime assumptions are in
|
||||
/// place. The reason that we store under the fn-id, and not
|
||||
/// something more fine-grained, is so that it is easier for
|
||||
/// regionck to be sure that it has found *all* the region
|
||||
/// obligations (otherwise, it's easy to fail to walk to a
|
||||
/// particular node-id).
|
||||
///
|
||||
/// Before running `resolve_regions_and_report_errors`, the creator
|
||||
/// of the inference context is expected to invoke
|
||||
/// [`InferCtxt::process_registered_region_obligations`]
|
||||
/// for each body-id in this map, which will process the
|
||||
/// obligations within. This is expected to be done 'late enough'
|
||||
/// that all type inference variables have been bound and so forth.
|
||||
region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
|
||||
|
||||
/// The outlives bounds that we assume must hold about placeholders that
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
|
||||
}
|
||||
|
||||
pub fn clone_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> {
|
||||
self.inner.borrow().region_obligations.clone()
|
||||
}
|
||||
|
||||
pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.undo_log.push(UndoLog::PushRegionAssumption);
|
||||
|
|
|
|||
|
|
@ -1122,18 +1122,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
|
||||
sess.time("layout_testing", || layout_test::test_layout(tcx));
|
||||
sess.time("abi_testing", || abi_test::test_abi(tcx));
|
||||
|
||||
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
|
||||
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
|
||||
// in MIR optimizations that may only be reachable through codegen, or other codepaths
|
||||
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
|
||||
if tcx.sess.opts.unstable_opts.validate_mir {
|
||||
sess.time("ensuring_final_MIR_is_computable", || {
|
||||
tcx.par_hir_body_owners(|def_id| {
|
||||
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the type-checking, region checking and other miscellaneous analysis
|
||||
|
|
@ -1199,6 +1187,20 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
|
||||
let _ = tcx.all_diagnostic_items(());
|
||||
});
|
||||
|
||||
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
|
||||
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
|
||||
// in MIR optimizations that may only be reachable through codegen, or other codepaths
|
||||
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
|
||||
// Nevertheless, wait after type checking is finished, as optimizing code that does not
|
||||
// type-check is very prone to ICEs.
|
||||
if tcx.sess.opts.unstable_opts.validate_mir {
|
||||
sess.time("ensuring_final_MIR_is_computable", || {
|
||||
tcx.par_hir_body_owners(|def_id| {
|
||||
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the codegen backend, after which the AST and analysis can
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::any::Any;
|
||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
|
@ -6,13 +7,20 @@ use std::{env, thread};
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::{ShouldEmit, validate_attr};
|
||||
use rustc_codegen_ssa::back::archive::ArArchiveBuilderBuilder;
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::LintBuffer;
|
||||
use rustc_metadata::{DylibError, load_symbol_from_dylib};
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
|
||||
use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::{CurrentGcx, TyCtxt};
|
||||
use rustc_session::config::{
|
||||
Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple,
|
||||
};
|
||||
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
|
||||
use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
@ -316,12 +324,13 @@ pub fn get_codegen_backend(
|
|||
let backend = backend_name
|
||||
.or(target.default_codegen_backend.as_deref())
|
||||
.or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND"))
|
||||
.unwrap_or("llvm");
|
||||
.unwrap_or("dummy");
|
||||
|
||||
match backend {
|
||||
filename if filename.contains('.') => {
|
||||
load_backend_from_dylib(early_dcx, filename.as_ref())
|
||||
}
|
||||
"dummy" => || Box::new(DummyCodegenBackend),
|
||||
#[cfg(feature = "llvm")]
|
||||
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
|
||||
backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name),
|
||||
|
|
@ -334,6 +343,63 @@ pub fn get_codegen_backend(
|
|||
unsafe { load() }
|
||||
}
|
||||
|
||||
struct DummyCodegenBackend;
|
||||
|
||||
impl CodegenBackend for DummyCodegenBackend {
|
||||
fn locale_resource(&self) -> &'static str {
|
||||
""
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"dummy"
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
|
||||
Box::new(CodegenResults {
|
||||
modules: vec![],
|
||||
allocator_module: None,
|
||||
crate_info: CrateInfo::new(tcx, String::new()),
|
||||
})
|
||||
}
|
||||
|
||||
fn join_codegen(
|
||||
&self,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
_sess: &Session,
|
||||
_outputs: &OutputFilenames,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
(*ongoing_codegen.downcast().unwrap(), FxIndexMap::default())
|
||||
}
|
||||
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
// JUSTIFICATION: TyCtxt no longer available here
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
if sess.opts.crate_types.iter().any(|&crate_type| crate_type != CrateType::Rlib) {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
sess.dcx().fatal(format!(
|
||||
"crate type {} not supported by the dummy codegen backend",
|
||||
sess.opts.crate_types[0],
|
||||
));
|
||||
}
|
||||
|
||||
link_binary(
|
||||
sess,
|
||||
&ArArchiveBuilderBuilder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
outputs,
|
||||
self.name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This is used for rustdoc, but it uses similar machinery to codegen backend
|
||||
// loading, so we leave the code here. It is potentially useful for other tools
|
||||
// that want to invoke the rustc binary while linking to rustc as well.
|
||||
|
|
@ -542,6 +608,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
|||
stem,
|
||||
None,
|
||||
sess.io.temps_dir.clone(),
|
||||
sess.opts.unstable_opts.split_dwarf_out_dir.clone(),
|
||||
sess.opts.cg.extra_filename.clone(),
|
||||
sess.opts.output_types.clone(),
|
||||
)
|
||||
|
|
@ -571,6 +638,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
|||
out_filestem,
|
||||
ofile,
|
||||
sess.io.temps_dir.clone(),
|
||||
sess.opts.unstable_opts.split_dwarf_out_dir.clone(),
|
||||
sess.opts.cg.extra_filename.clone(),
|
||||
sess.opts.output_types.clone(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1824,3 +1824,55 @@ extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() {
|
|||
return 6; // Default fallback depth
|
||||
}
|
||||
#endif
|
||||
|
||||
// Statically assert that the fixed metadata kind IDs declared in
|
||||
// `metadata_kind.rs` match the ones actually used by LLVM.
|
||||
#define FIXED_MD_KIND(VARIANT, VALUE) \
|
||||
static_assert(::llvm::LLVMContext::VARIANT == VALUE);
|
||||
// Must be kept in sync with the corresponding list in `metadata_kind.rs`.
|
||||
FIXED_MD_KIND(MD_dbg, 0)
|
||||
FIXED_MD_KIND(MD_tbaa, 1)
|
||||
FIXED_MD_KIND(MD_prof, 2)
|
||||
FIXED_MD_KIND(MD_fpmath, 3)
|
||||
FIXED_MD_KIND(MD_range, 4)
|
||||
FIXED_MD_KIND(MD_tbaa_struct, 5)
|
||||
FIXED_MD_KIND(MD_invariant_load, 6)
|
||||
FIXED_MD_KIND(MD_alias_scope, 7)
|
||||
FIXED_MD_KIND(MD_noalias, 8)
|
||||
FIXED_MD_KIND(MD_nontemporal, 9)
|
||||
FIXED_MD_KIND(MD_mem_parallel_loop_access, 10)
|
||||
FIXED_MD_KIND(MD_nonnull, 11)
|
||||
FIXED_MD_KIND(MD_dereferenceable, 12)
|
||||
FIXED_MD_KIND(MD_dereferenceable_or_null, 13)
|
||||
FIXED_MD_KIND(MD_make_implicit, 14)
|
||||
FIXED_MD_KIND(MD_unpredictable, 15)
|
||||
FIXED_MD_KIND(MD_invariant_group, 16)
|
||||
FIXED_MD_KIND(MD_align, 17)
|
||||
FIXED_MD_KIND(MD_loop, 18)
|
||||
FIXED_MD_KIND(MD_type, 19)
|
||||
FIXED_MD_KIND(MD_section_prefix, 20)
|
||||
FIXED_MD_KIND(MD_absolute_symbol, 21)
|
||||
FIXED_MD_KIND(MD_associated, 22)
|
||||
FIXED_MD_KIND(MD_callees, 23)
|
||||
FIXED_MD_KIND(MD_irr_loop, 24)
|
||||
FIXED_MD_KIND(MD_access_group, 25)
|
||||
FIXED_MD_KIND(MD_callback, 26)
|
||||
FIXED_MD_KIND(MD_preserve_access_index, 27)
|
||||
FIXED_MD_KIND(MD_vcall_visibility, 28)
|
||||
FIXED_MD_KIND(MD_noundef, 29)
|
||||
FIXED_MD_KIND(MD_annotation, 30)
|
||||
FIXED_MD_KIND(MD_nosanitize, 31)
|
||||
FIXED_MD_KIND(MD_func_sanitize, 32)
|
||||
FIXED_MD_KIND(MD_exclude, 33)
|
||||
FIXED_MD_KIND(MD_memprof, 34)
|
||||
FIXED_MD_KIND(MD_callsite, 35)
|
||||
FIXED_MD_KIND(MD_kcfi_type, 36)
|
||||
FIXED_MD_KIND(MD_pcsections, 37)
|
||||
FIXED_MD_KIND(MD_DIAssignID, 38)
|
||||
FIXED_MD_KIND(MD_coro_outside_frame, 39)
|
||||
FIXED_MD_KIND(MD_mmra, 40)
|
||||
FIXED_MD_KIND(MD_noalias_addrspace, 41)
|
||||
// If some fixed metadata kinds are not present and consistent in all supported
|
||||
// LLVM versions, it's fine to omit them from this list; in that case Rust-side
|
||||
// code cannot declare them as fixed IDs and must look them up by name instead.
|
||||
#undef FIXED_MD_KIND
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ macro_rules! arena_types {
|
|||
rustc_middle::mir::Body<'tcx>
|
||||
>,
|
||||
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
|
||||
[decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>,
|
||||
[decode] borrowck_result: rustc_middle::mir::DefinitionSiteHiddenTypes<'tcx>,
|
||||
[] resolver: rustc_data_structures::steal::Steal<(
|
||||
rustc_middle::ty::ResolverAstLowering,
|
||||
std::sync::Arc<rustc_ast::Crate>,
|
||||
|
|
|
|||
|
|
@ -84,11 +84,10 @@ impl Debug for CoroutineLayout<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// All the opaque types that are restricted to concrete types
|
||||
/// by this function. Unlike the value in `TypeckResults`, this has
|
||||
/// unerased regions.
|
||||
/// All the opaque types that have had their hidden type fully computed.
|
||||
/// Unlike the value in `TypeckResults`, this has unerased regions.
|
||||
#[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>);
|
||||
pub struct DefinitionSiteHiddenTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>);
|
||||
|
||||
/// The result of the `mir_const_qualif` query.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1244,7 +1244,7 @@ rustc_queries! {
|
|||
|
||||
/// Borrow-checks the given typeck root, e.g. functions, const/static items,
|
||||
/// and its children, e.g. closures, inline consts.
|
||||
query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
|
||||
query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> {
|
||||
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ pub struct TypeckResults<'tcx> {
|
|||
/// We also store the type here, so that the compiler can use it as a hint
|
||||
/// for figuring out hidden types, even if they are only set in dead code
|
||||
/// (which doesn't show up in MIR).
|
||||
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||
pub hidden_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||
|
||||
/// Tracks the minimum captures required for a closure;
|
||||
/// see `MinCaptureInformationMap` for more details.
|
||||
|
|
@ -250,7 +250,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
coercion_casts: Default::default(),
|
||||
used_trait_imports: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
concrete_opaque_types: Default::default(),
|
||||
hidden_types: Default::default(),
|
||||
closure_min_captures: Default::default(),
|
||||
closure_fake_reads: Default::default(),
|
||||
rvalue_scopes: Default::default(),
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
.expect("failed to build vtable representation");
|
||||
assert!(layout.is_sized(), "can't create a vtable for an unsized type");
|
||||
let size = layout.size.bytes();
|
||||
let align = layout.align.abi.bytes();
|
||||
let align = layout.align.bytes();
|
||||
|
||||
let ptr_size = tcx.data_layout.pointer_size();
|
||||
let ptr_align = tcx.data_layout.pointer_align().abi;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_ast::InlineAsmOptions;
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, TyCtxt, layout};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
/// A pass that runs which is targeted at ensuring that codegen guarantees about
|
||||
|
|
@ -33,6 +34,19 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
return;
|
||||
}
|
||||
|
||||
// Represent whether this compilation target fundamentally doesn't
|
||||
// support unwinding at all at an ABI level. If this the target has no
|
||||
// support for unwinding then cleanup actions, for example, are all
|
||||
// unnecessary and can be considered unreachable.
|
||||
//
|
||||
// Currently this is only true for wasm targets on panic=abort when the
|
||||
// `exception-handling` target feature is disabled. In such a
|
||||
// configuration it's illegal to emit exception-related instructions so
|
||||
// it's not possible to unwind.
|
||||
let target_supports_unwinding = !(tcx.sess.target.is_like_wasm
|
||||
&& tcx.sess.panic_strategy() == PanicStrategy::Abort
|
||||
&& !tcx.asm_target_features(def_id).contains(&sym::exception_handling));
|
||||
|
||||
// Here we test for this function itself whether its ABI allows
|
||||
// unwinding or not.
|
||||
let body_ty = tcx.type_of(def_id).skip_binder();
|
||||
|
|
@ -54,12 +68,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
let Some(terminator) = &mut block.terminator else { continue };
|
||||
let span = terminator.source_info.span;
|
||||
|
||||
// If we see an `UnwindResume` terminator inside a function that cannot unwind, we need
|
||||
// to replace it with `UnwindTerminate`.
|
||||
if let TerminatorKind::UnwindResume = &terminator.kind
|
||||
&& !body_can_unwind
|
||||
{
|
||||
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
|
||||
// If we see an `UnwindResume` terminator inside a function then:
|
||||
//
|
||||
// * If the target doesn't support unwinding at all, then this is an
|
||||
// unreachable block.
|
||||
// * If the body cannot unwind, we need to replace it with
|
||||
// `UnwindTerminate`.
|
||||
if let TerminatorKind::UnwindResume = &terminator.kind {
|
||||
if !target_supports_unwinding {
|
||||
terminator.kind = TerminatorKind::Unreachable;
|
||||
} else if !body_can_unwind {
|
||||
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
}
|
||||
|
||||
if block.is_cleanup {
|
||||
|
|
@ -93,8 +113,9 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
if !call_can_unwind {
|
||||
// If this function call can't unwind, then there's no need for it
|
||||
if !call_can_unwind || !target_supports_unwinding {
|
||||
// If this function call can't unwind, or if the target doesn't
|
||||
// support unwinding at all, then there's no need for it
|
||||
// to have a landing pad. This means that we can remove any cleanup
|
||||
// registered for it (and turn it into `UnwindAction::Unreachable`).
|
||||
let cleanup = block.terminator_mut().unwind_mut().unwrap();
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
};
|
||||
let val = match null_op {
|
||||
NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
|
||||
NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
|
||||
NullOp::AlignOf if layout.is_sized() => layout.align.bytes(),
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.ecx
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
}
|
||||
let val = match null_op {
|
||||
NullOp::SizeOf => arg_layout.size.bytes(),
|
||||
NullOp::AlignOf => arg_layout.align.abi.bytes(),
|
||||
NullOp::AlignOf => arg_layout.align.bytes(),
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.ecx
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
let op_layout = self.ecx.layout_of(ty).ok()?;
|
||||
let val = match null_op {
|
||||
NullOp::SizeOf => op_layout.size.bytes(),
|
||||
NullOp::AlignOf => op_layout.align.abi.bytes(),
|
||||
NullOp::AlignOf => op_layout.align.bytes(),
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.tcx
|
||||
.offset_of_subfield(self.typing_env, op_layout, fields.iter())
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use tracing::debug;
|
|||
/// once with `apply`. This is useful for MIR transformation passes.
|
||||
pub(crate) struct MirPatch<'tcx> {
|
||||
term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>,
|
||||
/// Set of statements that should be replaced by `Nop`.
|
||||
nop_statements: Vec<Location>,
|
||||
new_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
||||
new_locals: Vec<LocalDecl<'tcx>>,
|
||||
|
|
@ -33,6 +35,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
pub(crate) fn new(body: &Body<'tcx>) -> Self {
|
||||
let mut result = MirPatch {
|
||||
term_patch_map: Default::default(),
|
||||
nop_statements: vec![],
|
||||
new_blocks: vec![],
|
||||
new_statements: vec![],
|
||||
new_locals: vec![],
|
||||
|
|
@ -212,6 +215,15 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
self.term_patch_map.insert(block, new);
|
||||
}
|
||||
|
||||
/// Mark given statement to be replaced by a `Nop`.
|
||||
///
|
||||
/// This method only works on statements from the initial body, and cannot be used to remove
|
||||
/// statements from `add_statement` or `add_assign`.
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn nop_statement(&mut self, loc: Location) {
|
||||
self.nop_statements.push(loc);
|
||||
}
|
||||
|
||||
/// Queues the insertion of a statement at a given location. The statement
|
||||
/// currently at that location, and all statements that follow, are shifted
|
||||
/// down. If multiple statements are queued for addition at the same
|
||||
|
|
@ -257,11 +269,8 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
bbs.extend(self.new_blocks);
|
||||
body.local_decls.extend(self.new_locals);
|
||||
|
||||
// The order in which we patch terminators does not change the result.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (src, patch) in self.term_patch_map {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
bbs[src].terminator_mut().kind = patch;
|
||||
for loc in self.nop_statements {
|
||||
bbs[loc.block].statements[loc.statement_index].make_nop();
|
||||
}
|
||||
|
||||
let mut new_statements = self.new_statements;
|
||||
|
|
@ -285,6 +294,17 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
.insert(loc.statement_index, Statement::new(source_info, stmt));
|
||||
delta += 1;
|
||||
}
|
||||
|
||||
// The order in which we patch terminators does not change the result.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (src, patch) in self.term_patch_map {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
let bb = &mut bbs[src];
|
||||
if let TerminatorKind::Unreachable = patch {
|
||||
bb.statements.clear();
|
||||
}
|
||||
bb.terminator_mut().kind = patch;
|
||||
}
|
||||
}
|
||||
|
||||
fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::patch::MirPatch;
|
||||
|
||||
pub(super) enum SimplifyConstCondition {
|
||||
AfterConstProp,
|
||||
Final,
|
||||
|
|
@ -19,8 +21,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
trace!("Running SimplifyConstCondition on {:?}", body.source);
|
||||
let typing_env = body.typing_env(tcx);
|
||||
'blocks: for block in body.basic_blocks_mut() {
|
||||
for stmt in block.statements.iter_mut() {
|
||||
let mut patch = MirPatch::new(body);
|
||||
|
||||
'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
for (statement_index, stmt) in block.statements.iter().enumerate() {
|
||||
// Simplify `assume` of a known value: either a NOP or unreachable.
|
||||
if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind
|
||||
&& let NonDivergingIntrinsic::Assume(discr) = intrinsic
|
||||
|
|
@ -28,17 +32,16 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
&& let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
|
||||
{
|
||||
if constant {
|
||||
stmt.make_nop();
|
||||
patch.nop_statement(Location { block: bb, statement_index });
|
||||
} else {
|
||||
block.statements.clear();
|
||||
block.terminator_mut().kind = TerminatorKind::Unreachable;
|
||||
patch.patch_terminator(bb, TerminatorKind::Unreachable);
|
||||
continue 'blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let terminator = block.terminator_mut();
|
||||
terminator.kind = match terminator.kind {
|
||||
let terminator = block.terminator();
|
||||
let terminator = match terminator.kind {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Constant(ref c), ref targets, ..
|
||||
} => {
|
||||
|
|
@ -58,7 +61,9 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
},
|
||||
_ => continue,
|
||||
};
|
||||
patch.patch_terminator(bb, terminator);
|
||||
}
|
||||
patch.apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -473,7 +473,10 @@ where
|
|||
// fails to reach a fixpoint but ends up getting an error after
|
||||
// running for some additional step.
|
||||
//
|
||||
// cc trait-system-refactor-initiative#105
|
||||
// FIXME(@lcnr): While I believe an error here to be possible, we
|
||||
// currently don't have any test which actually triggers it. @lqd
|
||||
// created a minimization for an ICE in typenum, but that one no
|
||||
// longer fails here. cc trait-system-refactor-initiative#105.
|
||||
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
||||
let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
|
||||
self.probe_trait_candidate(source)
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
|
|||
pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
||||
cx: I,
|
||||
self_ty: I::Ty,
|
||||
) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
|
||||
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
|
||||
match self_ty.kind() {
|
||||
ty::FnDef(def_id, args) => {
|
||||
let sig = cx.fn_sig(def_id);
|
||||
|
|
@ -673,7 +673,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
|||
&& cx.fn_is_const(def_id)
|
||||
{
|
||||
Ok((
|
||||
sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())),
|
||||
sig.instantiate(cx, args)
|
||||
.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
|
||||
def_id,
|
||||
args,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -234,12 +234,12 @@ where
|
|||
let self_ty = goal.predicate.self_ty();
|
||||
let (inputs_and_output, def_id, args) =
|
||||
structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
|
||||
let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output);
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
|
||||
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output])
|
||||
});
|
||||
let output_is_sized_pred =
|
||||
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
|
||||
let requirements = cx
|
||||
.const_conditions(def_id.into())
|
||||
.iter_instantiated(cx, args)
|
||||
|
|
@ -251,15 +251,12 @@ where
|
|||
})
|
||||
.chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
|
||||
|
||||
let pred = inputs_and_output
|
||||
.map_bound(|(inputs, _)| {
|
||||
ty::TraitRef::new(
|
||||
cx,
|
||||
goal.predicate.def_id(),
|
||||
[goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())],
|
||||
)
|
||||
})
|
||||
.to_host_effect_clause(cx, goal.predicate.constness);
|
||||
let pred = ty::Binder::dummy(ty::TraitRef::new(
|
||||
cx,
|
||||
goal.predicate.def_id(),
|
||||
[goal.predicate.self_ty(), inputs],
|
||||
))
|
||||
.to_host_effect_clause(cx, goal.predicate.constness);
|
||||
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
|
|
|
|||
|
|
@ -633,28 +633,19 @@ where
|
|||
// the certainty of all the goals.
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
|
||||
let mut response = Ok(Certainty::overflow(false));
|
||||
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||
// FIXME: This match is a bit ugly, it might be nice to change the inspect
|
||||
// stuff to use a closure instead. which should hopefully simplify this a bit.
|
||||
match self.evaluate_added_goals_step() {
|
||||
Ok(Some(cert)) => {
|
||||
response = Ok(cert);
|
||||
break;
|
||||
}
|
||||
Ok(None) => {}
|
||||
Ok(Some(cert)) => return Ok(cert),
|
||||
Err(NoSolution) => {
|
||||
response = Err(NoSolution);
|
||||
break;
|
||||
self.tainted = Err(NoSolution);
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if response.is_err() {
|
||||
self.tainted = Err(NoSolution);
|
||||
}
|
||||
|
||||
response
|
||||
debug!("try_evaluate_added_goals: encountered overflow");
|
||||
Ok(Certainty::overflow(false))
|
||||
}
|
||||
|
||||
/// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue