Auto merge of #2835 - saethlin:rustup, r=oli-obk

rustup

`@oli-obk` I think this is the resolution we agreed to on Zulip?
This commit is contained in:
bors 2023-04-10 12:48:02 +00:00
commit 2c455530e1
961 changed files with 10733 additions and 9476 deletions

View file

@ -11,6 +11,7 @@ trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
max_line_length = 100
[*.md]
# double whitespace at end of line

2
.gitmodules vendored
View file

@ -25,7 +25,7 @@
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
branch = rustc/16.0-2023-03-06
branch = rustc/16.0-2023-04-05
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
url = https://github.com/rust-embedded/book.git

View file

@ -632,7 +632,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]
[[package]]
@ -1418,9 +1418,9 @@ dependencies = [
[[package]]
name = "elsa"
version = "1.8.0"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f74077c3c3aedb99a2683919698285596662518ea13e5eedcf8bdd43b0d0453b"
checksum = "848fe615fbb0a74d9ae68dcaa510106d32e37d9416207bbea4bd008bd89c47ed"
dependencies = [
"stable_deref_trait",
]
@ -1673,12 +1673,6 @@ version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50"
[[package]]
name = "fs_extra"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
[[package]]
name = "futf"
version = "0.1.5"
@ -2861,12 +2855,11 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "jemalloc-sys"
version = "0.5.0+5.3.0"
version = "0.5.3+5.3.0-patched"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f655c3ecfa6b0d03634595b4b54551d4bd5ac208b9e0124873949a7ab168f70b"
checksum = "f9bd5d616ea7ed58b571b2e209a65759664d7fb021a0819d7a790afc67e47ca1"
dependencies = [
"cc",
"fs_extra",
"libc",
]
@ -3475,18 +3468,30 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.38"
version = "0.10.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.8",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
@ -3495,20 +3500,19 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "111.22.0+1.1.1q"
version = "111.25.0+1.1.1t"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.72"
version = "0.9.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
dependencies = [
"autocfg",
"cc",
"libc",
"openssl-src",
@ -4178,7 +4182,7 @@ name = "rustbook"
version = "0.1.0"
dependencies = [
"clap 4.2.1",
"env_logger 0.7.1",
"env_logger 0.10.0",
"mdbook",
]
@ -4994,8 +4998,8 @@ dependencies = [
"fluent-syntax",
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"syn 2.0.8",
"synstructure 0.13.0",
"unic-langid",
]
@ -6131,6 +6135,18 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.8",
"unicode-xid",
]
[[package]]
name = "tar"
version = "0.4.38"
@ -6299,7 +6315,7 @@ name = "tidy"
version = "0.1.0"
dependencies = [
"cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.14.0",
"cargo_metadata 0.15.3",
"ignore",
"lazy_static",
"miropt-test-tools",
@ -7154,7 +7170,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]
[[package]]
@ -7175,7 +7191,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]
[[package]]
@ -7204,5 +7220,5 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]

View file

@ -8,19 +8,6 @@ use rand_xoshiro::Xoshiro128StarStar;
use tracing::debug;
// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`.
// This is used to go between `memory_index` (source field order to memory order)
// and `inverse_memory_index` (memory order to source field order).
// See also `FieldsShape::Arbitrary::memory_index` for more details.
// FIXME(eddyb) build a better abstraction for permutations, if possible.
fn invert_mapping(map: &[u32]) -> Vec<u32> {
let mut inverse = vec![0; map.len()];
for i in 0..map.len() {
inverse[map[i] as usize] = i as u32;
}
inverse
}
pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>;
@ -45,8 +32,8 @@ pub trait LayoutCalculator {
LayoutS {
variants: Variants::Single { index: FIRST_VARIANT },
fields: FieldsShape::Arbitrary {
offsets: vec![Size::ZERO, b_offset],
memory_index: vec![0, 1],
offsets: [Size::ZERO, b_offset].into(),
memory_index: [0, 1].into(),
},
abi: Abi::ScalarPair(a, b),
largest_niche,
@ -58,18 +45,18 @@ pub trait LayoutCalculator {
fn univariant(
&self,
dl: &TargetDataLayout,
fields: &[Layout<'_>],
fields: &IndexSlice<FieldIdx, Layout<'_>>,
repr: &ReprOptions,
kind: StructKind,
) -> Option<LayoutS> {
let pack = repr.pack;
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
let optimize = !repr.inhibit_struct_field_reordering_opt();
if optimize {
let end =
if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
let optimizing = &mut inverse_memory_index[..end];
let optimizing = &mut inverse_memory_index.raw[..end];
let effective_field_align = |layout: Layout<'_>| {
if let Some(pack) = pack {
// return the packed alignment in bytes
@ -105,7 +92,7 @@ pub trait LayoutCalculator {
// Place ZSTs first to avoid "interesting offsets",
// especially with only one or two non-ZST fields.
// Then place largest alignments first, largest niches within an alignment group last
let f = fields[x as usize];
let f = fields[x];
let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
(!f.0.is_zst(), cmp::Reverse(effective_field_align(f)), niche_size)
});
@ -117,7 +104,7 @@ pub trait LayoutCalculator {
// And put the largest niche in an alignment group at the end
// so it can be used as discriminant in jagged enums
optimizing.sort_by_key(|&x| {
let f = fields[x as usize];
let f = fields[x];
let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
(effective_field_align(f), niche_size)
});
@ -135,7 +122,7 @@ pub trait LayoutCalculator {
// At the bottom of this function, we invert `inverse_memory_index` to
// produce `memory_index` (see `invert_mapping`).
let mut sized = true;
let mut offsets = vec![Size::ZERO; fields.len()];
let mut offsets = IndexVec::from_elem(Size::ZERO, &fields);
let mut offset = Size::ZERO;
let mut largest_niche = None;
let mut largest_niche_available = 0;
@ -146,7 +133,7 @@ pub trait LayoutCalculator {
offset = prefix_size.align_to(prefix_align);
}
for &i in &inverse_memory_index {
let field = &fields[i as usize];
let field = &fields[i];
if !sized {
self.delay_bug(&format!(
"univariant: field #{} comes after unsized field",
@ -168,7 +155,7 @@ pub trait LayoutCalculator {
align = align.max(field_align);
debug!("univariant offset: {:?} field: {:#?}", offset, field);
offsets[i as usize] = offset;
offsets[i] = offset;
if let Some(mut niche) = field.largest_niche() {
let available = niche.available(dl);
@ -192,14 +179,18 @@ pub trait LayoutCalculator {
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
// Field 5 would be the first element, so memory_index is i:
// Note: if we didn't optimize, it's already right.
let memory_index =
if optimize { invert_mapping(&inverse_memory_index) } else { inverse_memory_index };
let memory_index = if optimize {
inverse_memory_index.invert_bijective_mapping()
} else {
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
};
let size = min_size.align_to(align.abi);
let mut abi = Abi::Aggregate { sized };
// Unpack newtype ABIs and find scalar pairs.
if sized && size.bytes() > 0 {
// All other fields must be ZSTs.
let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.0.is_zst());
let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
// We have exactly one non-ZST field.
@ -238,13 +229,13 @@ pub trait LayoutCalculator {
let pair = self.scalar_pair(a, b);
let pair_offsets = match pair.fields {
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
assert_eq!(memory_index, &[0, 1]);
assert_eq!(memory_index.raw, [0, 1]);
offsets
}
_ => panic!(),
};
if offsets[i] == pair_offsets[0]
&& offsets[j] == pair_offsets[1]
if offsets[i] == pair_offsets[FieldIdx::from_usize(0)]
&& offsets[j] == pair_offsets[FieldIdx::from_usize(1)]
&& align == pair.align
&& size == pair.size
{
@ -289,7 +280,7 @@ pub trait LayoutCalculator {
fn layout_of_struct_or_enum(
&self,
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, Vec<Layout<'_>>>,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, Layout<'_>>>,
is_enum: bool,
is_unsafe_cell: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
@ -312,7 +303,7 @@ pub trait LayoutCalculator {
// but *not* an encoding of the discriminant (e.g., a tag value).
// See issue #49298 for more details on the need to leave space
// for non-ZST uninhabited data (mostly partial initialization).
let absent = |fields: &[Layout<'_>]| {
let absent = |fields: &IndexSlice<FieldIdx, Layout<'_>>| {
let uninhabited = fields.iter().any(|f| f.abi().is_uninhabited());
let is_zst = fields.iter().all(|f| f.0.is_zst());
uninhabited && is_zst
@ -510,7 +501,7 @@ pub trait LayoutCalculator {
// It'll fit, but we need to make some adjustments.
match layout.fields {
FieldsShape::Arbitrary { ref mut offsets, .. } => {
for (j, offset) in offsets.iter_mut().enumerate() {
for (j, offset) in offsets.iter_enumerated_mut() {
if !variants[i][j].0.is_zst() {
*offset += this_offset;
}
@ -577,8 +568,8 @@ pub trait LayoutCalculator {
variants: IndexVec::new(),
},
fields: FieldsShape::Arbitrary {
offsets: vec![niche_offset],
memory_index: vec![0],
offsets: [niche_offset].into(),
memory_index: [0].into(),
},
abi,
largest_niche,
@ -651,7 +642,8 @@ pub trait LayoutCalculator {
st.variants = Variants::Single { index: i };
// Find the first field we can't move later
// to make room for a larger discriminant.
for field in st.fields.index_by_increasing_offset().map(|j| &field_layouts[j]) {
for field_idx in st.fields.index_by_increasing_offset() {
let field = &field_layouts[FieldIdx::from_usize(field_idx)];
if !field.0.is_zst() || field.align().abi.bytes() != 1 {
start_align = start_align.min(field.align().abi);
break;
@ -802,13 +794,13 @@ pub trait LayoutCalculator {
let pair = self.scalar_pair(tag, prim_scalar);
let pair_offsets = match pair.fields {
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
assert_eq!(memory_index, &[0, 1]);
assert_eq!(memory_index.raw, [0, 1]);
offsets
}
_ => panic!(),
};
if pair_offsets[0] == Size::ZERO
&& pair_offsets[1] == *offset
if pair_offsets[FieldIdx::from_u32(0)] == Size::ZERO
&& pair_offsets[FieldIdx::from_u32(1)] == *offset
&& align == pair.align
&& size == pair.size
{
@ -844,7 +836,10 @@ pub trait LayoutCalculator {
tag_field: 0,
variants: IndexVec::new(),
},
fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] },
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO].into(),
memory_index: [0].into(),
},
largest_niche,
abi,
align,
@ -883,7 +878,7 @@ pub trait LayoutCalculator {
fn layout_of_union(
&self,
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, Vec<Layout<'_>>>,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, Layout<'_>>>,
) -> Option<LayoutS> {
let dl = self.current_data_layout();
let dl = dl.borrow();

View file

@ -1108,7 +1108,7 @@ pub enum FieldsShape {
/// ordered to match the source definition order.
/// This vector does not go in increasing order.
// FIXME(eddyb) use small vector optimization for the common case.
offsets: Vec<Size>,
offsets: IndexVec<FieldIdx, Size>,
/// Maps source order field indices to memory order indices,
/// depending on how the fields were reordered (if at all).
@ -1122,7 +1122,7 @@ pub enum FieldsShape {
///
// FIXME(eddyb) build a better abstraction for permutations, if possible.
// FIXME(camlorn) also consider small vector optimization here.
memory_index: Vec<u32>,
memory_index: IndexVec<FieldIdx, u32>,
},
}
@ -1157,7 +1157,7 @@ impl FieldsShape {
assert!(i < count);
stride * i
}
FieldsShape::Arbitrary { ref offsets, .. } => offsets[i],
FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)],
}
}
@ -1168,28 +1168,27 @@ impl FieldsShape {
unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
}
FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(),
FieldsShape::Arbitrary { ref memory_index, .. } => {
memory_index[FieldIdx::from_usize(i)].try_into().unwrap()
}
}
}
/// Gets source indices of the fields by increasing offsets.
#[inline]
pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
pub fn index_by_increasing_offset(&self) -> impl Iterator<Item = usize> + '_ {
let mut inverse_small = [0u8; 64];
let mut inverse_big = vec![];
let mut inverse_big = IndexVec::new();
let use_small = self.count() <= inverse_small.len();
// We have to write this logic twice in order to keep the array small.
if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
if use_small {
for i in 0..self.count() {
inverse_small[memory_index[i] as usize] = i as u8;
for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
inverse_small[mem_idx as usize] = field_idx.as_u32() as u8;
}
} else {
inverse_big = vec![0; self.count()];
for i in 0..self.count() {
inverse_big[memory_index[i] as usize] = i as u32;
}
inverse_big = memory_index.invert_bijective_mapping();
}
}
@ -1199,7 +1198,7 @@ impl FieldsShape {
if use_small {
inverse_small[i] as usize
} else {
inverse_big[i] as usize
inverse_big[i as u32].as_usize()
}
}
})
@ -1523,6 +1522,16 @@ impl<'a> Layout<'a> {
pub fn size(self) -> Size {
self.0.0.size
}
/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
///
/// Currently, that means that the type is pointer-sized, pointer-aligned,
/// and has a scalar ABI.
pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
self.size() == data_layout.pointer_size
&& self.align().abi == data_layout.pointer_align.abi
&& matches!(self.abi(), Abi::Scalar(..))
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]

View file

@ -22,6 +22,7 @@
#![feature(strict_provenance)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
use smallvec::SmallVec;
@ -568,7 +569,9 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
}
pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized {
#[allow(clippy::mut_from_ref)]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
#[allow(clippy::mut_from_ref)]
fn allocate_from_iter<'a>(
arena: &'a Arena<'tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
@ -578,10 +581,12 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
// Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T {
#[inline]
#[allow(clippy::mut_from_ref)]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
arena.dropless.alloc(self)
}
#[inline]
#[allow(clippy::mut_from_ref)]
fn allocate_from_iter<'a>(
arena: &'a Arena<'tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
@ -601,6 +606,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
}
#[inline]
#[allow(clippy::mut_from_ref)]
fn allocate_from_iter<'a>(
arena: &'a Arena<'tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
@ -616,12 +622,14 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
impl<'tcx> Arena<'tcx> {
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T {
value.allocate_on(self)
}
// Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`.
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
if value.is_empty() {
return &mut [];
@ -629,6 +637,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
self.dropless.alloc_slice(value)
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>(
&'a self,
iter: impl ::std::iter::IntoIterator<Item = T>,

View file

@ -2890,6 +2890,20 @@ pub struct Fn {
pub body: Option<P<Block>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P<Ty>,
pub mutability: Mutability,
pub expr: Option<P<Expr>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct ConstItem {
pub defaultness: Defaultness,
pub ty: P<Ty>,
pub expr: Option<P<Expr>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
/// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
@ -2903,11 +2917,11 @@ pub enum ItemKind {
/// A static item (`static`).
///
/// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`.
Static(P<Ty>, Mutability, Option<P<Expr>>),
Static(Box<StaticItem>),
/// A constant item (`const`).
///
/// E.g., `const FOO: i32 = 42;`.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
Const(Box<ConstItem>),
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
@ -3023,7 +3037,7 @@ pub type AssocItem = Item<AssocItemKind>;
pub enum AssocItemKind {
/// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
/// If `def` is parsed, then the constant is provided, and otherwise required.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
Const(Box<ConstItem>),
/// An associated function.
Fn(Box<Fn>),
/// An associated type.
@ -3035,7 +3049,7 @@ pub enum AssocItemKind {
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
Self::Const(defaultness, ..)
Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
@ -3046,7 +3060,7 @@ impl AssocItemKind {
impl From<AssocItemKind> for ItemKind {
fn from(assoc_item_kind: AssocItemKind) -> ItemKind {
match assoc_item_kind {
AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c),
AssocItemKind::Const(item) => ItemKind::Const(item),
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
@ -3059,7 +3073,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
fn try_from(item_kind: ItemKind) -> Result<AssocItemKind, ItemKind> {
Ok(match item_kind {
ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c),
ItemKind::Const(item) => AssocItemKind::Const(item),
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
@ -3084,7 +3098,9 @@ pub enum ForeignItemKind {
impl From<ForeignItemKind> for ItemKind {
fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
match foreign_item_kind {
ForeignItemKind::Static(a, b, c) => ItemKind::Static(a, b, c),
ForeignItemKind::Static(a, b, c) => {
ItemKind::Static(StaticItem { ty: a, mutability: b, expr: c }.into())
}
ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
ForeignItemKind::MacCall(a) => ItemKind::MacCall(a),
@ -3097,7 +3113,9 @@ impl TryFrom<ItemKind> for ForeignItemKind {
fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> {
Ok(match item_kind {
ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c),
ItemKind::Static(box StaticItem { ty: a, mutability: b, expr: c }) => {
ForeignItemKind::Static(a, b, c)
}
ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind),
ItemKind::MacCall(a) => ForeignItemKind::MacCall(a),
@ -3114,8 +3132,8 @@ mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
// tidy-alphabetical-start
static_assert_size!(AssocItem, 104);
static_assert_size!(AssocItemKind, 32);
static_assert_size!(AssocItem, 88);
static_assert_size!(AssocItemKind, 16);
static_assert_size!(Attribute, 32);
static_assert_size!(Block, 32);
static_assert_size!(Expr, 72);

View file

@ -7,10 +7,10 @@
//! a `MutVisitor` renaming item names in a module will miss all of those
//! that are created by the expansion of a macro.
use crate::ast::*;
use crate::ptr::P;
use crate::token::{self, Token};
use crate::tokenstream::*;
use crate::{ast::*, StaticItem};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::sync::Lrc;
@ -1030,14 +1030,12 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
match kind {
ItemKind::ExternCrate(_orig_name) => {}
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
ItemKind::Static(ty, _, expr) => {
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ItemKind::Const(defaultness, ty, expr) => {
visit_defaultness(defaultness, vis);
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
ItemKind::Const(item) => {
visit_const_item(item, vis);
}
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
visit_defaultness(defaultness, vis);
@ -1120,10 +1118,8 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
visitor.visit_vis(vis);
visit_attrs(attrs, visitor);
match kind {
AssocItemKind::Const(defaultness, ty, expr) => {
visit_defaultness(defaultness, visitor);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
AssocItemKind::Const(item) => {
visit_const_item(item, visitor);
}
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
visit_defaultness(defaultness, visitor);
@ -1153,6 +1149,15 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
smallvec![item]
}
fn visit_const_item<T: MutVisitor>(
ConstItem { defaultness, ty, expr }: &mut ConstItem,
visitor: &mut T,
) {
visit_defaultness(defaultness, visitor);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
visit_constness(constness, vis);

View file

@ -13,7 +13,7 @@
//! instance, a walker looking for item names in a module will miss all of
//! those that are created by the expansion of a macro.
use crate::ast::*;
use crate::{ast::*, StaticItem};
use rustc_span::symbol::Ident;
use rustc_span::Span;
@ -305,8 +305,9 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
match &item.kind {
ItemKind::ExternCrate(_) => {}
ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
ItemKind::Static(typ, _, expr) | ItemKind::Const(_, typ, expr) => {
visitor.visit_ty(typ);
ItemKind::Static(box StaticItem { ty, mutability: _, expr })
| ItemKind::Const(box ConstItem { ty, expr, .. }) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
@ -674,7 +675,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
visitor.visit_ident(ident);
walk_list!(visitor, visit_attribute, attrs);
match kind {
AssocItemKind::Const(_, ty, expr) => {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}

View file

@ -229,12 +229,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
}
ItemKind::Static(t, m, e) => {
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Static(ty, *m, body_id)
}
ItemKind::Const(_, t, e) => {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
hir::ItemKind::Const(ty, body_id)
}
ItemKind::Fn(box Fn {
@ -708,10 +708,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
let trait_item_def_id = hir_id.expect_owner();
let (generics, kind, has_default) = match &i.kind {
AssocItemKind::Const(_, ty, default) => {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
}
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
@ -809,7 +809,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &i.attrs);
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
(

View file

@ -9,8 +9,8 @@
use itertools::{Either, Itertools};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::walk_list;
use rustc_ast::*;
use rustc_ast::{walk_list, StaticItem};
use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxIndexMap;
use rustc_macros::Subdiagnostic;
@ -691,7 +691,7 @@ fn validate_generic_param_order(
GenericParamKind::Lifetime => (),
GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
ordered_params += " = ";
ordered_params += &pprust::expr_to_string(&*default.value);
ordered_params += &pprust::expr_to_string(&default.value);
}
GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
}
@ -983,14 +983,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
}
}
ItemKind::Const(def, .., None) => {
self.check_defaultness(item.span, *def);
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
self.check_defaultness(item.span, *defaultness);
self.session.emit_err(errors::ConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
ItemKind::Static(.., None) => {
ItemKind::Static(box StaticItem { expr: None, .. }) => {
self.session.emit_err(errors::StaticWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
@ -1259,13 +1259,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if ctxt == AssocCtxt::Impl {
match &item.kind {
AssocItemKind::Const(_, _, body) => {
if body.is_none() {
self.session.emit_err(errors::AssocConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
self.session.emit_err(errors::AssocConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() {

View file

@ -404,11 +404,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
);
} else {
// And if it isn't, cancel the early-pass warning.
self.sess
if let Some(err) = self
.sess
.parse_sess
.span_diagnostic
.steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
.map(|err| err.cancel());
{
err.cancel()
}
}
}
ast::ExprKind::TryBlock(_) => {
@ -485,17 +488,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
if let Some(args) = constraint.gen_args.as_ref()
&& matches!(
args,
ast::GenericArgs::ReturnTypeNotation(..) | ast::GenericArgs::Parenthesized(..)
ast::GenericArgs::ReturnTypeNotation(..)
)
{
// RTN is gated elsewhere, and parenthesized args will turn into
// another error.
if matches!(args, ast::GenericArgs::Parenthesized(..)) {
self.sess.delay_span_bug(
constraint.span,
"should have emitted a parenthesized generics error",
);
}
// RTN is gated below with a `gate_all`.
} else {
gate_feature_post!(
&self,

View file

@ -686,7 +686,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
let has_comment = self.maybe_print_comment(span.hi());
if !empty || has_comment {
self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
self.break_offset_if_not_bol(1, -INDENT_UNIT);
}
self.word("}");
if close_box {
@ -988,7 +988,9 @@ impl<'a> State<'a> {
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
if let Some(args) = constraint.gen_args.as_ref() {
self.print_generic_args(args, false)
}
self.space();
match &constraint.kind {
ast::AssocConstraintKind::Equality { term } => {

View file

@ -2,6 +2,7 @@ use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::delimited::IterDelimited;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem;
use rustc_ast as ast;
use rustc_ast::GenericBound;
use rustc_ast::ModKind;
@ -156,7 +157,7 @@ impl<'a> State<'a> {
self.print_use_tree(tree);
self.word(";");
}
ast::ItemKind::Static(ty, mutbl, body) => {
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
let def = ast::Defaultness::Final;
self.print_item_const(
item.ident,
@ -167,8 +168,15 @@ impl<'a> State<'a> {
def,
);
}
ast::ItemKind::Const(def, ty, body) => {
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, *def);
ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
self.print_item_const(
item.ident,
None,
ty,
expr.as_deref(),
&item.vis,
*defaultness,
);
}
ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
self.print_fn_full(
@ -507,8 +515,8 @@ impl<'a> State<'a> {
ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness);
}
ast::AssocItemKind::Type(box ast::TyAlias {
defaultness,

View file

@ -181,8 +181,8 @@ trait TypeOpInfo<'tcx> {
};
let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder {
name: placeholder.name,
universe: adjusted_universe.into(),
bound: placeholder.bound,
});
let error_region =
@ -191,8 +191,8 @@ trait TypeOpInfo<'tcx> {
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
tcx.mk_re_placeholder(ty::Placeholder {
name: error_placeholder.name,
universe: adjusted.into(),
bound: error_placeholder.bound,
})
})
} else {

View file

@ -11,7 +11,7 @@ use crate::{
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location};
use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{RegionVid, TyCtxt};
pub(crate) fn find<'tcx>(
@ -70,7 +70,10 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
block_data
.terminator()
.successors()
.filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
.filter(|&bb| {
Some(&mir::UnwindAction::Cleanup(bb))
!= block_data.terminator().unwind()
})
.map(|bb| Location { statement_index: 0, block: bb }),
);
}

View file

@ -467,9 +467,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Ref(region, ..) = ty.kind() {
match **region {
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
printer.region_highlight_mode.highlighting_bound_region(br, counter)
}
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
_ => {}
}
}
@ -485,9 +486,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let region = if let ty::Ref(region, ..) = ty.kind() {
match **region {
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
printer.region_highlight_mode.highlighting_bound_region(br, counter)
}
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
_ => {}
}
region

View file

@ -207,7 +207,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.regioncx
.placeholders_contained_in(lower_bound)
.map(|placeholder| {
if let Some(id) = placeholder.name.get_id()
if let Some(id) = placeholder.bound.kind.get_id()
&& let Some(placeholder_id) = id.as_local()
&& let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id)
&& let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()

View file

@ -125,7 +125,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
args,
destination,
target: _,
cleanup: _,
unwind: _,
from_hir_call: _,
fn_span: _,
} => {
@ -135,7 +135,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
self.mutate_place(location, *destination, Deep);
}
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(location, cond);
use rustc_middle::mir::AssertKind;
if let AssertKind::BoundsCheck { len, index } = msg {
@ -173,7 +173,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
options: _,
line_spans: _,
destination: _,
cleanup: _,
unwind: _,
} => {
for op in operands {
match op {
@ -198,7 +198,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
}
TerminatorKind::Goto { target: _ }
| TerminatorKind::Abort
| TerminatorKind::Terminate
| TerminatorKind::Unreachable
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {

View file

@ -740,7 +740,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
args,
destination,
target: _,
cleanup: _,
unwind: _,
from_hir_call: _,
fn_span: _,
} => {
@ -750,7 +750,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
self.mutate_place(loc, (*destination, span), Deep, flow_state);
}
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(loc, (cond, span), flow_state);
use rustc_middle::mir::AssertKind;
if let AssertKind::BoundsCheck { len, index } = msg {
@ -770,7 +770,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
options: _,
line_spans: _,
destination: _,
cleanup: _,
unwind: _,
} => {
for op in operands {
match op {
@ -801,7 +801,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
TerminatorKind::Goto { target: _ }
| TerminatorKind::Abort
| TerminatorKind::Terminate
| TerminatorKind::Unreachable
| TerminatorKind::Resume
| TerminatorKind::Return
@ -845,7 +845,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
}
TerminatorKind::Abort
TerminatorKind::Terminate
| TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }

View file

@ -63,7 +63,7 @@ impl LocalUseMap {
elements: &RegionValueElements,
body: &Body<'_>,
) -> Self {
let nones = IndexVec::from_elem_n(None, body.local_decls.len());
let nones = IndexVec::from_elem(None, &body.local_decls);
let mut local_use_map = LocalUseMap {
first_def_at: nones.clone(),
first_use_at: nones.clone(),
@ -76,7 +76,7 @@ impl LocalUseMap {
}
let mut locals_with_use_data: IndexVec<Local, bool> =
IndexVec::from_elem_n(false, body.local_decls.len());
IndexVec::from_elem(false, &body.local_decls);
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }

View file

@ -1300,7 +1300,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
match &term.kind {
TerminatorKind::Goto { .. }
| TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::Terminate
| TerminatorKind::Return
| TerminatorKind::GeneratorDrop
| TerminatorKind::Unreachable
@ -1342,9 +1342,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let region_ctxt_fn = || {
let reg_info = match br.kind {
ty::BoundRegionKind::BrAnon(_, Some(span)) => {
BoundRegionInfo::Span(span)
}
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
ty::BoundRegionKind::BrAnon(..) => {
BoundRegionInfo::Name(Symbol::intern("anon"))
}
@ -1584,7 +1582,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
span_mirbug!(self, block_data, "resume on non-cleanup block!")
}
}
TerminatorKind::Abort => {
TerminatorKind::Terminate => {
if !is_cleanup {
span_mirbug!(self, block_data, "abort on non-cleanup block!")
}
@ -1610,25 +1608,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
TerminatorKind::Unreachable => {}
TerminatorKind::Drop { target, unwind, .. }
| TerminatorKind::Assert { target, cleanup: unwind, .. } => {
| TerminatorKind::Assert { target, unwind, .. } => {
self.assert_iscleanup(body, block_data, target, is_cleanup);
if let Some(unwind) = unwind {
if is_cleanup {
span_mirbug!(self, block_data, "unwind on cleanup block")
}
self.assert_iscleanup(body, block_data, unwind, true);
}
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
}
TerminatorKind::Call { ref target, cleanup, .. } => {
TerminatorKind::Call { ref target, unwind, .. } => {
if let &Some(target) = target {
self.assert_iscleanup(body, block_data, target, is_cleanup);
}
if let Some(cleanup) = cleanup {
if is_cleanup {
span_mirbug!(self, block_data, "cleanup on cleanup block")
}
self.assert_iscleanup(body, block_data, cleanup, true);
}
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
}
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
@ -1636,23 +1624,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
TerminatorKind::FalseUnwind { real_target, unwind } => {
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
if let Some(unwind) = unwind {
if is_cleanup {
span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
}
self.assert_iscleanup(body, block_data, unwind, true);
}
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
}
TerminatorKind::InlineAsm { destination, cleanup, .. } => {
TerminatorKind::InlineAsm { destination, unwind, .. } => {
if let Some(target) = destination {
self.assert_iscleanup(body, block_data, target, is_cleanup);
}
if let Some(cleanup) = cleanup {
if is_cleanup {
span_mirbug!(self, block_data, "cleanup on cleanup block")
}
self.assert_iscleanup(body, block_data, cleanup, true);
}
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
}
}
}
@ -1669,6 +1647,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
fn assert_iscleanup_unwind(
&mut self,
body: &Body<'tcx>,
ctxt: &dyn fmt::Debug,
unwind: UnwindAction,
is_cleanup: bool,
) {
match unwind {
UnwindAction::Cleanup(unwind) => {
if is_cleanup {
span_mirbug!(self, ctxt, "unwind on cleanup block")
}
self.assert_iscleanup(body, ctxt, unwind, true);
}
UnwindAction::Continue => {
if is_cleanup {
span_mirbug!(self, ctxt, "unwind on cleanup block")
}
}
UnwindAction::Unreachable | UnwindAction::Terminate => (),
}
}
fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
match body.local_kind(local) {
LocalKind::ReturnPointer | LocalKind::Arg => {

View file

@ -123,8 +123,8 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
.constraints
.placeholder_region(self.type_checker.infcx, placeholder);
let reg_info = match placeholder.name {
ty::BoundRegionKind::BrAnon(_, Some(span)) => BoundRegionInfo::Span(span),
let reg_info = match placeholder.bound.kind {
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")),
ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")),

View file

@ -25,12 +25,12 @@ pub fn expand(
// FIXME - if we get deref patterns, use them to reduce duplication here
let (item, is_stmt, ty_span) =
if let Annotatable::Item(item) = &item
&& let ItemKind::Static(ty, ..) = &item.kind
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
{
(item, false, ecx.with_def_site_ctxt(ty.span))
} else if let Annotatable::Stmt(stmt) = &item
&& let StmtKind::Item(item) = &stmt.kind
&& let ItemKind::Static(ty, ..) = &item.kind
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
{
(item, true, ecx.with_def_site_ctxt(ty.span))
} else {

View file

@ -7,7 +7,6 @@
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
#![feature(is_some_and)]
#![feature(is_sorted)]
#![feature(let_chains)]
#![feature(proc_macro_internals)]

View file

@ -254,25 +254,27 @@ pub fn expand_test_or_bench(
let location_info = get_location_info(cx, &item);
let mut test_const = cx.item(
sp,
Ident::new(item.ident.name, sp),
thin_vec![
// #[cfg(test)]
cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
// #[rustc_test_marker = "test_case_sort_key"]
cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
],
// const $ident: test::TestDescAndFn =
ast::ItemKind::Const(
ast::Defaultness::Final,
cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
// test::TestDescAndFn {
Some(
cx.expr_struct(
sp,
test_path("TestDescAndFn"),
thin_vec![
let mut test_const =
cx.item(
sp,
Ident::new(item.ident.name, sp),
thin_vec![
// #[cfg(test)]
cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
// #[rustc_test_marker = "test_case_sort_key"]
cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
],
// const $ident: test::TestDescAndFn =
ast::ItemKind::Const(
ast::ConstItem {
defaultness: ast::Defaultness::Final,
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
// test::TestDescAndFn {
expr: Some(
cx.expr_struct(
sp,
test_path("TestDescAndFn"),
thin_vec![
// desc: test::TestDesc {
field(
"desc",
@ -359,10 +361,12 @@ pub fn expand_test_or_bench(
// testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
field("testfn", test_fn), // }
],
), // }
), // }
),
}
.into(),
),
),
);
);
test_const = test_const.map(|mut tc| {
tc.vis.kind = ast::VisibilityKind::Public;
tc

View file

@ -53,7 +53,7 @@ pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn Resolve
// even in non-test builds
let test_runner = get_test_runner(span_diagnostic, &krate);
if sess.opts.test {
if sess.is_test_crate() {
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
(PanicStrategy::Abort, true) => PanicStrategy::Abort,
(PanicStrategy::Abort, false) => {

View file

@ -345,7 +345,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
TerminatorKind::Return => {
crate::abi::codegen_return(fx);
}
TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => {
if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
let target = fx.get_block(*target);
fx.bcx.ins().jump(target, &[]);
@ -450,7 +450,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
destination,
target,
fn_span,
cleanup: _,
unwind: _,
from_hir_call: _,
} => {
fx.tcx.prof.generic_activity("codegen call").run(|| {
@ -470,7 +470,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
options,
destination,
line_spans: _,
cleanup: _,
unwind: _,
} => {
if options.contains(InlineAsmOptions::MAY_UNWIND) {
fx.tcx.sess.span_fatal(
@ -488,7 +488,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
*destination,
);
}
TerminatorKind::Abort => {
TerminatorKind::Terminate => {
codegen_panic_cannot_unwind(fx, source_info);
}
TerminatorKind::Resume => {

View file

@ -549,7 +549,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
TerminatorKind::Goto { .. }
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::Terminate
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }

View file

@ -381,7 +381,7 @@ impl<'tcx> AsmMethods<'tcx> for CodegenCx<'_, 'tcx> {
}
unsafe {
llvm::LLVMRustAppendModuleInlineAsm(
llvm::LLVMAppendModuleInlineAsm(
self.llmod,
template_str.as_ptr().cast(),
template_str.len(),

View file

@ -904,9 +904,9 @@ unsafe fn embed_bitcode(
// We need custom section flags, so emit module-level inline assembly.
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
}
}

View file

@ -2,7 +2,7 @@ use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock};
use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
@ -841,7 +841,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value {
unsafe { llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty, is_signed) }
unsafe {
llvm::LLVMBuildIntCast2(
self.llbuilder,
val,
dest_ty,
if is_signed { True } else { False },
UNNAMED,
)
}
}
fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@ -1001,11 +1009,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> {
let name = cstr!("cleanuppad");
let ret = unsafe {
llvm::LLVMRustBuildCleanupPad(
llvm::LLVMBuildCleanupPad(
self.llbuilder,
parent,
args.len() as c_uint,
args.as_ptr(),
args.len() as c_uint,
name.as_ptr(),
)
};
@ -1014,7 +1022,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn cleanup_ret(&mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>) {
unsafe {
llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind)
llvm::LLVMBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind)
.expect("LLVM does not have support for cleanupret");
}
}
@ -1022,11 +1030,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> {
let name = cstr!("catchpad");
let ret = unsafe {
llvm::LLVMRustBuildCatchPad(
llvm::LLVMBuildCatchPad(
self.llbuilder,
parent,
args.len() as c_uint,
args.as_ptr(),
args.len() as c_uint,
name.as_ptr(),
)
};
@ -1041,7 +1049,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
) -> &'ll Value {
let name = cstr!("catchswitch");
let ret = unsafe {
llvm::LLVMRustBuildCatchSwitch(
llvm::LLVMBuildCatchSwitch(
self.llbuilder,
parent,
unwind,
@ -1052,7 +1060,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let ret = ret.expect("LLVM does not have support for catchswitch");
for handler in handlers {
unsafe {
llvm::LLVMRustAddHandler(ret, handler);
llvm::LLVMAddHandler(ret, handler);
}
}
ret
@ -1376,8 +1384,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
}
pub fn catch_ret(&mut self, funclet: &Funclet<'ll>, unwind: &'ll BasicBlock) -> &'ll Value {
let ret =
unsafe { llvm::LLVMRustBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
ret.expect("LLVM does not have support for catchret")
}

View file

@ -7,7 +7,6 @@ use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use cstr::cstr;
use libc::c_uint;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@ -486,10 +485,10 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
// go into custom sections of the wasm executable.
if self.tcx.sess.target.is_like_wasm {
if let Some(section) = attrs.link_section {
let section = llvm::LLVMMDStringInContext(
let section = llvm::LLVMMDStringInContext2(
self.llcx,
section.as_str().as_ptr().cast(),
section.as_str().len() as c_uint,
section.as_str().len(),
);
assert!(alloc.provenance().ptrs().is_empty());
@ -498,17 +497,15 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
// as part of the interpreter execution).
let bytes =
alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
let alloc = llvm::LLVMMDStringInContext(
self.llcx,
bytes.as_ptr().cast(),
bytes.len() as c_uint,
);
let alloc =
llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len());
let data = [section, alloc];
let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2);
let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
llvm::LLVMAddNamedMetadataOperand(
self.llmod,
"wasm.custom_sections\0".as_ptr().cast(),
meta,
val,
);
}
} else {

View file

@ -830,24 +830,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
}
.unwrap_or_default();
let split_name = split_name.to_str().unwrap();
// FIXME(#60020):
//
// This should actually be
//
// let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
//
// That is, we should set LLVM's emission kind to `LineTablesOnly` if
// we are compiling with "limited" debuginfo. However, some of the
// existing tools relied on slightly more debuginfo being generated than
// would be the case with `LineTablesOnly`, and we did not want to break
// these tools in a "drive-by fix", without a good idea or plan about
// what limited debuginfo should exactly look like. So for now we keep
// the emission kind as `FullDebug`.
//
// See https://github.com/rust-lang/rust/issues/60020 for details.
let kind = DebugEmissionKind::FullDebug;
assert!(tcx.sess.opts.debuginfo != DebugInfo::None);
let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
unsafe {
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
@ -881,8 +864,6 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
);
if tcx.sess.opts.unstable_opts.profile {
let cu_desc_metadata =
llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata);
let default_gcda_path = &output_filenames.with_extension("gcda");
let gcda_path =
tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path);
@ -890,20 +871,17 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
let gcov_cu_info = [
path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")),
path_to_mdstring(debug_context.llcontext, gcda_path),
cu_desc_metadata,
unit_metadata,
];
let gcov_metadata = llvm::LLVMMDNodeInContext(
let gcov_metadata = llvm::LLVMMDNodeInContext2(
debug_context.llcontext,
gcov_cu_info.as_ptr(),
gcov_cu_info.len() as c_uint,
gcov_cu_info.len(),
);
let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata);
let llvm_gcov_ident = cstr!("llvm.gcov");
llvm::LLVMAddNamedMetadataOperand(
debug_context.llmod,
llvm_gcov_ident.as_ptr(),
gcov_metadata,
);
llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), val);
}
// Insert `llvm.ident` metadata on the wasm targets since that will
@ -924,15 +902,9 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
return unit_metadata;
};
fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll llvm::Metadata {
let path_str = path_to_c_string(path);
unsafe {
llvm::LLVMMDStringInContext(
llcx,
path_str.as_ptr(),
path_str.as_bytes().len() as c_uint,
)
}
unsafe { llvm::LLVMMDStringInContext2(llcx, path_str.as_ptr(), path_str.as_bytes().len()) }
}
}

View file

@ -209,8 +209,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
unsafe {
let dbg_loc_as_llval = llvm::LLVMRustMetadataAsValue(self.cx().llcx, dbg_loc);
llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc_as_llval);
llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
}
}
@ -402,7 +401,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
cx: &CodegenCx<'ll, 'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> &'ll DIArray {
if cx.sess().opts.debuginfo == DebugInfo::Limited {
if cx.sess().opts.debuginfo != DebugInfo::Full {
return create_DIArray(DIB(cx), &[]);
}

View file

@ -946,15 +946,27 @@ pub mod debuginfo {
NoDebug,
FullDebug,
LineTablesOnly,
DebugDirectivesOnly,
}
impl DebugEmissionKind {
pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self {
// We should be setting LLVM's emission kind to `LineTablesOnly` if
// we are compiling with "limited" debuginfo. However, some of the
// existing tools relied on slightly more debuginfo being generated than
// would be the case with `LineTablesOnly`, and we did not want to break
// these tools in a "drive-by fix", without a good idea or plan about
// what limited debuginfo should exactly look like. So for now we are
// instead adding a new debuginfo option "line-tables-only" so as to
// not break anything and to allow users to have 'limited' debug info.
//
// See https://github.com/rust-lang/rust/issues/60020 for details.
use rustc_session::config::DebugInfo;
match kind {
DebugInfo::None => DebugEmissionKind::NoDebug,
DebugInfo::Limited => DebugEmissionKind::LineTablesOnly,
DebugInfo::Full => DebugEmissionKind::FullDebug,
DebugInfo::LineDirectivesOnly => DebugEmissionKind::DebugDirectivesOnly,
DebugInfo::LineTablesOnly => DebugEmissionKind::LineTablesOnly,
DebugInfo::Limited | DebugInfo::Full => DebugEmissionKind::FullDebug,
}
}
}
@ -1006,7 +1018,7 @@ extern "C" {
pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
/// See Module::setModuleInlineAsm.
pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t);
pub fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t);
/// See llvm::LLVMTypeKind::getTypeID.
pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
@ -1053,7 +1065,7 @@ extern "C" {
// Operations on other types
pub fn LLVMVoidTypeInContext(C: &Context) -> &Type;
pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type;
pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
// Operations on all values
pub fn LLVMTypeOf(Val: &Value) -> &Type;
@ -1072,7 +1084,12 @@ extern "C" {
pub fn LLVMGetPoison(Ty: &Type) -> &Value;
// Operations on metadata
// FIXME: deprecated, replace with LLVMMDStringInContext2
pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value;
pub fn LLVMMDStringInContext2(C: &Context, Str: *const c_char, SLen: size_t) -> &Metadata;
// FIXME: deprecated, replace with LLVMMDNodeInContext2
pub fn LLVMMDNodeInContext<'a>(
C: &'a Context,
Vals: *const &'a Value,
@ -1111,6 +1128,8 @@ extern "C" {
Packed: Bool,
) -> &'a Value;
// FIXME: replace with LLVMConstArray2 when bumped minimal version to llvm-17
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
pub fn LLVMConstArray<'a>(
ElementTy: &'a Type,
ConstantVals: *const &'a Value,
@ -1250,7 +1269,7 @@ extern "C" {
pub fn LLVMDisposeBuilder<'a>(Builder: &'a mut Builder<'a>);
// Metadata
pub fn LLVMSetCurrentDebugLocation<'a>(Builder: &Builder<'a>, L: &'a Value);
pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: &'a Metadata);
// Terminators
pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
@ -1290,38 +1309,38 @@ extern "C" {
pub fn LLVMBuildResume<'a>(B: &Builder<'a>, Exn: &'a Value) -> &'a Value;
pub fn LLVMBuildUnreachable<'a>(B: &Builder<'a>) -> &'a Value;
pub fn LLVMRustBuildCleanupPad<'a>(
pub fn LLVMBuildCleanupPad<'a>(
B: &Builder<'a>,
ParentPad: Option<&'a Value>,
ArgCnt: c_uint,
Args: *const &'a Value,
NumArgs: c_uint,
Name: *const c_char,
) -> Option<&'a Value>;
pub fn LLVMRustBuildCleanupRet<'a>(
pub fn LLVMBuildCleanupRet<'a>(
B: &Builder<'a>,
CleanupPad: &'a Value,
UnwindBB: Option<&'a BasicBlock>,
BB: Option<&'a BasicBlock>,
) -> Option<&'a Value>;
pub fn LLVMRustBuildCatchPad<'a>(
pub fn LLVMBuildCatchPad<'a>(
B: &Builder<'a>,
ParentPad: &'a Value,
ArgCnt: c_uint,
Args: *const &'a Value,
NumArgs: c_uint,
Name: *const c_char,
) -> Option<&'a Value>;
pub fn LLVMRustBuildCatchRet<'a>(
pub fn LLVMBuildCatchRet<'a>(
B: &Builder<'a>,
Pad: &'a Value,
CatchPad: &'a Value,
BB: &'a BasicBlock,
) -> Option<&'a Value>;
pub fn LLVMRustBuildCatchSwitch<'a>(
pub fn LLVMBuildCatchSwitch<'a>(
Builder: &Builder<'a>,
ParentPad: Option<&'a Value>,
BB: Option<&'a BasicBlock>,
UnwindBB: Option<&'a BasicBlock>,
NumHandlers: c_uint,
Name: *const c_char,
) -> Option<&'a Value>;
pub fn LLVMRustAddHandler<'a>(CatchSwitch: &'a Value, Handler: &'a BasicBlock);
pub fn LLVMAddHandler<'a>(CatchSwitch: &'a Value, Dest: &'a BasicBlock);
pub fn LLVMSetPersonalityFn<'a>(Func: &'a Value, Pers: &'a Value);
// Add a case to the switch instruction
@ -1615,11 +1634,12 @@ extern "C" {
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
pub fn LLVMRustBuildIntCast<'a>(
pub fn LLVMBuildIntCast2<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
IsSigned: bool,
IsSigned: Bool,
Name: *const c_char,
) -> &'a Value;
// Comparisons
@ -1908,7 +1928,7 @@ extern "C" {
);
pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
pub fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;

View file

@ -53,7 +53,7 @@ impl<'ll> CodegenCx<'ll, '_> {
}
pub(crate) fn type_metadata(&self) -> &'ll Type {
unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) }
unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) }
}
///x Creates an integer type with the given number of bits, e.g., i24

View file

@ -2301,7 +2301,7 @@ fn add_native_libs_from_crate(
|| (whole_archive == None
&& bundle
&& cnum == LOCAL_CRATE
&& sess.opts.test);
&& sess.is_test_crate());
if bundle && cnum != LOCAL_CRATE {
if let Some(filename) = lib.filename {

View file

@ -1121,9 +1121,12 @@ impl<'a> Linker for EmLinker<'a> {
fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
// Preserve names or generate source maps depending on debug info
// For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g
self.cmd.arg(match self.sess.opts.debuginfo {
DebugInfo::None => "-g0",
DebugInfo::Limited => "--profiling-funcs",
DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
"--profiling-funcs"
}
DebugInfo::Full => "-g",
});
}

View file

@ -13,8 +13,7 @@ use object::{
use snap::write::FrameEncoder;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
use rustc_data_structures::owned_slice::try_slice_owned;
use rustc_data_structures::sync::MetadataRef;
use rustc_metadata::fs::METADATA_FILENAME;
use rustc_metadata::EncodedMetadata;
@ -42,10 +41,10 @@ fn load_metadata_with(
) -> Result<MetadataRef, String> {
let file =
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
let data = unsafe { Mmap::map(file) }
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))?;
let metadata = OwningRef::new(data).try_map(f)?;
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
unsafe { Mmap::map(file) }
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
.and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
}
impl MetadataLoader for DefaultMetadataLoader {

View file

@ -284,7 +284,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
match data.terminator().kind {
TerminatorKind::Goto { .. }
| TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::Terminate
| TerminatorKind::Return
| TerminatorKind::GeneratorDrop
| TerminatorKind::Unreachable
@ -292,11 +292,11 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
| TerminatorKind::Yield { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
TerminatorKind::Call { cleanup: unwind, .. }
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. }
TerminatorKind::Call { unwind, .. }
| TerminatorKind::InlineAsm { unwind, .. }
| TerminatorKind::Assert { unwind, .. }
| TerminatorKind::Drop { unwind, .. } => {
if let Some(unwind) = unwind {
if let mir::UnwindAction::Cleanup(unwind) = unwind {
debug!(
"cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
bb, data, unwind

View file

@ -147,7 +147,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
/// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional
/// return destination `destination` and the cleanup function `cleanup`.
/// return destination `destination` and the unwind action `unwind`.
fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
@ -156,7 +156,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
fn_ptr: Bx::Value,
llargs: &[Bx::Value],
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>,
mut unwind: mir::UnwindAction,
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
mergeable_succ: bool,
) -> MergingSucc {
@ -164,23 +164,23 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
// do an invoke, otherwise do a call.
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
Some(self.llbb_with_cleanup(fx, cleanup))
} else if fx.mir[self.bb].is_cleanup
&& fn_abi.can_unwind
&& !base::wants_msvc_seh(fx.cx.tcx().sess)
{
// Exception must not propagate out of the execution of a cleanup (doing so
// can cause undefined behaviour). We insert a double unwind guard for
// functions that can potentially unwind to protect against this.
//
// This is not necessary for SEH which does not use successive unwinding
// like Itanium EH. EH frames in SEH are different from normal function
// frames and SEH will abort automatically if an exception tries to
// propagate out from cleanup.
Some(fx.double_unwind_guard())
} else {
None
if !fn_abi.can_unwind {
unwind = mir::UnwindAction::Unreachable;
}
let unwind_block = match unwind {
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
mir::UnwindAction::Continue => None,
mir::UnwindAction::Unreachable => None,
mir::UnwindAction::Terminate => {
if fx.mir[self.bb].is_cleanup && base::wants_msvc_seh(fx.cx.tcx().sess) {
// SEH will abort automatically if an exception tries to
// propagate out from cleanup.
None
} else {
Some(fx.terminate_block())
}
}
};
if let Some(unwind_block) = unwind_block {
@ -234,7 +234,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
}
/// Generates inline assembly with optional `destination` and `cleanup`.
/// Generates inline assembly with optional `destination` and `unwind`.
fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
@ -244,11 +244,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
options: InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
instance: Instance<'_>,
mergeable_succ: bool,
) -> MergingSucc {
if let Some(cleanup) = cleanup {
let unwind_target = match unwind {
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
mir::UnwindAction::Continue => None,
mir::UnwindAction::Unreachable => None,
};
if let Some(cleanup) = unwind_target {
let ret_llbb = if let Some(target) = destination {
fx.llbb(target)
} else {
@ -261,7 +268,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
options,
line_spans,
instance,
Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))),
Some((ret_llbb, cleanup, self.funclet(fx))),
);
MergingSucc::False
} else {
@ -431,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &mut Bx,
location: mir::Place<'tcx>,
target: mir::BasicBlock,
unwind: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
mergeable_succ: bool,
) -> MergingSucc {
let ty = location.ty(self.mir, bx.tcx()).ty;
@ -552,7 +559,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
expected: bool,
msg: &mir::AssertMessage<'tcx>,
target: mir::BasicBlock,
cleanup: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
mergeable_succ: bool,
) -> MergingSucc {
let span = terminator.source_info.span;
@ -618,12 +625,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
// Codegen the actual panic invoke/call.
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, cleanup, &[], false);
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
assert_eq!(merging_succ, MergingSucc::False);
MergingSucc::False
}
fn codegen_abort_terminator(
fn codegen_terminate_terminator(
&mut self,
helper: TerminatorCodegenHelper<'tcx>,
bx: &mut Bx,
@ -636,7 +643,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
// Codegen the actual panic invoke/call.
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false);
let merging_succ = helper.do_call(
self,
bx,
fn_abi,
llfn,
&[],
None,
mir::UnwindAction::Unreachable,
&[],
false,
);
assert_eq!(merging_succ, MergingSucc::False);
}
@ -649,7 +666,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
instance: Option<Instance<'tcx>>,
source_info: mir::SourceInfo,
target: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
mergeable_succ: bool,
) -> Option<MergingSucc> {
// Emit a panic or a no-op for `assert_*` intrinsics.
@ -696,7 +713,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
llfn,
&[msg.0, msg.1],
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
cleanup,
unwind,
&[],
mergeable_succ,
)
@ -719,7 +736,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args: &[mir::Operand<'tcx>],
destination: mir::Place<'tcx>,
target: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
fn_span: Span,
mergeable_succ: bool,
) -> MergingSucc {
@ -783,7 +800,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
instance,
source_info,
target,
cleanup,
unwind,
mergeable_succ,
) {
return merging_succ;
@ -1064,7 +1081,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_ptr,
&llargs,
target.as_ref().map(|&target| (ret_dest, target)),
cleanup,
unwind,
&copied_constant_arguments,
false,
);
@ -1084,7 +1101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_ptr,
&llargs,
target.as_ref().map(|&target| (ret_dest, target)),
cleanup,
unwind,
&copied_constant_arguments,
mergeable_succ,
)
@ -1100,7 +1117,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
cleanup: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
instance: Instance<'_>,
mergeable_succ: bool,
) -> MergingSucc {
@ -1164,7 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options,
line_spans,
destination,
cleanup,
unwind,
instance,
mergeable_succ,
)
@ -1246,8 +1263,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MergingSucc::False
}
mir::TerminatorKind::Abort => {
self.codegen_abort_terminator(helper, bx, terminator);
mir::TerminatorKind::Terminate => {
self.codegen_terminate_terminator(helper, bx, terminator);
MergingSucc::False
}
@ -1274,7 +1291,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
}
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => self
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
.codegen_assert_terminator(
helper,
bx,
@ -1283,7 +1300,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
expected,
msg,
target,
cleanup,
unwind,
mergeable_succ(),
),
@ -1292,7 +1309,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ref args,
destination,
target,
cleanup,
unwind,
from_hir_call: _,
fn_span,
} => self.codegen_call_terminator(
@ -1303,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args,
destination,
target,
cleanup,
unwind,
fn_span,
mergeable_succ(),
),
@ -1320,7 +1337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options,
line_spans,
destination,
cleanup,
unwind,
} => self.codegen_asm_terminator(
helper,
bx,
@ -1330,7 +1347,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options,
line_spans,
destination,
cleanup,
unwind,
self.instance,
mergeable_succ(),
),
@ -1536,62 +1553,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
let llbb = self.llbb(bb);
if base::wants_msvc_seh(self.cx.sess()) {
let funclet;
let ret_llbb;
match self.mir[bb].terminator.as_ref().map(|t| &t.kind) {
// This is a basic block that we're aborting the program for,
// notably in an `extern` function. These basic blocks are inserted
// so that we assert that `extern` functions do indeed not panic,
// and if they do we abort the process.
//
// On MSVC these are tricky though (where we're doing funclets). If
// we were to do a cleanuppad (like below) the normal functions like
// `longjmp` would trigger the abort logic, terminating the
// program. Instead we insert the equivalent of `catch(...)` for C++
// which magically doesn't trigger when `longjmp` files over this
// frame.
//
// Lots more discussion can be found on #48251 but this codegen is
// modeled after clang's for:
//
// try {
// foo();
// } catch (...) {
// bar();
// }
Some(&mir::TerminatorKind::Abort) => {
let cs_llbb =
Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb));
let cp_llbb =
Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb));
ret_llbb = cs_llbb;
let mut cs_bx = Bx::build(self.cx, cs_llbb);
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
// The "null" here is actually a RTTI type descriptor for the
// C++ personality function, but `catch (...)` has no type so
// it's null. The 64 here is actually a bitfield which
// represents that this is a catch-all block.
let mut cp_bx = Bx::build(self.cx, cp_llbb);
let null = cp_bx.const_null(
cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space),
);
let sixty_four = cp_bx.const_i32(64);
funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
cp_bx.br(llbb);
}
_ => {
let cleanup_llbb =
Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
ret_llbb = cleanup_llbb;
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
funclet = cleanup_bx.cleanup_pad(None, &[]);
cleanup_bx.br(llbb);
}
}
let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
let funclet = cleanup_bx.cleanup_pad(None, &[]);
cleanup_bx.br(llbb);
self.funclets[bb] = Some(funclet);
ret_llbb
cleanup_bb
} else {
let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
@ -1618,26 +1585,68 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
}
fn double_unwind_guard(&mut self) -> Bx::BasicBlock {
self.double_unwind_guard.unwrap_or_else(|| {
assert!(!base::wants_msvc_seh(self.cx.sess()));
fn terminate_block(&mut self) -> Bx::BasicBlock {
self.terminate_block.unwrap_or_else(|| {
let funclet;
let llbb;
let mut bx;
if base::wants_msvc_seh(self.cx.sess()) {
// This is a basic block that we're aborting the program for,
// notably in an `extern` function. These basic blocks are inserted
// so that we assert that `extern` functions do indeed not panic,
// and if they do we abort the process.
//
// On MSVC these are tricky though (where we're doing funclets). If
// we were to do a cleanuppad (like below) the normal functions like
// `longjmp` would trigger the abort logic, terminating the
// program. Instead we insert the equivalent of `catch(...)` for C++
// which magically doesn't trigger when `longjmp` files over this
// frame.
//
// Lots more discussion can be found on #48251 but this codegen is
// modeled after clang's for:
//
// try {
// foo();
// } catch (...) {
// bar();
// }
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
let mut cs_bx = Bx::build(self.cx, llbb);
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
// The "null" here is actually a RTTI type descriptor for the
// C++ personality function, but `catch (...)` has no type so
// it's null. The 64 here is actually a bitfield which
// represents that this is a catch-all block.
bx = Bx::build(self.cx, cp_llbb);
let null =
bx.const_null(bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space));
let sixty_four = bx.const_i32(64);
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
} else {
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
bx = Bx::build(self.cx, llbb);
let llpersonality = self.cx.eh_personality();
bx.cleanup_landing_pad(llpersonality);
funclet = None;
}
let llbb = Bx::append_block(self.cx, self.llfn, "abort");
let mut bx = Bx::build(self.cx, llbb);
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
let llpersonality = self.cx.eh_personality();
bx.cleanup_landing_pad(llpersonality);
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None);
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
bx.do_not_inline(llret);
bx.unreachable();
self.double_unwind_guard = Some(llbb);
self.terminate_block = Some(llbb);
llbb
})
}

View file

@ -165,11 +165,15 @@ fn calculate_debuginfo_offset<
mir::ProjectionElem::Downcast(_, variant) => {
place = place.downcast(bx, variant);
}
_ => span_bug!(
var.source_info.span,
"unsupported var debuginfo place `{:?}`",
mir::Place { local, projection: var.projection },
),
_ => {
// Sanity check for `can_use_in_debuginfo`.
debug_assert!(!elem.can_use_in_debuginfo());
span_bug!(
var.source_info.span,
"unsupported var debuginfo place `{:?}`",
mir::Place { local, projection: var.projection },
)
}
}
}

View file

@ -73,8 +73,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
/// Cached unreachable block
unreachable_block: Option<Bx::BasicBlock>,
/// Cached double unwind guarding block
double_unwind_guard: Option<Bx::BasicBlock>,
/// Cached terminate upon unwinding block
terminate_block: Option<Bx::BasicBlock>,
/// The location where each MIR arg/var/tmp/ret is stored. This is
/// usually an `PlaceRef` representing an alloca, but not always:
@ -166,7 +166,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let start_llbb = Bx::append_block(cx, llfn, "start");
let mut start_bx = Bx::build(cx, start_llbb);
if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
if mir.basic_blocks.iter().any(|bb| {
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
}) {
start_bx.set_personality_fn(cx.eh_personality());
}
@ -189,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
personality_slot: None,
cached_llbbs,
unreachable_block: None,
double_unwind_guard: None,
terminate_block: None,
cleanup_kinds,
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),

View file

@ -23,10 +23,26 @@ pub enum OperandValue<V> {
/// to be valid for the operand's lifetime.
/// The second value, if any, is the extra data (vtable or length)
/// which indicates that it refers to an unsized rvalue.
///
/// An `OperandValue` has this variant for types which are neither
/// `Immediate` nor `Pair`s. The backend value in this variant must be a
/// pointer to the *non*-immediate backend type. That pointee type is the
/// one returned by [`LayoutTypeMethods::backend_type`].
Ref(V, Option<V>, Align),
/// A single LLVM value.
/// A single LLVM immediate value.
///
/// An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeMethods::is_backend_immediate`] returns `true`.
/// The backend value in this variant must be the *immediate* backend type,
/// as returned by [`LayoutTypeMethods::immediate_backend_type`].
Immediate(V),
/// A pair of immediate LLVM values. Used by fat pointers too.
///
/// An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeMethods::is_backend_scalar_pair`] returns `true`.
/// The backend values in this variant must be the *immediate* backend types,
/// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`]
/// with `immediate: true`.
Pair(V, V),
}
@ -243,6 +259,31 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
}
impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
/// Returns an `OperandValue` that's generally UB to use in any way.
///
/// Depending on the `layout`, returns an `Immediate` or `Pair` containing
/// poison value(s), or a `Ref` containing a poison pointer.
///
/// Supports sized types only.
pub fn poison<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> OperandValue<V> {
assert!(layout.is_sized());
if bx.cx().is_backend_immediate(layout) {
let ibty = bx.cx().immediate_backend_type(layout);
OperandValue::Immediate(bx.const_poison(ibty))
} else if bx.cx().is_backend_scalar_pair(layout) {
let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true);
let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
} else {
let bty = bx.cx().backend_type(layout);
let ptr_bty = bx.cx().type_ptr_to(bty);
OperandValue::Ref(bx.const_poison(ptr_bty), None, layout.align.abi)
}
}
pub fn store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,

View file

@ -10,7 +10,7 @@ use crate::MemFlags;
use rustc_middle::mir;
use rustc_middle::mir::Operand;
use rustc_middle::ty::cast::{CastTy, IntTy};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_target::abi::{self, FIRST_VARIANT};
@ -158,33 +158,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
debug_assert!(src.layout.is_sized());
debug_assert!(dst.layout.is_sized());
if src.layout.size != dst.layout.size
|| src.layout.abi == abi::Abi::Uninhabited
|| dst.layout.abi == abi::Abi::Uninhabited
{
// In all of these cases it's UB to run this transmute, but that's
// known statically so might as well trap for it, rather than just
// making it unreachable.
bx.abort();
return;
}
let size_in_bytes = src.layout.size.bytes();
if size_in_bytes == 0 {
// Nothing to write
if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) {
val.store(bx, dst);
return;
}
match src.val {
OperandValue::Ref(src_llval, meta, src_align) => {
debug_assert_eq!(meta, None);
// For a place-to-place transmute, call `memcpy` directly so that
// both arguments get the best-available alignment information.
let bytes = bx.cx().const_usize(size_in_bytes);
let flags = MemFlags::empty();
bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags);
OperandValue::Ref(..) => {
span_bug!(
self.mir.span,
"Operand path should have handled transmute \
from `Ref` {src:?} to place {dst:?}"
);
}
OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
OperandValue::Immediate(..) | OperandValue::Pair(..) => {
// When we have immediate(s), the alignment of the source is irrelevant,
// so we can store them using the destination's alignment.
let llty = bx.backend_type(src.layout);
@ -194,6 +181,123 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
/// Attempts to transmute an `OperandValue` to another `OperandValue`.
///
/// Returns `None` for cases that can't work in that framework, such as for
/// `Immediate`->`Ref` that needs an `alloc` to get the location.
fn codegen_transmute_operand(
&mut self,
bx: &mut Bx,
operand: OperandRef<'tcx, Bx::Value>,
cast: TyAndLayout<'tcx>,
) -> Option<OperandValue<Bx::Value>> {
// Check for transmutes that are always UB.
if operand.layout.size != cast.size
|| operand.layout.abi.is_uninhabited()
|| cast.abi.is_uninhabited()
{
if !operand.layout.abi.is_uninhabited() {
// Since this is known statically and the input could have existed
// without already having hit UB, might as well trap for it.
bx.abort();
}
// Because this transmute is UB, return something easy to generate,
// since it's fine that later uses of the value are probably UB.
return Some(OperandValue::poison(bx, cast));
}
let operand_kind = self.value_kind(operand.layout);
let cast_kind = self.value_kind(cast);
match operand.val {
OperandValue::Ref(ptr, meta, align) => {
debug_assert_eq!(meta, None);
debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
let cast_bty = bx.backend_type(cast);
let cast_ptr = bx.pointercast(ptr, bx.type_ptr_to(cast_bty));
let fake_place = PlaceRef::new_sized_aligned(cast_ptr, cast, align);
Some(bx.load_operand(fake_place).val)
}
OperandValue::Immediate(imm) => {
let OperandValueKind::Immediate(in_scalar) = operand_kind else {
bug!("Found {operand_kind:?} for operand {operand:?}");
};
if let OperandValueKind::Immediate(out_scalar) = cast_kind {
match (in_scalar, out_scalar) {
(ScalarOrZst::Zst, ScalarOrZst::Zst) => {
Some(OperandRef::new_zst(bx, cast).val)
}
(ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar))
if in_scalar.size(self.cx) == out_scalar.size(self.cx) =>
{
let cast_bty = bx.backend_type(cast);
Some(OperandValue::Immediate(
self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty),
))
}
_ => None,
}
} else {
None
}
}
OperandValue::Pair(imm_a, imm_b) => {
let OperandValueKind::Pair(in_a, in_b) = operand_kind else {
bug!("Found {operand_kind:?} for operand {operand:?}");
};
if let OperandValueKind::Pair(out_a, out_b) = cast_kind
&& in_a.size(self.cx) == out_a.size(self.cx)
&& in_b.size(self.cx) == out_b.size(self.cx)
{
let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
Some(OperandValue::Pair(
self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty),
self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty),
))
} else {
None
}
}
}
}
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
/// or an [`OperandValue::Pair`] to an immediate of the target type.
///
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
/// `i8`, not `i1`, for `bool`-like types.)
fn transmute_immediate(
&self,
bx: &mut Bx,
mut imm: Bx::Value,
from_scalar: abi::Scalar,
to_scalar: abi::Scalar,
to_backend_ty: Bx::Type,
) -> Bx::Value {
debug_assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
use abi::Primitive::*;
imm = bx.from_immediate(imm);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | F32 | F64, Int(..) | F32 | F64) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.inttoptr(imm, to_backend_ty),
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
(F32 | F64, Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.inttoptr(int_imm, to_backend_ty)
}
(Pointer(..), F32 | F64) => {
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty)
}
};
imm = bx.to_immediate_scalar(imm, to_scalar);
imm
}
pub fn codegen_rvalue_unsized(
&mut self,
bx: &mut Bx,
@ -396,7 +500,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandValue::Immediate(newval)
}
mir::CastKind::Transmute => {
bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| {
bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}");
})
}
};
OperandRef { val, layout: cast }
@ -739,10 +845,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
match *rvalue {
mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
// FIXME: Now that transmute is an Rvalue, it would be nice if
// it could create `Immediate`s for scalars, where possible.
false,
mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => {
let operand_ty = operand.ty(self.mir, self.cx.tcx());
let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty));
let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty));
match (self.value_kind(operand_layout), self.value_kind(cast_layout)) {
// Can always load from a pointer as needed
(OperandValueKind::Ref, _) => true,
// Need to generate an `alloc` to get a pointer from an immediate
(OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false,
// When we have scalar immediates, we can only convert things
// where the sizes match, to avoid endianness questions.
(OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) =>
a.size(self.cx) == b.size(self.cx),
(OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) =>
a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx),
// Send mixings between scalars and pairs through the memory route
// FIXME: Maybe this could use insertvalue/extractvalue instead?
(OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) |
(OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false,
}
}
mir::Rvalue::Ref(..) |
mir::Rvalue::CopyForDeref(..) |
mir::Rvalue::AddressOf(..) |
@ -767,4 +894,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// (*) this is only true if the type is suitable
}
/// Gets which variant of [`OperandValue`] is expected for a particular type.
fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind {
if self.cx.is_backend_immediate(layout) {
debug_assert!(!self.cx.is_backend_scalar_pair(layout));
OperandValueKind::Immediate(match layout.abi {
abi::Abi::Scalar(s) => ScalarOrZst::Scalar(s),
abi::Abi::Vector { element, .. } => ScalarOrZst::Scalar(element),
_ if layout.is_zst() => ScalarOrZst::Zst,
x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"),
})
} else if self.cx.is_backend_scalar_pair(layout) {
let abi::Abi::ScalarPair(s1, s2) = layout.abi else {
span_bug!(
self.mir.span,
"Couldn't translate {:?} as backend scalar pair",
layout.abi,
);
};
OperandValueKind::Pair(s1, s2)
} else {
OperandValueKind::Ref
}
}
}
/// The variants of this match [`OperandValue`], giving details about the
/// backend values that will be held in that other type.
#[derive(Debug, Copy, Clone)]
enum OperandValueKind {
Ref,
Immediate(ScalarOrZst),
Pair(abi::Scalar, abi::Scalar),
}
#[derive(Debug, Copy, Clone)]
enum ScalarOrZst {
Zst,
Scalar(abi::Scalar),
}
impl ScalarOrZst {
pub fn size(self, cx: &impl abi::HasDataLayout) -> abi::Size {
match self {
ScalarOrZst::Zst => abi::Size::ZERO,
ScalarOrZst::Scalar(s) => s.size(cx),
}
}
}

View file

@ -100,11 +100,22 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {}
pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
/// The backend type used for a rust type when it's in memory,
/// such as when it's stack-allocated or when it's being loaded or stored.
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type;
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
fn reg_backend_type(&self, ty: &Reg) -> Self::Type;
/// The backend type used for a rust type when it's in an SSA register.
///
/// For nearly all types this is the same as the [`Self::backend_type`], however
/// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`]
/// in registers but as [`BaseTypeMethods::type_i8`] in memory.
///
/// Converting values between the two different backend types is done using
/// [`from_immediate`](super::BuilderMethods::from_immediate) and
/// [`to_immediate_scalar`](super::BuilderMethods::to_immediate_scalar).
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool;
fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool;

View file

@ -23,7 +23,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
use crate::interpret::{
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
InterpResult, OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
};
use super::error::*;
@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
/* with_caller_location = */ false,
dest,
ret,
StackPopUnwind::NotAllowed,
mir::UnwindAction::Unreachable,
)?;
Ok(ControlFlow::Break(()))
} else {
@ -401,7 +401,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
args: &[OpTy<'tcx>],
dest: &PlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
_unwind: StackPopUnwind, // unwinding is not supported in consts
_unwind: mir::UnwindAction, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
debug!("find_mir_or_eval_fn: {:?}", instance);
@ -450,7 +450,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
args: &[OpTy<'tcx>],
dest: &PlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
_unwind: StackPopUnwind,
_unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, dest, target)? {
@ -526,7 +526,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &AssertMessage<'tcx>,
_unwind: Option<mir::BasicBlock>,
_unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
use rustc_middle::mir::AssertKind::*;
// Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.

View file

@ -139,17 +139,6 @@ pub struct FrameInfo<'tcx> {
pub lint_root: Option<hir::HirId>,
}
/// Unwind information.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum StackPopUnwind {
/// The cleanup block.
Cleanup(mir::BasicBlock),
/// No cleanup needs to be done.
Skip,
/// Unwinding is not allowed (UB).
NotAllowed,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
pub enum StackPopCleanup {
/// Jump to the next block in the caller, or cause UB if None (that's a function
@ -157,7 +146,7 @@ pub enum StackPopCleanup {
/// we can validate it at that layout.
/// `ret` stores the block we jump to on a normal return, while `unwind`
/// stores the block used for cleanup during unwinding.
Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
/// The root frame of the stack: nowhere else to jump to.
/// `cleanup` says whether locals are deallocated. Static computation
/// wants them leaked to intern what they need (and just throw away
@ -735,18 +724,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// *Unwind* to the given `target` basic block.
/// Do *not* use for returning! Use `return_to_block` instead.
///
/// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
/// If `target` is `UnwindAction::Continue`, that indicates the function does not need cleanup
/// during unwinding, and we will just keep propagating that upwards.
///
/// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
/// unwinding, and doing so is UB.
pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
self.frame_mut().loc = match target {
StackPopUnwind::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
StackPopUnwind::Skip => Right(self.frame_mut().body.span),
StackPopUnwind::NotAllowed => {
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
mir::UnwindAction::Unreachable => {
throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
}
mir::UnwindAction::Terminate => {
self.frame_mut().loc = Right(self.frame_mut().body.span);
M::abort(self, "panic in a function that cannot unwind".to_owned())?;
}
};
Ok(())
}

View file

@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
use super::{
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
};
/// Data returned by Machine::stack_pop,
@ -185,7 +185,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
args: &[OpTy<'tcx, Self::Provenance>],
destination: &PlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
unwind: StackPopUnwind,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
@ -197,7 +197,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
args: &[OpTy<'tcx, Self::Provenance>],
destination: &PlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
unwind: StackPopUnwind,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx>;
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
@ -208,17 +208,17 @@ pub trait Machine<'mir, 'tcx>: Sized {
args: &[OpTy<'tcx, Self::Provenance>],
destination: &PlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
unwind: StackPopUnwind,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx>;
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &mir::AssertMessage<'tcx>,
unwind: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx>;
/// Called to evaluate `Abort` MIR terminator.
/// Called to abort evaluation.
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> {
throw_unsup_format!("aborting execution is not supported")
}
@ -487,7 +487,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
_args: &[OpTy<$tcx>],
_destination: &PlaceTy<$tcx, Self::Provenance>,
_target: Option<mir::BasicBlock>,
_unwind: StackPopUnwind,
_unwind: mir::UnwindAction,
) -> InterpResult<$tcx> {
match fn_val {}
}

View file

@ -20,9 +20,7 @@ mod visitor;
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
pub use self::eval_context::{
Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
};
pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
pub use self::intern::{intern_const_alloc_recursive, InternKind};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};

View file

@ -612,14 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
// FIXME(const_prop): normalization needed b/c const prop lint in
// `mir_drops_elaborated_and_const_checked`, which happens before
// optimized MIR. Only after optimizing the MIR can we guarantee
// that the `RevealAll` pass has happened and that the body's consts
// are normalized, so any call to resolve before that needs to be
// manually normalized.
let val = self.tcx.normalize_erasing_regions(self.param_env, *val);
match val {
match *val {
mir::ConstantKind::Ty(ct) => {
let ty = ct.ty();
let valtree = self.eval_ty_constant(ct, span)?;

View file

@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi;
use super::{
FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
PlaceTy, Scalar, StackPopCleanup, StackPopUnwind,
PlaceTy, Scalar, StackPopCleanup,
};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@ -60,7 +60,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ref args,
destination,
target,
ref cleanup,
unwind,
from_hir_call: _,
fn_span: _,
} => {
@ -106,11 +106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
with_caller_location,
&destination,
target,
match (cleanup, fn_abi.can_unwind) {
(Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
(None, true) => StackPopUnwind::Skip,
(_, false) => StackPopUnwind::NotAllowed,
},
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
)?;
// Sanity-check that `eval_fn_call` either pushed a new frame or
// did a jump to another block.
@ -137,19 +133,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.drop_in_place(&place, instance, target, unwind)?;
}
Assert { ref cond, expected, ref msg, target, cleanup } => {
Assert { ref cond, expected, ref msg, target, unwind } => {
let ignored =
M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
if ignored || expected == cond_val {
self.go_to_block(target);
} else {
M::assert_panic(self, msg, cleanup)?;
M::assert_panic(self, msg, unwind)?;
}
}
Abort => {
M::abort(self, "the program aborted execution".to_owned())?;
Terminate => {
// FIXME: maybe should call `panic_no_unwind` lang item instead.
M::abort(self, "panic in a function that cannot unwind".to_owned())?;
}
// When we encounter Resume, we've finished unwinding
@ -351,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
with_caller_location: bool,
destination: &PlaceTy<'tcx, M::Provenance>,
target: Option<mir::BasicBlock>,
mut unwind: StackPopUnwind,
mut unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
trace!("eval_fn_call: {:#?}", fn_val);
@ -410,9 +407,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
// The callee cannot unwind.
unwind = StackPopUnwind::NotAllowed;
if !callee_fn_abi.can_unwind {
// The callee cannot unwind, so force the `Unreachable` unwind handling.
unwind = mir::UnwindAction::Unreachable;
}
self.push_stack_frame(
@ -676,7 +673,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
place: &PlaceTy<'tcx, M::Provenance>,
instance: ty::Instance<'tcx>,
target: mir::BasicBlock,
unwind: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
// We take the address of the object. This may well be unaligned, which is fine
@ -717,10 +714,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
false,
&ret.into(),
Some(target),
match unwind {
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
None => StackPopUnwind::Skip,
},
unwind,
)
}
}

View file

@ -20,7 +20,6 @@ Rust MIR: a lowered representation of Rust.
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![feature(if_let_guard)]
#![feature(is_some_and)]
#![recursion_limit = "256"]
#[macro_use]

View file

@ -553,7 +553,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
Rvalue::Cast(CastKind::DynStar, _, _) => {
unimplemented!()
// `dyn*` coercion is implemented for CTFE.
}
Rvalue::Cast(_, _, _) => {}
@ -1031,9 +1031,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
}
TerminatorKind::Abort => {
TerminatorKind::Terminate => {
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
span_bug!(self.span, "`Abort` terminator outside of cleanup block")
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
}
TerminatorKind::Assert { .. }

View file

@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
}
}
mir::TerminatorKind::Abort
mir::TerminatorKind::Terminate
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
| mir::TerminatorKind::FalseEdge { .. }

View file

@ -807,7 +807,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
kind: TerminatorKind::Call {
func,
args,
cleanup: None,
unwind: UnwindAction::Continue,
destination: Place::from(new_temp),
target: Some(new_target),
from_hir_call,

View file

@ -5,13 +5,12 @@ use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::traits::Reveal;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, UnOp, START_BLOCK,
TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
};
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_mir_dataflow::impls::MaybeStorageLive;
@ -233,6 +232,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
fn check_unwind_edge(&mut self, location: Location, unwind: UnwindAction) {
let is_cleanup = self.body.basic_blocks[location.block].is_cleanup;
match unwind {
UnwindAction::Cleanup(unwind) => {
if is_cleanup {
self.fail(location, "unwind on cleanup block");
}
self.check_edge(location, unwind, EdgeKind::Unwind);
}
UnwindAction::Continue => {
if is_cleanup {
self.fail(location, "unwind on cleanup block");
}
}
UnwindAction::Unreachable | UnwindAction::Terminate => (),
}
}
/// Check if src can be assigned into dest.
/// This is not precise, it will accept some incorrect assignments.
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
@ -419,13 +436,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.super_projection_elem(local, proj_base, elem, context, location);
}
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
let check_place = |place: Place<'_>| {
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
self.fail(
START_BLOCK.start_location(),
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
);
}
};
match debuginfo.value {
VarDebugInfoContents::Const(_) => {}
VarDebugInfoContents::Place(place) => check_place(place),
VarDebugInfoContents::Composite { ty, ref fragments } => {
for f in fragments {
check_place(f.contents);
if ty.is_union() || ty.is_enum() {
self.fail(
START_BLOCK.start_location(),
format!("invalid type {:?} for composite debuginfo", ty),
);
}
if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
self.fail(
START_BLOCK.start_location(),
format!(
"illegal projection {:?} in debuginfo for {:?}",
f.projection, debuginfo.name
),
);
}
}
}
}
self.super_var_debug_info(debuginfo);
}
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
// Set off any `bug!`s in the type computation code
let _ = place.ty(&self.body.local_decls, self.tcx);
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
&& place.projection.len() > 1
&& cntxt != PlaceContext::NonUse(VarDebugInfo)
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref)
{
self.fail(location, format!("{:?}, has deref at the wrong place", place));
@ -867,11 +920,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
TerminatorKind::Drop { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
if let Some(unwind) = unwind {
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
TerminatorKind::Call { func, args, destination, target, unwind, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {}
@ -883,9 +934,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if let Some(target) = target {
self.check_edge(location, *target, EdgeKind::Normal);
}
if let Some(cleanup) = cleanup {
self.check_edge(location, *cleanup, EdgeKind::Unwind);
}
self.check_unwind_edge(location, *unwind);
// The call destination place and Operand::Move place used as an argument might be
// passed by a reference to the callee. Consequently they must be non-overlapping.
@ -911,7 +960,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
TerminatorKind::Assert { cond, target, cleanup, .. } => {
TerminatorKind::Assert { cond, target, unwind, .. } => {
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
if cond_ty != self.tcx.types.bool {
self.fail(
@ -923,9 +972,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
self.check_edge(location, *target, EdgeKind::Normal);
if let Some(cleanup) = cleanup {
self.check_edge(location, *cleanup, EdgeKind::Unwind);
}
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::Yield { resume, drop, .. } => {
if self.body.generator.is_none() {
@ -957,17 +1004,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
self.check_edge(location, *real_target, EdgeKind::Normal);
if let Some(unwind) = unwind {
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::InlineAsm { destination, cleanup, .. } => {
TerminatorKind::InlineAsm { destination, unwind, .. } => {
if let Some(destination) = destination {
self.check_edge(location, *destination, EdgeKind::Normal);
}
if let Some(cleanup) = cleanup {
self.check_edge(location, *cleanup, EdgeKind::Unwind);
}
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::GeneratorDrop => {
if self.body.generator.is_none() {
@ -980,10 +1023,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
TerminatorKind::Resume | TerminatorKind::Abort => {
TerminatorKind::Resume | TerminatorKind::Terminate => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
self.fail(
location,
"Cannot `Resume` or `Terminate` from non-cleanup basic block",
)
}
}
TerminatorKind::Return => {

View file

@ -32,7 +32,7 @@ stacker = "0.1.15"
tempfile = "3.2"
thin-vec = "0.2.12"
tracing = "0.1"
elsa = "1.8"
elsa = "=1.7.1"
[dependencies.parking_lot]
version = "0.11"

View file

@ -206,17 +206,11 @@ impl<N: Debug, E: Debug> Graph<N, E> {
AdjacentEdges { graph: self, direction, next: first_edge }
}
pub fn successor_nodes<'a>(
&'a self,
source: NodeIndex,
) -> impl Iterator<Item = NodeIndex> + 'a {
pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
self.outgoing_edges(source).targets()
}
pub fn predecessor_nodes<'a>(
&'a self,
target: NodeIndex,
) -> impl Iterator<Item = NodeIndex> + 'a {
pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
self.incoming_edges(target).sources()
}

View file

@ -1,5 +1,5 @@
//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! is that code in here should not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
@ -27,6 +27,8 @@
#![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
#![feature(get_mut_unchecked)]
#![feature(lint_reasons)]
#![feature(unwrap_infallible)]
#![allow(rustc::default_hash_types)]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
@ -59,7 +61,6 @@ pub mod intern;
pub mod jobserver;
pub mod macros;
pub mod obligation_forest;
pub mod owning_ref;
pub mod sip128;
pub mod small_c_str;
pub mod small_str;
@ -82,6 +83,7 @@ pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod owned_slice;
pub mod sso;
pub mod steal;
pub mod tagged_ptr;

View file

@ -2,9 +2,7 @@ use std::fs::File;
use std::io;
use std::ops::{Deref, DerefMut};
use crate::owning_ref::StableAddress;
/// A trivial wrapper for [`memmap2::Mmap`] that implements [`StableAddress`].
/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec<u8>` on WASM).
#[cfg(not(target_arch = "wasm32"))]
pub struct Mmap(memmap2::Mmap);
@ -42,16 +40,10 @@ impl Deref for Mmap {
impl AsRef<[u8]> for Mmap {
fn as_ref(&self) -> &[u8] {
&*self.0
&self.0
}
}
// SAFETY: On architectures other than WASM, mmap is used as backing storage. The address of this
// memory map is stable. On WASM, `Vec<u8>` is used as backing storage. The `Mmap` type doesn't
// export any function that can cause the `Vec` to be re-allocated. As such the address of the
// bytes inside this `Vec` is stable.
unsafe impl StableAddress for Mmap {}
#[cfg(not(target_arch = "wasm32"))]
pub struct MmapMut(memmap2::MmapMut);

View file

@ -0,0 +1,118 @@
use std::{borrow::Borrow, ops::Deref};
// Use our fake Send/Sync traits when on not parallel compiler,
// so that `OwnedSlice` only implements/requires Send/Sync
// for parallel compiler builds.
use crate::sync::{Send, Sync};
/// An owned slice.
///
/// This is similar to `Box<[u8]>` but allows slicing and using anything as the
/// backing buffer.
///
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
///
/// ---------------------------------------------------------------------------
///
/// This is essentially a replacement for `owning_ref` which is a lot simpler
/// and even sound! 🌸
pub struct OwnedSlice {
/// This is conceptually a `&'self.owner [u8]`.
bytes: *const [u8],
// +---------------------------------------+
// | We expect `dead_code` lint here, |
// | because we don't want to accidentally |
// | touch the owner — otherwise the owner |
// | could invalidate out `bytes` pointer |
// | |
// | so be quiet |
// +----+ +-------------------------------+
// \/
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
#[expect(dead_code)]
owner: Box<dyn Send + Sync>,
}
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
///
/// ## Examples
///
/// ```rust
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
/// let vec = vec![1, 2, 3, 4];
///
/// // Identical to slicing via `&v[1..3]` but produces an owned slice
/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]);
/// assert_eq!(&*slice, [2, 3]);
/// ```
///
/// ```rust
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
/// # use std::ops::Deref;
/// let vec = vec![1, 2, 3, 4];
///
/// // Identical to slicing via `&v[..]` but produces an owned slice
/// let slice: OwnedSlice = slice_owned(vec, Deref::deref);
/// assert_eq!(&*slice, [1, 2, 3, 4]);
/// ```
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
where
O: Send + Sync + 'static,
F: FnOnce(&O) -> &[u8],
{
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
}
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail.
///
/// See [`slice_owned`] for the infallible version.
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
where
O: Send + Sync + 'static,
F: FnOnce(&O) -> Result<&[u8], E>,
{
// We box the owner of the bytes, so it doesn't move.
//
// Since the owner does not move and we don't access it in any way
// before drop, there is nothing that can invalidate the bytes pointer.
//
// Thus, "extending" the lifetime of the reference returned from `F` is fine.
// We pretend that we pass it a reference that lives as long as the returned slice.
//
// N.B. the HRTB on the `slicer` is important — without it the caller could provide
// a short lived slice, unrelated to the owner.
let owner = Box::new(owner);
let bytes = slicer(&*owner)?;
Ok(OwnedSlice { bytes, owner })
}
impl Deref for OwnedSlice {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
// Safety:
// `self.bytes` is valid per the construction in `slice_owned`
// (which is the only constructor)
unsafe { &*self.bytes }
}
}
impl Borrow<[u8]> for OwnedSlice {
#[inline]
fn borrow(&self) -> &[u8] {
self
}
}
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
unsafe impl Send for OwnedSlice {}
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
unsafe impl Sync for OwnedSlice {}
#[cfg(test)]
mod tests;

View file

@ -0,0 +1,74 @@
use std::{
ops::Deref,
sync::{
atomic::{self, AtomicBool},
Arc,
},
};
use crate::{
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
OnDrop,
};
#[test]
fn smoke() {
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
assert_eq!(&*slice, [1, 2, 3, 4, 5, 6]);
}
#[test]
fn static_storage() {
let slice = slice_owned(Box::new(String::from("what")), |_| b"bytes boo");
assert_eq!(&*slice, b"bytes boo");
}
#[test]
fn slice_the_slice() {
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
let slice = slice_owned(slice, |s| &s[1..][..4]);
let slice = slice_owned(slice, |s| s);
let slice = slice_owned(slice, |s| &s[1..]);
assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
}
#[test]
fn try_and_fail() {
let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(()));
assert!(res.is_err());
}
#[test]
fn boxed() {
// It's important that we don't cause UB because of `Box`'es uniqueness
let boxed: Box<[u8]> = vec![1, 1, 2, 3, 5, 8, 13, 21].into_boxed_slice();
let slice = slice_owned(boxed, Deref::deref);
assert_eq!(&*slice, [1, 1, 2, 3, 5, 8, 13, 21]);
}
#[test]
fn drop_drops() {
let flag = Arc::new(AtomicBool::new(false));
let flag_prime = Arc::clone(&flag);
let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed));
let slice = slice_owned(d, |_| &[]);
assert_eq!(flag.load(atomic::Ordering::Relaxed), false);
drop(slice);
assert_eq!(flag.load(atomic::Ordering::Relaxed), true);
}
#[test]
fn send_sync() {
crate::sync::assert_send::<OwnedSlice>();
crate::sync::assert_sync::<OwnedSlice>();
}

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Marvin Löbel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load diff

View file

@ -1,711 +0,0 @@
// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
#[cfg(not(miri))]
mod owning_ref {
use super::super::OwningRef;
use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(Debug, PartialEq)]
struct Example(u32, String, [u8; 3]);
fn example() -> Example {
Example(42, "hello world".to_string(), [1, 2, 3])
}
#[test]
fn new_deref() {
let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
assert_eq!(&*or, &());
}
#[test]
fn into() {
let or: OwningRef<Box<()>, ()> = Box::new(()).into();
assert_eq!(&*or, &());
}
#[test]
fn map_offset_ref() {
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, u32> = or.map(|x| &x.0);
assert_eq!(&*or, &42);
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
assert_eq!(&*or, &2);
}
#[test]
fn map_heap_ref() {
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
assert_eq!(&*or, "hello");
}
#[test]
fn map_static_ref() {
let or: BoxRef<()> = Box::new(()).into();
let or: BoxRef<_, str> = or.map(|_| "hello");
assert_eq!(&*or, "hello");
}
#[test]
fn map_chained() {
let or: BoxRef<String> = Box::new(example().1).into();
let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
let or: BoxRef<_, str> = or.map(|x| &x[..2]);
assert_eq!(&*or, "el");
}
#[test]
fn map_chained_inference() {
let or = BoxRef::new(Box::new(example().1)).map(|x| &x[..5]).map(|x| &x[1..3]);
assert_eq!(&*or, "el");
}
#[test]
fn owner() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
assert_eq!(&*or, "hello");
assert_eq!(&**or.owner(), "hello world");
}
#[test]
fn into_inner() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
assert_eq!(&*or, "hello");
let s = *or.into_inner();
assert_eq!(&s, "hello world");
}
#[test]
fn fmt_debug() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
let s = format!("{:?}", or);
assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
}
#[test]
fn erased_owner() {
let o1: BoxRef<Example, str> = BoxRef::new(Box::new(example())).map(|x| &x.1[..]);
let o2: BoxRef<String, str> = BoxRef::new(Box::new(example().1)).map(|x| &x[..]);
let os: Vec<ErasedBoxRef<str>> = vec![o1.erase_owner(), o2.erase_owner()];
assert!(os.iter().all(|e| &e[..] == "hello world"));
}
#[test]
fn raii_locks() {
use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef};
use super::super::{RefMutRef, RefRef};
use std::cell::RefCell;
use std::sync::{Mutex, RwLock};
{
let a = RefCell::new(1);
let a = {
let a = RefRef::new(a.borrow());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = RefCell::new(1);
let a = {
let a = RefMutRef::new(a.borrow_mut());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = Mutex::new(1);
let a = {
let a = MutexGuardRef::new(a.lock().unwrap());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = RwLock::new(1);
let a = {
let a = RwLockReadGuardRef::new(a.read().unwrap());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = RwLock::new(1);
let a = {
let a = RwLockWriteGuardRef::new(a.write().unwrap());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
}
#[test]
fn eq() {
let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
assert_eq!(or1.eq(&or2), true);
}
#[test]
fn cmp() {
let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
assert_eq!(or1.cmp(&or2), Ordering::Less);
}
#[test]
fn partial_cmp() {
let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice());
let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
}
#[test]
fn hash() {
let mut h1 = DefaultHasher::new();
let mut h2 = DefaultHasher::new();
let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice());
or1.hash(&mut h1);
or2.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
}
#[test]
fn borrow() {
let mut hash = HashMap::new();
let key = RcRef::<String>::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]);
hash.insert(key.clone().map(|s| &s[..3]), 42);
hash.insert(key.clone().map(|s| &s[4..]), 23);
assert_eq!(hash.get("foo"), Some(&42));
assert_eq!(hash.get("bar"), Some(&23));
}
#[test]
fn total_erase() {
let a: OwningRef<Vec<u8>, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]);
let b: OwningRef<Box<[u8]>, [u8]> =
OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
let c: OwningRef<Rc<Vec<u8>>, [u8]> = unsafe { a.map_owner(Rc::new) };
let d: OwningRef<Rc<Box<[u8]>>, [u8]> = unsafe { b.map_owner(Rc::new) };
let e: OwningRef<Rc<dyn Erased>, [u8]> = c.erase_owner();
let f: OwningRef<Rc<dyn Erased>, [u8]> = d.erase_owner();
let _g = e.clone();
let _h = f.clone();
}
#[test]
fn total_erase_box() {
let a: OwningRef<Vec<u8>, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]);
let b: OwningRef<Box<[u8]>, [u8]> =
OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]);
let c: OwningRef<Box<Vec<u8>>, [u8]> = a.map_owner_box();
let d: OwningRef<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
let _e: OwningRef<Box<dyn Erased>, [u8]> = c.erase_owner();
let _f: OwningRef<Box<dyn Erased>, [u8]> = d.erase_owner();
}
#[test]
fn try_map1() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
}
#[test]
fn try_map2() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(!OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
}
}
mod owning_handle {
use super::super::OwningHandle;
use super::super::RcRef;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::RwLock;
#[test]
fn owning_handle() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let mut handle =
OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
}
#[test]
fn try_owning_handle_ok() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
Ok(unsafe { x.as_ref() }.unwrap().borrow_mut())
})
.unwrap();
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
}
#[test]
fn try_owning_handle_err() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| {
if false {
return Ok(unsafe { x.as_ref() }.unwrap().borrow_mut());
}
Err(())
});
assert!(handle.is_err());
}
#[test]
fn nested() {
use std::cell::RefCell;
use std::sync::{Arc, RwLock};
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
let curr =
OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
let mut curr = OwningHandle::new_with_fn(curr, |x| {
unsafe { x.as_ref() }.unwrap().try_write().unwrap()
});
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
};
assert_eq!(*result, "someOtherString");
}
#[test]
fn owning_handle_safe() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let handle = OwningHandle::new(cell_ref);
assert_eq!(*handle, 2);
}
#[test]
fn owning_handle_mut_safe() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let mut handle = OwningHandle::new_mut(cell_ref);
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
}
#[test]
fn owning_handle_safe_2() {
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
let curr =
OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
let mut curr = OwningHandle::new_with_fn(curr, |x| {
unsafe { x.as_ref() }.unwrap().try_write().unwrap()
});
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
};
assert_eq!(*result, "someOtherString");
}
}
// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
#[cfg(not(miri))]
mod owning_ref_mut {
use super::super::BoxRef;
use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
#[derive(Debug, PartialEq)]
struct Example(u32, String, [u8; 3]);
fn example() -> Example {
Example(42, "hello world".to_string(), [1, 2, 3])
}
#[test]
fn new_deref() {
let or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
assert_eq!(&*or, &());
}
#[test]
fn new_deref_mut() {
let mut or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(()));
assert_eq!(&mut *or, &mut ());
}
#[test]
fn mutate() {
let mut or: OwningRefMut<Box<usize>, usize> = OwningRefMut::new(Box::new(0));
assert_eq!(&*or, &0);
*or = 1;
assert_eq!(&*or, &1);
}
#[test]
fn into() {
let or: OwningRefMut<Box<()>, ()> = Box::new(()).into();
assert_eq!(&*or, &());
}
#[test]
fn map_offset_ref() {
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRef<_, u32> = or.map(|x| &mut x.0);
assert_eq!(&*or, &42);
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]);
assert_eq!(&*or, &2);
}
#[test]
fn map_heap_ref() {
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]);
assert_eq!(&*or, "hello");
}
#[test]
fn map_static_ref() {
let or: BoxRefMut<()> = Box::new(()).into();
let or: BoxRef<_, str> = or.map(|_| "hello");
assert_eq!(&*or, "hello");
}
#[test]
fn map_mut_offset_ref() {
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0);
assert_eq!(&*or, &42);
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]);
assert_eq!(&*or, &2);
}
#[test]
fn map_mut_heap_ref() {
let or: BoxRefMut<Example> = Box::new(example()).into();
let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]);
assert_eq!(&*or, "hello");
}
#[test]
fn map_mut_static_ref() {
static mut MUT_S: [u8; 5] = *b"hello";
let mut_s: &'static mut [u8] = unsafe { &mut MUT_S };
let or: BoxRefMut<()> = Box::new(()).into();
let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s);
assert_eq!(&*or, b"hello");
}
#[test]
fn map_mut_chained() {
let or: BoxRefMut<String> = Box::new(example().1).into();
let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]);
let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]);
assert_eq!(&*or, "el");
}
#[test]
fn map_chained_inference() {
let or = BoxRefMut::new(Box::new(example().1))
.map_mut(|x| &mut x[..5])
.map_mut(|x| &mut x[1..3]);
assert_eq!(&*or, "el");
}
#[test]
fn try_map_mut() {
let or: BoxRefMut<String> = Box::new(example().1).into();
let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|x| Ok(&mut x[1..5]));
assert_eq!(&*or.unwrap(), "ello");
let or: BoxRefMut<String> = Box::new(example().1).into();
let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|_| Err(()));
assert!(or.is_err());
}
#[test]
fn owner() {
let or: BoxRefMut<String> = Box::new(example().1).into();
let or = or.map_mut(|x| &mut x[..5]);
assert_eq!(&*or, "hello");
assert_eq!(&**or.owner(), "hello world");
}
#[test]
fn into_inner() {
let or: BoxRefMut<String> = Box::new(example().1).into();
let or = or.map_mut(|x| &mut x[..5]);
assert_eq!(&*or, "hello");
let s = *or.into_inner();
assert_eq!(&s, "hello world");
}
#[test]
fn fmt_debug() {
let or: BoxRefMut<String> = Box::new(example().1).into();
let or = or.map_mut(|x| &mut x[..5]);
let s = format!("{:?}", or);
assert_eq!(&s, "OwningRefMut { owner: \"hello world\", reference: \"hello\" }");
}
#[test]
fn erased_owner() {
let o1: BoxRefMut<Example, str> =
BoxRefMut::new(Box::new(example())).map_mut(|x| &mut x.1[..]);
let o2: BoxRefMut<String, str> =
BoxRefMut::new(Box::new(example().1)).map_mut(|x| &mut x[..]);
let os: Vec<ErasedBoxRefMut<str>> = vec![o1.erase_owner(), o2.erase_owner()];
assert!(os.iter().all(|e| &e[..] == "hello world"));
}
#[test]
fn raii_locks() {
use super::super::RefMutRefMut;
use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut};
use std::cell::RefCell;
use std::sync::{Mutex, RwLock};
{
let a = RefCell::new(1);
let a = {
let a = RefMutRefMut::new(a.borrow_mut());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = Mutex::new(1);
let a = {
let a = MutexGuardRefMut::new(a.lock().unwrap());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
{
let a = RwLock::new(1);
let a = {
let a = RwLockWriteGuardRefMut::new(a.write().unwrap());
assert_eq!(*a, 1);
a
};
assert_eq!(*a, 1);
drop(a);
}
}
#[test]
fn eq() {
let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
assert_eq!(or1.eq(&or2), true);
}
#[test]
fn cmp() {
let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
assert_eq!(or1.cmp(&or2), Ordering::Less);
}
#[test]
fn partial_cmp() {
let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice());
let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater));
}
#[test]
fn hash() {
let mut h1 = DefaultHasher::new();
let mut h2 = DefaultHasher::new();
let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice());
or1.hash(&mut h1);
or2.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
}
#[test]
fn borrow() {
let mut hash = HashMap::new();
let key1 = BoxRefMut::<String>::new(Box::new("foo".to_string())).map(|s| &s[..]);
let key2 = BoxRefMut::<String>::new(Box::new("bar".to_string())).map(|s| &s[..]);
hash.insert(key1, 42);
hash.insert(key2, 23);
assert_eq!(hash.get("foo"), Some(&42));
assert_eq!(hash.get("bar"), Some(&23));
}
#[test]
fn total_erase() {
let a: OwningRefMut<Vec<u8>, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
let b: OwningRefMut<Box<[u8]>, [u8]> =
OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
let c: OwningRefMut<Box<Vec<u8>>, [u8]> = unsafe { a.map_owner(Box::new) };
let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = unsafe { b.map_owner(Box::new) };
let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
}
#[test]
fn total_erase_box() {
let a: OwningRefMut<Vec<u8>, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]);
let b: OwningRefMut<Box<[u8]>, [u8]> =
OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]);
let c: OwningRefMut<Box<Vec<u8>>, [u8]> = a.map_owner_box();
let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = b.map_owner_box();
let _e: OwningRefMut<Box<dyn Erased>, [u8]> = c.erase_owner();
let _f: OwningRefMut<Box<dyn Erased>, [u8]> = d.erase_owner();
}
#[test]
fn try_map1() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_ok());
}
#[test]
fn try_map2() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(!OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_err());
}
#[test]
fn try_map3() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok());
}
#[test]
fn try_map4() {
use std::any::Any;
let x = Box::new(123_i32);
let y: Box<dyn Any> = x;
assert!(!OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err());
}
#[test]
fn into_owning_ref() {
use super::super::BoxRef;
let or: BoxRefMut<()> = Box::new(()).into();
let or: BoxRef<()> = or.into();
assert_eq!(&*or, &());
}
struct Foo {
u: u32,
}
struct Bar {
f: Foo,
}
#[test]
fn ref_mut() {
use std::cell::RefCell;
let a = RefCell::new(Bar { f: Foo { u: 42 } });
let mut b = OwningRefMut::new(a.borrow_mut());
assert_eq!(b.f.u, 42);
b.f.u = 43;
let mut c = b.map_mut(|x| &mut x.f);
assert_eq!(c.u, 43);
c.u = 44;
let mut d = c.map_mut(|x| &mut x.u);
assert_eq!(*d, 44);
*d = 45;
assert_eq!(*d, 45);
}
}

