Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #110821

Merged
merged 21 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
77c83c0
Add `impl_tag!` macro to implement `Tag` for tagged pointer easily
WaffleLapkin Apr 20, 2023
0892a73
change usages of explicit_item_bounds to bound_explicit_item_bounds
kylematsuda Apr 17, 2023
f3b279f
add EarlyBinder to output of explicit_item_bounds; replace bound_expl…
kylematsuda Apr 17, 2023
e54854f
add subst_identity_iter and subst_identity_iter_copied methods on Ear…
kylematsuda Apr 17, 2023
96905d5
Use `impl Tag for $T` syntax for `impl_tag!`
WaffleLapkin Apr 20, 2023
7cfecf2
Remove confusing comment
WaffleLapkin Apr 20, 2023
ad8c7b6
Simplify `bits_for_tags` impl
WaffleLapkin Apr 20, 2023
5731655
Fix no_global_oom_handling build
arlosi Apr 21, 2023
5a69b5d
Changes from review
kylematsuda Apr 20, 2023
2b8d27b
Switch `impl_tag!` from explicit tags to `${index()}`
WaffleLapkin Apr 24, 2023
794cb89
Consider polarity in new solver
compiler-errors Apr 22, 2023
bb2cb89
Negative coherence test
compiler-errors Apr 24, 2023
3b196fb
Updating Wake example to use new 'pin!' macro
madsravn Apr 25, 2023
040e1b6
Fix ICE on --print=... i/o errors
dtolnay Apr 25, 2023
bec7ce4
Add `#[inline]` in `impl_tag`
WaffleLapkin Apr 25, 2023
297b222
Rollup merge of #110556 - kylematsuda:earlybinder-explicit-item-bound…
matthiaskrgr Apr 25, 2023
8d00a8d
Rollup merge of #110615 - WaffleLapkin:impl_tag, r=cjgillot
matthiaskrgr Apr 25, 2023
94dfb3b
Rollup merge of #110649 - arlosi:fix_no_global_oom_handling, r=Mark-S…
matthiaskrgr Apr 25, 2023
95e9f68
Rollup merge of #110671 - compiler-errors:polarity, r=lcnr
matthiaskrgr Apr 25, 2023
f5a3039
Rollup merge of #110783 - dtolnay:safeprint, r=petrochenkov
matthiaskrgr Apr 25, 2023
77752a0
Rollup merge of #110796 - madsravn:wake-example, r=Mark-Simulacrum
matthiaskrgr Apr 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.copied()
.find_map(find_fn_kind_from_did),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
.bound_explicit_item_bounds(def_id)
.explicit_item_bounds(def_id)
.subst_iter_copied(tcx, substs)
.find_map(find_fn_kind_from_did),
ty::Closure(_, substs) => match substs.as_closure().kind() {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#![feature(unwrap_infallible)]
#![feature(strict_provenance)]
#![feature(ptr_alignment_type)]
#![feature(macro_metavar_expr)]
#![allow(rustc::default_hash_types)]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
Expand Down
31 changes: 25 additions & 6 deletions compiler/rustc_data_structures/src/tagged_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::aligned::Aligned;

mod copy;
mod drop;
mod impl_tag;

pub use copy::CopyTaggedPtr;
pub use drop::TaggedPtr;
Expand Down Expand Up @@ -141,6 +142,30 @@ pub unsafe trait Tag: Copy {
unsafe fn from_usize(tag: usize) -> Self;
}

/// Returns the number of bits available for use for tags in a pointer to `T`
/// (this is based on `T`'s alignment).
pub const fn bits_for<T: ?Sized + Aligned>() -> u32 {
crate::aligned::align_of::<T>().as_nonzero().trailing_zeros()
}

/// Returns the correct [`Tag::BITS`] constant for a set of tag values.
pub const fn bits_for_tags(mut tags: &[usize]) -> u32 {
let mut bits = 0;

while let &[tag, ref rest @ ..] = tags {
tags = rest;

// bits required to represent `tag`,
// position of the most significant 1
let b = usize::BITS - tag.leading_zeros();
if b > bits {
bits = b;
}
}

bits
}

unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
const BITS: u32 = bits_for::<Self::Target>();

Expand Down Expand Up @@ -221,12 +246,6 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T {
}
}

/// Returns the number of bits available for use for tags in a pointer to `T`
/// (this is based on `T`'s alignment).
pub const fn bits_for<T: ?Sized + Aligned>() -> u32 {
crate::aligned::align_of::<T>().as_nonzero().trailing_zeros()
}

/// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg(test)]
Expand Down
144 changes: 144 additions & 0 deletions compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/// Implements [`Tag`] for a given type.
///
/// You can use `impl_tag` on structs and enums.
/// You need to specify the type and all its possible values,
/// which can only be paths with optional fields.
///
/// [`Tag`]: crate::tagged_ptr::Tag
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
///
/// #[derive(Copy, Clone, PartialEq, Debug)]
/// enum SomeTag {
/// A,
/// B,
/// X { v: bool },
/// Y(bool, bool),
/// }
///
/// impl_tag! {
/// // The type for which the `Tag` will be implemented
/// impl Tag for SomeTag;
/// // You need to specify all possible tag values:
/// SomeTag::A, // 0
/// SomeTag::B, // 1
/// // For variants with fields, you need to specify the fields:
/// SomeTag::X { v: true }, // 2
/// SomeTag::X { v: false }, // 3
/// // For tuple variants use named syntax:
/// SomeTag::Y { 0: true, 1: true }, // 4
/// SomeTag::Y { 0: false, 1: true }, // 5
/// SomeTag::Y { 0: true, 1: false }, // 6
/// SomeTag::Y { 0: false, 1: false }, // 7
/// }
///
/// // Tag values are assigned in order:
/// assert_eq!(SomeTag::A.into_usize(), 0);
/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
///
/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
/// ```
///
/// Structs are supported:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// struct Flags { a: bool, b: bool }
///
/// impl_tag! {
/// impl Tag for Flags;
/// Flags { a: true, b: true },
/// Flags { a: false, b: true },
/// Flags { a: true, b: false },
/// Flags { a: false, b: false },
/// }
/// ```
///
/// Not specifying all values results in a compile error:
///
/// ```compile_fail,E0004
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// enum E {
/// A,
/// B,
/// }
///
/// impl_tag! {
/// impl Tag for E;
/// E::A,
/// }
/// ```
#[macro_export]
macro_rules! impl_tag {
(
impl Tag for $Self:ty;
$(
$($path:ident)::* $( { $( $fields:tt )* })?,
)*
) => {
// Safety:
// `bits_for_tags` is called on the same `${index()}`-es as
// `into_usize` returns, thus `BITS` constant is correct.
unsafe impl $crate::tagged_ptr::Tag for $Self {
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
$(
${index()},
$( ${ignore(path)} )*
)*
]);

#[inline]
fn into_usize(self) -> usize {
// This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
// (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
#[forbid(unreachable_patterns)]
match self {
// `match` is doing heavy lifting here, by requiring exhaustiveness
$(
$($path)::* $( { $( $fields )* } )? => ${index()},
)*
}
}

#[inline]
unsafe fn from_usize(tag: usize) -> Self {
match tag {
$(
${index()} => $($path)::* $( { $( $fields )* } )?,
)*

// Safety:
// `into_usize` only returns `${index()}` of the same
// repetition as we are filtering above, thus if this is
// reached, the safety contract of this function was
// already breached.
_ => unsafe {
debug_assert!(
false,
"invalid tag: {tag}\
(this is a bug in the caller of `from_usize`)"
);
std::hint::unreachable_unchecked()
},
}
}

}
};
}

#[cfg(test)]
mod tests;
34 changes: 34 additions & 0 deletions compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#[test]
fn bits_constant() {
use crate::tagged_ptr::Tag;

#[derive(Copy, Clone)]
struct Unit;
impl_tag! { impl Tag for Unit; Unit, }
assert_eq!(Unit::BITS, 0);

#[derive(Copy, Clone)]
enum Enum3 {
A,
B,
C,
}
impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, }
assert_eq!(Enum3::BITS, 2);

#[derive(Copy, Clone)]
struct Eight(bool, bool, bool);
impl_tag! {
impl Tag for Eight;
Eight { 0: true, 1: true, 2: true },
Eight { 0: true, 1: true, 2: false },
Eight { 0: true, 1: false, 2: true },
Eight { 0: true, 1: false, 2: false },
Eight { 0: false, 1: true, 2: true },
Eight { 0: false, 1: true, 2: false },
Eight { 0: false, 1: false, 2: true },
Eight { 0: false, 1: false, 2: false },
}

assert_eq!(Eight::BITS, 3);
}
Loading