Skip to content

Commit

Permalink
Start using pattern types in libcore
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Jan 27, 2025
1 parent 6c6b492 commit ed90eb8
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 30 deletions.
14 changes: 9 additions & 5 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2153,11 +2153,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
);
let ty_from = op.ty(body, tcx);
match ty_from.kind() {
ty::Pat(base, _) if base == ty => {}
_ => span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
),
}
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,18 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
ty::Pat(base, _) => return type_di_node(cx, base),
// FIXME(unsafe_binders): impl debug info
ty::UnsafeBinder(_) => unimplemented!(),
ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Infer(_)
| ty::Placeholder(_)
| ty::CoroutineWitness(..)
| ty::Error(_) => {
bug!("debuginfo: unexpected type in type_di_node(): {:?}", t)
}
};

{
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_lint/src/foreign_modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>(
if let ty::Adt(def, args) = *ty.kind() {
let is_transparent = def.repr().transparent();
let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
debug!(
"non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
ty, is_transparent, is_non_null
);
debug!(?ty, is_transparent, is_non_null);
if is_transparent && !is_non_null {
debug_assert_eq!(def.variants().len(), 1);
let v = &def.variant(FIRST_VARIANT);
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,9 +891,8 @@ fn get_nullable_type<'tcx>(
};
return get_nullable_type(tcx, typing_env, inner_field_ty);
}
ty::Int(ty) => Ty::new_int(tcx, ty),
ty::Uint(ty) => Ty::new_uint(tcx, ty),
ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base),
ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty,
// As these types are always non-null, the nullable equivalent of
// `Option<T>` of these types are their raw pointer counterparts.
ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
Expand Down Expand Up @@ -934,6 +933,7 @@ fn is_niche_optimization_candidate<'tcx>(
!non_exhaustive && empty
}
ty::Tuple(tys) => tys.is_empty(),
ty::Pat(..) => true,
_ => false,
}
}
Expand Down Expand Up @@ -1240,11 +1240,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
help: Some(fluent::lint_improper_ctypes_char_help),
},

ty::Pat(..) => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_pat_reason,
help: Some(fluent::lint_improper_ctypes_pat_help),
},
// It's just extra invariants on the type that you need to uphold,
// but only the base type is relevant for being representable in FFI.
ty::Pat(base, ..) => self.check_type_for_ffi(acc, base),

ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
Expand Down
28 changes: 26 additions & 2 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);

let expect_ty = value.ty();
let expect = self.literal_operand(test.span, value);
let mut expect_ty = value.ty();
let mut expect = self.literal_operand(test.span, value);

let mut place = place;
let mut block = block;
Expand Down Expand Up @@ -177,6 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place = ref_str;
ty = ref_str_ty;
}
&ty::Pat(base, _) => {
assert_eq!(ty, value.ty());

let transmuted_place = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(scrutinee_span),
transmuted_place,
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
);

let transmuted_expect = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(test.span),
transmuted_expect,
Rvalue::Cast(CastKind::Transmute, expect, base),
);

place = transmuted_place;
expect = Operand::Copy(transmuted_expect);
ty = base;
expect_ty = base;
}
_ => {}
}

Expand Down
2 changes: 2 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@
#![feature(no_core)]
#![feature(no_sanitize)]
#![feature(optimize_attribute)]
#![feature(pattern_type_macro)]
#![feature(pattern_types)]
#![feature(prelude_import)]
#![feature(repr_simd)]
#![feature(rustc_allow_const_fn_unstable)]
Expand Down
19 changes: 15 additions & 4 deletions library/core/src/num/niche_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,28 @@ use crate::cmp::Ordering;
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::StructuralPartialEq;
#[cfg(not(bootstrap))]
use crate::pattern_type;

macro_rules! define_valid_range_type {
($(
$(#[$m:meta])*
$vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
)+) => {$(
#[derive(Clone, Copy, Eq)]
#[derive(Clone, Copy)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start($low)]
#[rustc_layout_scalar_valid_range_end($high)]
#[cfg_attr(bootstrap, rustc_layout_scalar_valid_range_start($low))]
#[cfg_attr(bootstrap, rustc_layout_scalar_valid_range_end($high))]
$(#[$m])*
#[cfg(bootstrap)]
$vis struct $name($int);

#[derive(Clone, Copy)]
#[repr(transparent)]
$(#[$m])*
#[cfg(not(bootstrap))]
$vis struct $name(pattern_type!($int is $low..=$high));

const _: () = {
// With the `valid_range` attributes, it's always specified as unsigned
assert!(<$uint>::MIN == 0);
Expand All @@ -41,7 +50,7 @@ macro_rules! define_valid_range_type {
#[inline]
pub const unsafe fn new_unchecked(val: $int) -> Self {
// SAFETY: Caller promised that `val` is non-zero.
unsafe { $name(val) }
unsafe { $name(crate::mem::transmute(val)) }
}

#[inline]
Expand All @@ -57,6 +66,8 @@ macro_rules! define_valid_range_type {
// by <https://github.com/rust-lang/compiler-team/issues/807>.
impl StructuralPartialEq for $name {}

impl Eq for $name {}

impl PartialEq for $name {
#[inline]
fn eq(&self, other: &Self) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/consts/const-eval/raw-bytes.64bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:59:1
|
LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
Expand All @@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:61:1
|
LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/consts/const-eval/ub-nonnull.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-nonnull.rs:24:1
|
LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
Expand All @@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-nonnull.rs:26:1
|
LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/lint/invalid_value.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ LL | let _val: (NonZero<u32>, i32) = mem::uninitialized();
|
= note: `std::num::NonZero<u32>` must be non-null
= note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
= note: integers must be initialized

error: the type `*const dyn Send` does not permit zero-initialization
--> $DIR/invalid_value.rs:97:37
Expand Down Expand Up @@ -430,7 +429,6 @@ note: because `std::num::NonZero<u32>` must be non-null (in this field of the on
LL | Banana(NonZero<u32>),
| ^^^^^^^^^^^^
= note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
= note: integers must be initialized

error: the type `bool` does not permit being left uninitialized
--> $DIR/invalid_value.rs:111:26
Expand Down
25 changes: 25 additions & 0 deletions tests/ui/type/pattern_types/matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![feature(pattern_types, pattern_type_macro, structural_match)]

//@ check-pass

use std::marker::StructuralPartialEq;
use std::pat::pattern_type;

struct Thing(pattern_type!(u32 is 1..));

impl StructuralPartialEq for Thing {}
impl Eq for Thing {}
impl PartialEq for Thing {
fn eq(&self, other: &Thing) -> bool {
todo!()
}
}

const TWO: Thing = Thing(unsafe { std::mem::transmute(2_u32) });

const _: () = match TWO {
TWO => {}
_ => unreachable!(),
};

fn main() {}

0 comments on commit ed90eb8

Please sign in to comment.