View file

@ -778,7 +778,7 @@ pub fn print_time_passes_entry(
"rss_start": start_rss,
"rss_end": end_rss,
});
eprintln!("time: {}", json.to_string());
eprintln!("time: {json}");
return;
}
TimePassesFormat::Text => (),

View file

@ -140,6 +140,7 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
/// `hash` can be computed with any hasher, so long as that hasher is used
/// consistently for each `Sharded` instance.
#[inline]
#[allow(clippy::modulo_one)]
pub fn get_shard_index_by_hash(hash: u64) -> usize {
let hash_len = mem::size_of::<usize>();
// Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.

View file

@ -247,7 +247,7 @@ impl SipHasher128 {
for i in 0..BUFFER_CAPACITY {
let elem = self.buf.get_unchecked(i).assume_init().to_le();
self.state.v3 ^= elem;
Sip24Rounds::c_rounds(&mut self.state);
Sip13Rounds::c_rounds(&mut self.state);
self.state.v0 ^= elem;
}
@ -327,7 +327,7 @@ impl SipHasher128 {
for i in 0..last {
let elem = self.buf.get_unchecked(i).assume_init().to_le();
self.state.v3 ^= elem;
Sip24Rounds::c_rounds(&mut self.state);
Sip13Rounds::c_rounds(&mut self.state);
self.state.v0 ^= elem;
}
@ -340,7 +340,7 @@ impl SipHasher128 {
for _ in 0..elems_left {
let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le();
self.state.v3 ^= elem;
Sip24Rounds::c_rounds(&mut self.state);
Sip13Rounds::c_rounds(&mut self.state);
self.state.v0 ^= elem;
processed += ELEM_SIZE;
}
@ -368,7 +368,7 @@ impl SipHasher128 {
for i in 0..last {
let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() };
state.v3 ^= elem;
Sip24Rounds::c_rounds(&mut state);
Sip13Rounds::c_rounds(&mut state);
state.v0 ^= elem;
}
@ -392,15 +392,15 @@ impl SipHasher128 {
let b: u64 = ((length as u64 & 0xff) << 56) | elem;
state.v3 ^= b;
Sip24Rounds::c_rounds(&mut state);
Sip13Rounds::c_rounds(&mut state);
state.v0 ^= b;
state.v2 ^= 0xee;
Sip24Rounds::d_rounds(&mut state);
Sip13Rounds::d_rounds(&mut state);
let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3;
state.v1 ^= 0xdd;
Sip24Rounds::d_rounds(&mut state);
Sip13Rounds::d_rounds(&mut state);
let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3;
(_0, _1)
@ -477,13 +477,12 @@ impl Hasher for SipHasher128 {
}
#[derive(Debug, Clone, Default)]
struct Sip24Rounds;
struct Sip13Rounds;
impl Sip24Rounds {
impl Sip13Rounds {
#[inline]
fn c_rounds(state: &mut State) {
compress!(state);
compress!(state);
}
#[inline]
@ -491,6 +490,5 @@ impl Sip24Rounds {
compress!(state);
compress!(state);
compress!(state);
compress!(state);
}
}

View file

@ -22,269 +22,76 @@ fn hash_with<T: Hash>(mut st: SipHasher128, x: &T) -> (u64, u64) {
fn hash<T: Hash>(x: &T) -> (u64, u64) {
hash_with(SipHasher128::new_with_keys(0, 0), x)
}
#[rustfmt::skip]
const TEST_VECTOR: [[u8; 16]; 64] = [
[
0xa3, 0x81, 0x7f, 0x04, 0xba, 0x25, 0xa8, 0xe6, 0x6d, 0xf6, 0x72, 0x14, 0xc7, 0x55, 0x02,
0x93,
],
[
0xda, 0x87, 0xc1, 0xd8, 0x6b, 0x99, 0xaf, 0x44, 0x34, 0x76, 0x59, 0x11, 0x9b, 0x22, 0xfc,
0x45,
],
[
0x81, 0x77, 0x22, 0x8d, 0xa4, 0xa4, 0x5d, 0xc7, 0xfc, 0xa3, 0x8b, 0xde, 0xf6, 0x0a, 0xff,
0xe4,
],
[
0x9c, 0x70, 0xb6, 0x0c, 0x52, 0x67, 0xa9, 0x4e, 0x5f, 0x33, 0xb6, 0xb0, 0x29, 0x85, 0xed,
0x51,
],
[
0xf8, 0x81, 0x64, 0xc1, 0x2d, 0x9c, 0x8f, 0xaf, 0x7d, 0x0f, 0x6e, 0x7c, 0x7b, 0xcd, 0x55,
0x79,
],
[
0x13, 0x68, 0x87, 0x59, 0x80, 0x77, 0x6f, 0x88, 0x54, 0x52, 0x7a, 0x07, 0x69, 0x0e, 0x96,
0x27,
],
[
0x14, 0xee, 0xca, 0x33, 0x8b, 0x20, 0x86, 0x13, 0x48, 0x5e, 0xa0, 0x30, 0x8f, 0xd7, 0xa1,
0x5e,
],
[
0xa1, 0xf1, 0xeb, 0xbe, 0xd8, 0xdb, 0xc1, 0x53, 0xc0, 0xb8, 0x4a, 0xa6, 0x1f, 0xf0, 0x82,
0x39,
],
[
0x3b, 0x62, 0xa9, 0xba, 0x62, 0x58, 0xf5, 0x61, 0x0f, 0x83, 0xe2, 0x64, 0xf3, 0x14, 0x97,
0xb4,
],
[
0x26, 0x44, 0x99, 0x06, 0x0a, 0xd9, 0xba, 0xab, 0xc4, 0x7f, 0x8b, 0x02, 0xbb, 0x6d, 0x71,
0xed,
],
[
0x00, 0x11, 0x0d, 0xc3, 0x78, 0x14, 0x69, 0x56, 0xc9, 0x54, 0x47, 0xd3, 0xf3, 0xd0, 0xfb,
0xba,
],
[
0x01, 0x51, 0xc5, 0x68, 0x38, 0x6b, 0x66, 0x77, 0xa2, 0xb4, 0xdc, 0x6f, 0x81, 0xe5, 0xdc,
0x18,
],
[
0xd6, 0x26, 0xb2, 0x66, 0x90, 0x5e, 0xf3, 0x58, 0x82, 0x63, 0x4d, 0xf6, 0x85, 0x32, 0xc1,
0x25,
],
[
0x98, 0x69, 0xe2, 0x47, 0xe9, 0xc0, 0x8b, 0x10, 0xd0, 0x29, 0x93, 0x4f, 0xc4, 0xb9, 0x52,
0xf7,
],
[
0x31, 0xfc, 0xef, 0xac, 0x66, 0xd7, 0xde, 0x9c, 0x7e, 0xc7, 0x48, 0x5f, 0xe4, 0x49, 0x49,
0x02,
],
[
0x54, 0x93, 0xe9, 0x99, 0x33, 0xb0, 0xa8, 0x11, 0x7e, 0x08, 0xec, 0x0f, 0x97, 0xcf, 0xc3,
0xd9,
],
[
0x6e, 0xe2, 0xa4, 0xca, 0x67, 0xb0, 0x54, 0xbb, 0xfd, 0x33, 0x15, 0xbf, 0x85, 0x23, 0x05,
0x77,
],
[
0x47, 0x3d, 0x06, 0xe8, 0x73, 0x8d, 0xb8, 0x98, 0x54, 0xc0, 0x66, 0xc4, 0x7a, 0xe4, 0x77,
0x40,
],
[
0xa4, 0x26, 0xe5, 0xe4, 0x23, 0xbf, 0x48, 0x85, 0x29, 0x4d, 0xa4, 0x81, 0xfe, 0xae, 0xf7,
0x23,
],
[
0x78, 0x01, 0x77, 0x31, 0xcf, 0x65, 0xfa, 0xb0, 0x74, 0xd5, 0x20, 0x89, 0x52, 0x51, 0x2e,
0xb1,
],
[
0x9e, 0x25, 0xfc, 0x83, 0x3f, 0x22, 0x90, 0x73, 0x3e, 0x93, 0x44, 0xa5, 0xe8, 0x38, 0x39,
0xeb,
],
[
0x56, 0x8e, 0x49, 0x5a, 0xbe, 0x52, 0x5a, 0x21, 0x8a, 0x22, 0x14, 0xcd, 0x3e, 0x07, 0x1d,
0x12,
],
[
0x4a, 0x29, 0xb5, 0x45, 0x52, 0xd1, 0x6b, 0x9a, 0x46, 0x9c, 0x10, 0x52, 0x8e, 0xff, 0x0a,
0xae,
],
[
0xc9, 0xd1, 0x84, 0xdd, 0xd5, 0xa9, 0xf5, 0xe0, 0xcf, 0x8c, 0xe2, 0x9a, 0x9a, 0xbf, 0x69,
0x1c,
],
[
0x2d, 0xb4, 0x79, 0xae, 0x78, 0xbd, 0x50, 0xd8, 0x88, 0x2a, 0x8a, 0x17, 0x8a, 0x61, 0x32,
0xad,
],
[
0x8e, 0xce, 0x5f, 0x04, 0x2d, 0x5e, 0x44, 0x7b, 0x50, 0x51, 0xb9, 0xea, 0xcb, 0x8d, 0x8f,
0x6f,
],
[
0x9c, 0x0b, 0x53, 0xb4, 0xb3, 0xc3, 0x07, 0xe8, 0x7e, 0xae, 0xe0, 0x86, 0x78, 0x14, 0x1f,
0x66,
],
[
0xab, 0xf2, 0x48, 0xaf, 0x69, 0xa6, 0xea, 0xe4, 0xbf, 0xd3, 0xeb, 0x2f, 0x12, 0x9e, 0xeb,
0x94,
],
[
0x06, 0x64, 0xda, 0x16, 0x68, 0x57, 0x4b, 0x88, 0xb9, 0x35, 0xf3, 0x02, 0x73, 0x58, 0xae,
0xf4,
],
[
0xaa, 0x4b, 0x9d, 0xc4, 0xbf, 0x33, 0x7d, 0xe9, 0x0c, 0xd4, 0xfd, 0x3c, 0x46, 0x7c, 0x6a,
0xb7,
],
[
0xea, 0x5c, 0x7f, 0x47, 0x1f, 0xaf, 0x6b, 0xde, 0x2b, 0x1a, 0xd7, 0xd4, 0x68, 0x6d, 0x22,
0x87,
],
[
0x29, 0x39, 0xb0, 0x18, 0x32, 0x23, 0xfa, 0xfc, 0x17, 0x23, 0xde, 0x4f, 0x52, 0xc4, 0x3d,
0x35,
],
[
0x7c, 0x39, 0x56, 0xca, 0x5e, 0xea, 0xfc, 0x3e, 0x36, 0x3e, 0x9d, 0x55, 0x65, 0x46, 0xeb,
0x68,
],
[
0x77, 0xc6, 0x07, 0x71, 0x46, 0xf0, 0x1c, 0x32, 0xb6, 0xb6, 0x9d, 0x5f, 0x4e, 0xa9, 0xff,
0xcf,
],
[
0x37, 0xa6, 0x98, 0x6c, 0xb8, 0x84, 0x7e, 0xdf, 0x09, 0x25, 0xf0, 0xf1, 0x30, 0x9b, 0x54,
0xde,
],
[
0xa7, 0x05, 0xf0, 0xe6, 0x9d, 0xa9, 0xa8, 0xf9, 0x07, 0x24, 0x1a, 0x2e, 0x92, 0x3c, 0x8c,
0xc8,
],
[
0x3d, 0xc4, 0x7d, 0x1f, 0x29, 0xc4, 0x48, 0x46, 0x1e, 0x9e, 0x76, 0xed, 0x90, 0x4f, 0x67,
0x11,
],
[
0x0d, 0x62, 0xbf, 0x01, 0xe6, 0xfc, 0x0e, 0x1a, 0x0d, 0x3c, 0x47, 0x51, 0xc5, 0xd3, 0x69,
0x2b,
],
[
0x8c, 0x03, 0x46, 0x8b, 0xca, 0x7c, 0x66, 0x9e, 0xe4, 0xfd, 0x5e, 0x08, 0x4b, 0xbe, 0xe7,
0xb5,
],
[
0x52, 0x8a, 0x5b, 0xb9, 0x3b, 0xaf, 0x2c, 0x9c, 0x44, 0x73, 0xcc, 0xe5, 0xd0, 0xd2, 0x2b,
0xd9,
],
[
0xdf, 0x6a, 0x30, 0x1e, 0x95, 0xc9, 0x5d, 0xad, 0x97, 0xae, 0x0c, 0xc8, 0xc6, 0x91, 0x3b,
0xd8,
],
[
0x80, 0x11, 0x89, 0x90, 0x2c, 0x85, 0x7f, 0x39, 0xe7, 0x35, 0x91, 0x28, 0x5e, 0x70, 0xb6,
0xdb,
],
[
0xe6, 0x17, 0x34, 0x6a, 0xc9, 0xc2, 0x31, 0xbb, 0x36, 0x50, 0xae, 0x34, 0xcc, 0xca, 0x0c,
0x5b,
],
[
0x27, 0xd9, 0x34, 0x37, 0xef, 0xb7, 0x21, 0xaa, 0x40, 0x18, 0x21, 0xdc, 0xec, 0x5a, 0xdf,
0x89,
],
[
0x89, 0x23, 0x7d, 0x9d, 0xed, 0x9c, 0x5e, 0x78, 0xd8, 0xb1, 0xc9, 0xb1, 0x66, 0xcc, 0x73,
0x42,
],
[
0x4a, 0x6d, 0x80, 0x91, 0xbf, 0x5e, 0x7d, 0x65, 0x11, 0x89, 0xfa, 0x94, 0xa2, 0x50, 0xb1,
0x4c,
],
[
0x0e, 0x33, 0xf9, 0x60, 0x55, 0xe7, 0xae, 0x89, 0x3f, 0xfc, 0x0e, 0x3d, 0xcf, 0x49, 0x29,
0x02,
],
[
0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1, 0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15,
0x1b,
],
[
0xf7, 0xe5, 0xae, 0xf5, 0x49, 0xf7, 0x82, 0xcf, 0x37, 0x90, 0x55, 0xa6, 0x08, 0x26, 0x9b,
0x16,
],
[
0x43, 0x8d, 0x03, 0x0f, 0xd0, 0xb7, 0xa5, 0x4f, 0xa8, 0x37, 0xf2, 0xad, 0x20, 0x1a, 0x64,
0x03,
],
[
0xa5, 0x90, 0xd3, 0xee, 0x4f, 0xbf, 0x04, 0xe3, 0x24, 0x7e, 0x0d, 0x27, 0xf2, 0x86, 0x42,
0x3f,
],
[
0x5f, 0xe2, 0xc1, 0xa1, 0x72, 0xfe, 0x93, 0xc4, 0xb1, 0x5c, 0xd3, 0x7c, 0xae, 0xf9, 0xf5,
0x38,
],
[
0x2c, 0x97, 0x32, 0x5c, 0xbd, 0x06, 0xb3, 0x6e, 0xb2, 0x13, 0x3d, 0xd0, 0x8b, 0x3a, 0x01,
0x7c,
],
[
0x92, 0xc8, 0x14, 0x22, 0x7a, 0x6b, 0xca, 0x94, 0x9f, 0xf0, 0x65, 0x9f, 0x00, 0x2a, 0xd3,
0x9e,
],
[
0xdc, 0xe8, 0x50, 0x11, 0x0b, 0xd8, 0x32, 0x8c, 0xfb, 0xd5, 0x08, 0x41, 0xd6, 0x91, 0x1d,
0x87,
],
[
0x67, 0xf1, 0x49, 0x84, 0xc7, 0xda, 0x79, 0x12, 0x48, 0xe3, 0x2b, 0xb5, 0x92, 0x25, 0x83,
0xda,
],
[
0x19, 0x38, 0xf2, 0xcf, 0x72, 0xd5, 0x4e, 0xe9, 0x7e, 0x94, 0x16, 0x6f, 0xa9, 0x1d, 0x2a,
0x36,
],
[
0x74, 0x48, 0x1e, 0x96, 0x46, 0xed, 0x49, 0xfe, 0x0f, 0x62, 0x24, 0x30, 0x16, 0x04, 0x69,
0x8e,
],
[
0x57, 0xfc, 0xa5, 0xde, 0x98, 0xa9, 0xd6, 0xd8, 0x00, 0x64, 0x38, 0xd0, 0x58, 0x3d, 0x8a,
0x1d,
],
[
0x9f, 0xec, 0xde, 0x1c, 0xef, 0xdc, 0x1c, 0xbe, 0xd4, 0x76, 0x36, 0x74, 0xd9, 0x57, 0x53,
0x59,
],
[
0xe3, 0x04, 0x0c, 0x00, 0xeb, 0x28, 0xf1, 0x53, 0x66, 0xca, 0x73, 0xcb, 0xd8, 0x72, 0xe7,
0x40,
],
[
0x76, 0x97, 0x00, 0x9a, 0x6a, 0x83, 0x1d, 0xfe, 0xcc, 0xa9, 0x1c, 0x59, 0x93, 0x67, 0x0f,
0x7a,
],
[
0x58, 0x53, 0x54, 0x23, 0x21, 0xf5, 0x67, 0xa0, 0x05, 0xd5, 0x47, 0xa4, 0xf0, 0x47, 0x59,
0xbd,
],
[
0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a, 0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd,
0x7c,
],
[0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01],
[0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63],
[0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95],
[0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43],
[0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25],
[0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e],
[0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8],
[0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77],
[0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99],
[0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42],
[0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4],
[0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e],
[0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65],
[0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44],
[0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78],
[0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09],
[0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93],
[0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec],
[0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b],
[0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9],
[0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7],
[0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef],
[0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79],
[0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59],
[0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a],
[0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2],
[0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64],
[0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93],
[0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14],
[0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86],
[0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06],
[0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10],
[0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3],
[0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b],
[0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9],
[0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f],
[0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40],
[0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10],
[0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93],
[0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c],
[0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38],
[0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3],
[0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02],
[0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56],
[0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a],
[0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58],
[0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8],
[0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37],
[0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08],
[0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f],
[0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66],
[0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a],
[0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca],
[0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b],
[0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b],
[0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22],
[0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84],
[0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10],
[0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69],
[0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e],
[0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61],
[0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7],
[0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18],
[0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad],
];
// Test vector from reference implementation
#[test]
fn test_siphash_2_4_test_vector() {
fn test_siphash_1_3_test_vector() {
let k0 = 0x_07_06_05_04_03_02_01_00;
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;

View file

@ -312,14 +312,14 @@ impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
impl<CTX> HashStable<CTX> for f32 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let val: u32 = unsafe { ::std::mem::transmute(*self) };
let val: u32 = self.to_bits();
val.hash_stable(ctx, hasher);
}
}
impl<CTX> HashStable<CTX> for f64 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let val: u64 = unsafe { ::std::mem::transmute(*self) };
let val: u64 = self.to_bits();
val.hash_stable(ctx, hasher);
}
}

View file

@ -39,7 +39,7 @@ fn test_hash_integers() {
test_isize.hash(&mut h);
// This depends on the hashing algorithm. See note at top of file.
let expected = (1784307454142909076, 11471672289340283879);
let expected = (13997337031081104755, 6178945012502239489);
assert_eq!(h.finalize(), expected);
}
@ -53,7 +53,7 @@ fn test_hash_usize() {
test_usize.hash(&mut h);
// This depends on the hashing algorithm. See note at top of file.
let expected = (5798740672699530587, 11186240177685111648);
let expected = (12037165114281468837, 3094087741167521712);
assert_eq!(h.finalize(), expected);
}
@ -67,7 +67,7 @@ fn test_hash_isize() {
test_isize.hash(&mut h);
// This depends on the hashing algorithm. See note at top of file.
let expected = (2789913510339652884, 674280939192711005);
let expected = (3979067582695659080, 2322428596355037273);
assert_eq!(h.finalize(), expected);
}

View file

@ -5,7 +5,7 @@ const RED_ZONE: usize = 100 * 1024; // 100k
// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
// on. This flag has performance relevant characteristics. Don't set it too high.
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB
/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit

View file

@ -7,9 +7,6 @@
//! while the serial versions degenerate straightforwardly to serial execution.
//! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`.
//!
//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the
//! serial version and `Erased + Send + Sync` for the parallel version.
//!
//! Types
//! -----
//! The parallel versions of types provide various kinds of synchronization,
@ -42,7 +39,7 @@
//!
//! [^2] `MTLockRef` is a typedef.
use crate::owning_ref::{Erased, OwningRef};
use crate::owned_slice::OwnedSlice;
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, DerefMut};
@ -51,24 +48,17 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
pub use std::sync::atomic::Ordering;
pub use std::sync::atomic::Ordering::SeqCst;
pub use vec::AppendOnlyVec;
pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
mod vec;
cfg_if! {
if #[cfg(not(parallel_compiler))] {
pub auto trait Send {}
pub auto trait Sync {}
pub unsafe auto trait Send {}
pub unsafe auto trait Sync {}
impl<T> Send for T {}
impl<T> Sync for T {}
#[macro_export]
macro_rules! rustc_erase_owner {
($v:expr) => {
$v.erase_owner()
}
}
unsafe impl<T> Send for T {}
unsafe impl<T> Sync for T {}
use std::ops::Add;
@ -107,6 +97,14 @@ cfg_if! {
}
}
impl Atomic<bool> {
pub fn fetch_or(&self, val: bool, _: Ordering) -> bool {
let result = self.0.get() | val;
self.0.set(val);
result
}
}
impl<T: Copy + PartialEq> Atomic<T> {
#[inline]
pub fn compare_exchange(&self,
@ -189,7 +187,7 @@ cfg_if! {
}
}
pub type MetadataRef = OwningRef<Box<dyn Erased>, [u8]>;
pub type MetadataRef = OwnedSlice;
pub use std::rc::Rc as Lrc;
pub use std::rc::Weak as Weak;
@ -372,20 +370,11 @@ cfg_if! {
});
}
pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>;
pub type MetadataRef = OwnedSlice;
/// This makes locks panic if they are already held.
/// It is only useful when you are running in a single thread
const ERROR_CHECKING: bool = false;
#[macro_export]
macro_rules! rustc_erase_owner {
($v:expr) => {{
let v = $v;
::rustc_data_structures::sync::assert_send_val(&v);
v.erase_send_sync_owner()
}}
}
}
}
@ -481,14 +470,6 @@ impl<T: Default> Default for Lock<T> {
}
}
// FIXME: Probably a bad idea
impl<T: Clone> Clone for Lock<T> {
#[inline]
fn clone(&self) -> Self {
Lock::new(self.borrow().clone())
}
}
#[derive(Debug, Default)]
pub struct RwLock<T>(InnerRwLock<T>);

