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:
commit
2c455530e1
961 changed files with 10733 additions and 9476 deletions
|
|
@ -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
2
.gitmodules
vendored
|
|
@ -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
|
||||
|
|
|
|||
68
Cargo.lock
68
Cargo.lock
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
(
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 } => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 }),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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: _ } => {
|
||||
|
|
|
|||
|
|
@ -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 { .. }
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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")),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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 { .. }
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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), &[]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<'_>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>`.
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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 { .. }
|
||||
|
|
|
|||
|
|
@ -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 { .. }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
118
compiler/rustc_data_structures/src/owned_slice.rs
Normal file
118
compiler/rustc_data_structures/src/owned_slice.rs
Normal 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;
|
||||
74
compiler/rustc_data_structures/src/owned_slice/tests.rs
Normal file
74
compiler/rustc_data_structures/src/owned_slice/tests.rs
Normal 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>();
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 => (),
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]`.
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)?),
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(<_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(<_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()) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue