Merge pull request #20779 from rust-lang/rustc-pull

minor: Rustc pull update
This commit is contained in:
Laurențiu Nicola 2025-10-02 04:25:20 +00:00 committed by GitHub
commit b5108da611
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
321 changed files with 3994 additions and 2802 deletions

View file

@ -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.

View file

@ -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),
}
}
}

View file

@ -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,

View file

@ -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,
}
}

View file

@ -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.

View file

@ -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)
}
}

View file

@ -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"]

View file

@ -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,
}

View file

@ -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}

View file

@ -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,
);
}
}

View file

@ -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

View file

@ -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> {

View file

@ -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)]

View file

@ -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")
}
}

View file

@ -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,

View file

@ -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);
}
_ => {}

View file

@ -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);

View file

@ -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.
///

View file

@ -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,

View file

@ -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,
);
}

View file

@ -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,
}

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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)]

View file

@ -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,
));

View file

@ -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 {

View file

@ -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(

View file

@ -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));

View file

@ -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,

View file

@ -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() {

View file

@ -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

View file

@ -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,

View file

@ -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).

View file

@ -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")]
{

View file

@ -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

View file

@ -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);
}
}

View file

@ -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(

View file

@ -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);
}
}

View file

@ -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()
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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);

View file

@ -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(),
);
}
}

View file

@ -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;

View 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)
}

View file

@ -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::*;

View file

@ -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),

View file

@ -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;

View file

@ -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);

View file

@ -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),
]);
}

View file

@ -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) => {

View file

@ -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

View file

@ -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(),
);
}
}

View file

@ -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) => {

View file

@ -37,7 +37,7 @@ where
debug!(
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
place,
layout.align.abi.bytes(),
layout.align.bytes(),
pack.bytes()
);
false

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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),

View file

@ -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,
}
}

View file

@ -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,

View file

@ -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

View file

@ -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.

View file

@ -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")
}

View file

@ -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,

View file

@ -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

View file

@ -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,
);
}

View file

@ -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();

View file

@ -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={:?} \

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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()

View file

@ -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(

View file

@ -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();
}

View file

@ -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,

View file

@ -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);

View file

@ -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) });
}
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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(),
)

View file

@ -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

View file

@ -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>,

View file

@ -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.
///

View file

@ -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) }
}

View file

@ -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(),

View file

@ -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;

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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 {

View file

@ -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 {

View file

@ -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)

View file

@ -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,
))

View file

@ -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,

View file

@ -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