View file

@ -2,7 +2,8 @@ use std::marker::PhantomData;
use rustc_index::vec::Idx;
pub struct AppendOnlyVec<I: Idx, T: Copy> {
#[derive(Default)]
pub struct AppendOnlyIndexVec<I: Idx, T: Copy> {
#[cfg(not(parallel_compiler))]
vec: elsa::vec::FrozenVec<T>,
#[cfg(parallel_compiler)]
@ -10,7 +11,7 @@ pub struct AppendOnlyVec<I: Idx, T: Copy> {
_marker: PhantomData<fn(&I)>,
}
impl<I: Idx, T: Copy> AppendOnlyVec<I, T> {
impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {
pub fn new() -> Self {
Self {
#[cfg(not(parallel_compiler))]
@ -39,3 +40,66 @@ impl<I: Idx, T: Copy> AppendOnlyVec<I, T> {
return self.vec.get(i);
}
}
#[derive(Default)]
pub struct AppendOnlyVec<T: Copy> {
#[cfg(not(parallel_compiler))]
vec: elsa::vec::FrozenVec<T>,
#[cfg(parallel_compiler)]
vec: elsa::sync::LockFreeFrozenVec<T>,
}
impl<T: Copy> AppendOnlyVec<T> {
pub fn new() -> Self {
Self {
#[cfg(not(parallel_compiler))]
vec: elsa::vec::FrozenVec::new(),
#[cfg(parallel_compiler)]
vec: elsa::sync::LockFreeFrozenVec::new(),
}
}
pub fn push(&self, val: T) -> usize {
#[cfg(not(parallel_compiler))]
let i = self.vec.len();
#[cfg(not(parallel_compiler))]
self.vec.push(val);
#[cfg(parallel_compiler)]
let i = self.vec.push(val);
i
}
pub fn get(&self, i: usize) -> Option<T> {
#[cfg(not(parallel_compiler))]
return self.vec.get_copy(i);
#[cfg(parallel_compiler)]
return self.vec.get(i);
}
pub fn iter_enumerated(&self) -> impl Iterator<Item = (usize, T)> + '_ {
(0..)
.map(|i| (i, self.get(i)))
.take_while(|(_, o)| o.is_some())
.filter_map(|(i, o)| Some((i, o?)))
}
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
(0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten()
}
}
impl<T: Copy + PartialEq> AppendOnlyVec<T> {
pub fn contains(&self, val: T) -> bool {
self.iter_enumerated().any(|(_, v)| v == val)
}
}
impl<A: Copy> FromIterator<A> for AppendOnlyVec<A> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
let this = Self::new();
for val in iter {
this.push(val);
}
this
}
}

View file

@ -224,7 +224,7 @@ impl<V: Eq + Hash> UnordSet<V> {
}
#[inline]
pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
pub fn items(&self) -> UnordItems<&V, impl Iterator<Item = &V>> {
UnordItems(self.inner.iter())
}
@ -415,7 +415,7 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
}
#[inline]
pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator<Item = (&K, &V)>> {
UnordItems(self.inner.iter())
}

View file

@ -44,8 +44,10 @@ use rustc_session::{early_error, early_error_no_abort, early_warn};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTriple};
use std::cmp::max;
use std::collections::BTreeMap;
use std::env;
use std::ffi::OsString;
use std::fs;
@ -648,6 +650,15 @@ fn print_crate_info(
TargetSpec => {
println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
}
AllTargetSpecs => {
let mut targets = BTreeMap::new();
for name in rustc_target::spec::TARGETS {
let triple = TargetTriple::from_triple(name);
let target = Target::expect_builtin(&triple);
targets.insert(name, target.to_json());
}
println!("{}", serde_json::to_string_pretty(&targets).unwrap());
}
FileNames | CrateName => {
let Some(attrs) = attrs.as_ref() else {
// no crate attributes, print out an error and exit

View file

@ -956,7 +956,7 @@ impl Diagnostic {
// Exact iteration order of diagnostic arguments shouldn't make a difference to output because
// they're only used in interpolation.
#[allow(rustc::potential_query_instability)]
pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
pub fn args(&self) -> impl Iterator<Item = DiagnosticArg<'_, 'static>> {
self.args.iter()
}

View file

@ -1407,7 +1407,7 @@ impl EmitterWriter {
// Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(&text).lines().enumerate() {
buffer.append(
0 + line,
line,
&format!(
"{}{}",
if line == 0 { String::new() } else { " ".repeat(label_width) },
@ -1918,7 +1918,7 @@ impl EmitterWriter {
let last_line = unhighlighted_lines.pop();
let first_line = unhighlighted_lines.drain(..).next();
first_line.map(|(p, l)| {
if let Some((p, l)) = first_line {
self.draw_code_line(
&mut buffer,
&mut row_num,
@ -1930,12 +1930,12 @@ impl EmitterWriter {
&file_lines,
is_multiline,
)
});
}
buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
row_num += 1;
last_line.map(|(p, l)| {
if let Some((p, l)) = last_line {
self.draw_code_line(
&mut buffer,
&mut row_num,
@ -1947,7 +1947,7 @@ impl EmitterWriter {
&file_lines,
is_multiline,
)
});
}
}
}

View file

@ -620,10 +620,15 @@ impl<'a> ExtCtxt<'a> {
span: Span,
name: Ident,
ty: P<ast::Ty>,
mutbl: ast::Mutability,
mutability: ast::Mutability,
expr: P<ast::Expr>,
) -> P<ast::Item> {
self.item(span, name, AttrVec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr)))
self.item(
span,
name,
AttrVec::new(),
ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()),
)
}
pub fn item_const(
@ -633,8 +638,13 @@ impl<'a> ExtCtxt<'a> {
ty: P<ast::Ty>,
expr: P<ast::Expr>,
) -> P<ast::Item> {
let def = ast::Defaultness::Final;
self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr)))
let defaultness = ast::Defaultness::Final;
self.item(
span,
name,
AttrVec::new(),
ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()),
)
}
// Builds `#[name]`.

View file

@ -466,7 +466,7 @@ impl<'a> StripUnconfigured<'a> {
//
// N.B., this is intentionally not part of the visit_expr() function
// in order for filter_map_expr() to be able to avoid this check
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) {
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
self.sess.emit_err(RemoveExprNotSupported { span: attr.span });
}

View file

@ -41,7 +41,7 @@ impl MetaVarExpr {
};
check_trailing_token(&mut tts, sess)?;
let mut iter = args.trees();
let rslt = match &*ident.as_str() {
let rslt = match ident.as_str() {
"count" => parse_count(&mut iter, sess, ident.span)?,
"ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
"index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),

View file

@ -518,6 +518,8 @@ declare_features! (
/// Allows dyn upcasting trait objects via supertraits.
/// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
(active, trait_upcasting, "1.56.0", Some(65991), None),
/// Allows for transmuting between arrays with sizes that contain generic consts.
(active, transmute_generic_consts, "CURRENT_RUSTC_VERSION", Some(109929), None),
/// Allows #[repr(transparent)] on unions (RFC 2645).
(active, transparent_unions, "1.37.0", Some(60405), None),
/// Allows inconsistent bounds in where clauses.

View file

@ -49,7 +49,7 @@ impl LanguageItems {
self.get(it).ok_or_else(|| LangItemError(it))
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (LangItem, DefId)> + 'a {
pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ {
self.items
.iter()
.enumerate()

View file

@ -2,7 +2,6 @@ use crate::def::{CtorOf, DefKind, Res};
use crate::def_id::DefId;
use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::Ident;
use rustc_span::Span;
@ -136,14 +135,4 @@ impl hir::Pat<'_> {
});
result
}
/// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
pub fn for_loop_some(&self) -> Option<&Self> {
if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
return Some(pat_field.pat);
}
}
None
}
}

View file

@ -189,3 +189,39 @@ hir_analysis_return_type_notation_equality_bound =
hir_analysis_return_type_notation_missing_method =
cannot find associated function `{$assoc_name}` in trait `{$trait_name}`
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
.suggestion = use a fully qualified path with inferred lifetimes
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
.label = overflowed on value after {$discr}
.note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
.note = required by this annotation
hir_analysis_must_implement_not_function = not a function
hir_analysis_must_implement_not_function_span_note = required by this annotation
hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
hir_analysis_function_not_found_in_trait = function not found in this trait
hir_analysis_functions_names_duplicated = functions names are duplicated
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
.help = add `#![feature(simd_ffi)]` to the crate attributes to enable

View file

@ -33,9 +33,9 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{DynKind, ToPredicate};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
@ -1526,8 +1526,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
assert_eq!(constness, ty::BoundConstness::NotConst);
for pred in traits::elaborate_trait_ref(tcx, base_trait_ref) {
let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
for pred in traits::elaborate(tcx, [base_pred]) {
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
let bound_predicate = pred.kind();
@ -2336,10 +2336,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
FnMutDelegate {
regions: &mut |_| tcx.lifetimes.re_erased,
types: &mut |bv| {
tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind })
tcx.mk_placeholder(ty::PlaceholderType { universe, bound: bv })
},
consts: &mut |bv, ty| {
tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty)
tcx.mk_const(ty::PlaceholderConst { universe, bound: bv }, ty)
},
},
);
@ -2525,11 +2525,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
regions: &mut |_| tcx.lifetimes.re_erased,
types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType {
universe,
name: bv.kind,
bound: bv,
}),
consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst {
universe,
name: bv
bound: bv,
}, ty),
})
)

View file

@ -2034,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>(
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
};
let obligations = tcx
let obligations: Vec<_> = tcx
.bound_explicit_item_bounds(trait_ty.def_id)
.subst_iter_copied(tcx, rebased_substs)
.map(|(concrete_ty_bound, span)| {
@ -2044,7 +2044,7 @@ pub(super) fn check_type_bounds<'tcx>(
.collect();
debug!("check_type_bounds: item_bounds={:?}", obligations);
for mut obligation in util::elaborate_obligations(tcx, obligations) {
for mut obligation in util::elaborate(tcx, obligations) {
let normalized_predicate =
ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);

View file

@ -253,10 +253,6 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
self.tcx
}
fn intercrate(&self) -> bool {
false
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@ -269,10 +265,6 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
true
}
fn mark_ambiguous(&mut self) {
bug!()
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,

View file

@ -139,14 +139,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(&[
ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
ty::BoundVariableKind::Region(ty::BrAnon(None)),
ty::BoundVariableKind::Region(ty::BrEnv),
]);
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
let region = tcx.mk_re_late_bound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
);
let env_region = tcx.mk_re_late_bound(
ty::INNERMOST,
@ -387,8 +387,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
);
let discriminant_def_id = assoc_items[0];
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
(
1,
vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))],
@ -440,8 +439,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::raw_eq => {
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0));
(1, vec![param_ty; 2], tcx.types.bool)
}

View file

@ -1908,7 +1908,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied();
// Check elaborated bounds.
let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span);
let implied_obligations = traits::elaborate(tcx, predicates_with_span);
for (pred, obligation_span) in implied_obligations {
// We lower empty bounds like `Vec<dyn Copy>:` as

View file

@ -302,7 +302,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
.iter()
.flatten()
.map(|r| r.impl_blocks.len() as isize - avg as isize)
.map(|v| v.abs() as usize)
.map(|v| v.unsigned_abs())
.sum::<usize>();
s / connected_regions.len()
},

View file

@ -20,7 +20,7 @@ use crate::errors;
use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
@ -333,17 +333,7 @@ fn bad_placeholder<'tcx>(
let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) };
spans.sort();
let mut err = struct_span_err!(
tcx.sess,
spans.clone(),
E0121,
"the placeholder `_` is not allowed within types on item signatures for {}",
kind
);
for span in spans {
err.span_label(span, "not allowed in type signatures");
}
err
tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
}
impl<'tcx> ItemCtxt<'tcx> {
@ -419,13 +409,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
self.tcx().mk_projection(item_def_id, item_substs)
} else {
// There are no late-bound regions; we can just ignore the binder.
let mut err = struct_span_err!(
self.tcx().sess,
span,
E0212,
"cannot use the associated type of a trait \
with uninferred generic parameters"
);
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
let mut bound = String::new();
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
@ -444,31 +429,25 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
(bound.span.shrink_to_lo(), format!("{}, ", lt_name))
}
};
let suggestions = vec![
(lt_sp, sugg),
(
span.with_hi(item_segment.ident.span.lo()),
format!(
"{}::",
// Replace the existing lifetimes with a new named lifetime.
self.tcx.replace_late_bound_regions_uncached(
poly_trait_ref,
|_| {
self.tcx.mk_re_early_bound(ty::EarlyBoundRegion {
def_id: item_def_id,
index: 0,
name: Symbol::intern(&lt_name),
})
}
),
mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion {
fspan: lt_sp,
first: sugg,
sspan: span.with_hi(item_segment.ident.span.lo()),
second: format!(
"{}::",
// Replace the existing lifetimes with a new named lifetime.
self.tcx.replace_late_bound_regions_uncached(
poly_trait_ref,
|_| {
self.tcx.mk_re_early_bound(ty::EarlyBoundRegion {
def_id: item_def_id,
index: 0,
name: Symbol::intern(&lt_name),
})
}
),
),
];
err.multipart_suggestion(
"use a fully qualified path with explicit lifetimes",
suggestions,
Applicability::MaybeIncorrect,
);
});
}
_ => {}
}
@ -482,20 +461,23 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
| hir::Node::ForeignItem(_)
| hir::Node::TraitItem(_)
| hir::Node::ImplItem(_) => {
err.span_suggestion_verbose(
span.with_hi(item_segment.ident.span.lo()),
"use a fully qualified path with inferred lifetimes",
format!(
"{}::",
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
),
Applicability::MaybeIncorrect,
inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo()));
bound = format!(
"{}::",
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
);
}
_ => {}
}
self.tcx().ty_error(err.emit())
self.tcx().ty_error(self.tcx().sess.emit_err(
errors::AssociatedTypeTraitUninferredGenericParams {
span,
inferred_sugg,
bound,
mpart_sugg,
},
))
}
}
@ -763,14 +745,12 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
Some(discr)
} else {
let span = tcx.def_span(variant.def_id);
struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
.span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
.note(&format!(
"explicitly set `{} = {}` if that is desired outcome",
tcx.item_name(variant.def_id),
wrapped_discr
))
.emit();
tcx.sess.emit_err(errors::EnumDiscriminantOverflowed {
span,
discr: prev_discr.unwrap().to_string(),
item_name: tcx.item_name(variant.def_id),
wrapped_discr: wrapped_discr.to_string(),
});
None
}
.unwrap_or(wrapped_discr),
@ -915,14 +895,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
if paren_sugar && !tcx.features().unboxed_closures {
tcx.sess
.struct_span_err(
item.span,
"the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
which traits can use parenthetical notation",
)
.help("add `#![feature(unboxed_closures)]` to the crate attributes to use it")
.emit();
tcx.sess.emit_err(errors::ParenSugarAttribute { span: item.span });
}
let is_marker = tcx.has_attr(def_id, sym::marker);
@ -942,13 +915,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
// and that they are all identifiers
.and_then(|attr| match attr.meta_item_list() {
Some(items) if items.len() < 2 => {
tcx.sess
.struct_span_err(
attr.span,
"the `#[rustc_must_implement_one_of]` attribute must be \
used with at least 2 args",
)
.emit();
tcx.sess.emit_err(errors::MustImplementOneOfAttribute { span: attr.span });
None
}
@ -957,9 +924,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
.map(|item| item.ident().ok_or(item.span()))
.collect::<Result<Box<[_]>, _>>()
.map_err(|span| {
tcx.sess
.struct_span_err(span, "must be a name of an associated function")
.emit();
tcx.sess.emit_err(errors::MustBeNameOfAssociatedFunction { span });
})
.ok()
.zip(Some(attr.span)),
@ -975,13 +940,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
if !tcx.impl_defaultness(item.id.owner_id).has_value() {
tcx.sess
.struct_span_err(
item.span,
"function doesn't have a default implementation",
)
.span_note(attr_span, "required by this annotation")
.emit();
tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation {
span: item.span,
note_span: attr_span,
});
return Some(());
}
@ -989,19 +951,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
return None;
}
Some(item) => {
tcx.sess
.struct_span_err(item.span, "not a function")
.span_note(attr_span, "required by this annotation")
.note(
"all `#[rustc_must_implement_one_of]` arguments must be associated \
function names",
)
.emit();
tcx.sess.emit_err(errors::MustImplementNotFunction {
span: item.span,
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
note: errors::MustImplementNotFunctionNote {},
});
}
None => {
tcx.sess
.struct_span_err(ident.span, "function not found in this trait")
.emit();
tcx.sess.emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
}
}
@ -1018,9 +975,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
for ident in &*list {
if let Some(dup) = set.insert(ident.name, ident.span) {
tcx.sess
.struct_span_err(vec![dup, ident.span], "functions names are duplicated")
.note("all `#[rustc_must_implement_one_of]` arguments must be unique")
.emit();
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
no_dups = false;
}
@ -1485,17 +1440,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
.source_map()
.span_to_snippet(ast_ty.span)
.map_or_else(|_| String::new(), |s| format!(" `{}`", s));
tcx.sess
.struct_span_err(
ast_ty.span,
&format!(
"use of SIMD type{} in FFI is highly experimental and \
may result in invalid code",
snip
),
)
.help("add `#![feature(simd_ffi)]` to the crate attributes to enable")
.emit();
tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip });
}
};
for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {

View file

@ -130,7 +130,7 @@ pub(super) fn item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
let bounds = tcx.mk_predicates_from_iter(util::elaborate_predicates(
let bounds = tcx.mk_predicates_from_iter(util::elaborate(
tcx,
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
));

View file

@ -507,3 +507,127 @@ pub(crate) struct ReturnTypeNotationMissingMethod {
pub trait_name: Symbol,
pub assoc_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
pub(crate) struct PlaceholderNotAllowedItemSignatures {
#[primary_span]
#[label]
pub spans: Vec<Span>,
pub kind: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = "E0212")]
pub(crate) struct AssociatedTypeTraitUninferredGenericParams {
#[primary_span]
pub span: Span,
#[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")]
pub inferred_sugg: Option<Span>,
pub bound: String,
#[subdiagnostic]
pub mpart_sugg: Option<AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion,
applicability = "maybe-incorrect"
)]
pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion {
#[suggestion_part(code = "{first}")]
pub fspan: Span,
pub first: String,
#[suggestion_part(code = "{second}")]
pub sspan: Span,
pub second: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_enum_discriminant_overflowed, code = "E0370")]
#[note]
pub(crate) struct EnumDiscriminantOverflowed {
#[primary_span]
#[label]
pub span: Span,
pub discr: String,
pub item_name: Symbol,
pub wrapped_discr: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_paren_sugar_attribute)]
#[help]
pub(crate) struct ParenSugarAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_must_implement_one_of_attribute)]
pub(crate) struct MustImplementOneOfAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_must_be_name_of_associated_function)]
pub(crate) struct MustBeNameOfAssociatedFunction {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_function_not_have_default_implementation)]
pub(crate) struct FunctionNotHaveDefaultImplementation {
#[primary_span]
pub span: Span,
#[note]
pub note_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_must_implement_not_function)]
pub(crate) struct MustImplementNotFunction {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub span_note: MustImplementNotFunctionSpanNote,
#[subdiagnostic]
pub note: MustImplementNotFunctionNote,
}
#[derive(Subdiagnostic)]
#[note(hir_analysis_must_implement_not_function_span_note)]
pub(crate) struct MustImplementNotFunctionSpanNote {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[note(hir_analysis_must_implement_not_function_note)]
pub(crate) struct MustImplementNotFunctionNote {}
#[derive(Diagnostic)]
#[diag(hir_analysis_function_not_found_in_trait)]
pub(crate) struct FunctionNotFoundInTrait {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_functions_names_duplicated)]
#[note]
pub(crate) struct FunctionNamesDuplicated {
#[primary_span]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_simd_ffi_highly_experimental)]
#[help]
pub(crate) struct SIMDFFIHighlyExperimental {
#[primary_span]
pub span: Span,
pub snip: String,
}

View file

@ -318,15 +318,14 @@ fn check_predicates<'tcx>(
span: Span,
) {
let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
let impl1_predicates: Vec<_> =
traits::elaborate_predicates_with_span(tcx, instantiated.into_iter()).collect();
let impl1_predicates: Vec<_> = traits::elaborate(tcx, instantiated.into_iter()).collect();
let mut impl2_predicates = if impl2_node.is_from_trait() {
// Always applicable traits have to be always applicable without any
// assumptions.
Vec::new()
} else {
traits::elaborate_predicates(
traits::elaborate(
tcx,
tcx.predicates_of(impl2_node.def_id())
.instantiate(tcx, impl2_substs)
@ -371,11 +370,10 @@ fn check_predicates<'tcx>(
.unwrap();
assert!(!obligations.needs_infer());
impl2_predicates.extend(
traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
)
impl2_predicates
.extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate))
}
impl2_predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits));
impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits));
for (predicate, span) in impl1_predicates {
if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {

View file

@ -70,7 +70,6 @@ This API is completely unstable and subject to change.
#![feature(lazy_cell)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]
#![feature(is_some_and)]
#![feature(type_alias_impl_trait)]
#![recursion_limit = "256"]

View file

@ -242,7 +242,7 @@ pub fn enum_def_to_string(
impl<'a> State<'a> {
pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
self.maybe_print_comment(span.hi());
self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
self.break_offset_if_not_bol(1, -INDENT_UNIT);
self.word("}");
if close_box {
self.end(); // close the outer-box

View file

@ -538,8 +538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(rpitit): This will need to be fixed when we move to associated types
assert!(matches!(
*trait_pred.trait_ref.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if def_id == rpit_def_id && substs == substs
ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
if def_id == rpit_def_id && substs == alias_substs
));
ty::PredicateKind::Clause(ty::Clause::Trait(
trait_pred.with_self_ty(self.tcx, ty),
@ -548,8 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert!(matches!(
*proj_pred.projection_ty.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if def_id == rpit_def_id && substs == substs
ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
if def_id == rpit_def_id && substs == alias_substs
));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))

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