From 0afd16bc9f3843e4801169c55e4414a3484aa769 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH] Start using pattern types in libcore --- .../src/debuginfo/metadata.rs | 13 ++++++- compiler/rustc_lint/src/foreign_modules.rs | 5 +-- compiler/rustc_lint/src/types.rs | 18 +++++---- .../src/builder/matches/test.rs | 6 +++ library/core/src/lib.rs | 2 + library/core/src/num/niche_types.rs | 19 ++++++++-- .../consts/const-eval/raw-bytes.64bit.stderr | 4 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 4 +- tests/ui/lint/clashing-extern-fn.stderr | 38 ++++++++++++++++++- tests/ui/lint/invalid_value.stderr | 2 - tests/ui/type/pattern_types/matching.rs | 23 +++++++++++ tests/ui/type/pattern_types/matching.stderr | 20 ++++++++++ 12 files changed, 130 insertions(+), 24 deletions(-) create mode 100644 tests/ui/type/pattern_types/matching.rs create mode 100644 tests/ui/type/pattern_types/matching.stderr diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 8d782a618fc07..6b70c50ba6ba3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -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) + } }; { diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 45b188205d228..f7e2f308ca1b5 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -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); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0060f33888ebd..0e931b0fe6968 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -891,9 +891,13 @@ 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, pat) + if let ty::PatternKind::Range { start: Some(start), end: None, .. } = *pat + && start.try_to_bits(tcx, typing_env) == Some(1) => + { + base + } + ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty, // As these types are always non-null, the nullable equivalent of // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), @@ -1240,11 +1244,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 } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 4bd757fbfc493..dfd8b4bd329ec 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -177,6 +177,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place = ref_str; ty = ref_str_ty; } + &ty::Pat(base, _) => { + assert_eq!(ty, value.ty()); + + ty = base; + expect_ty = base; + } _ => {} } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c18e0405f7293..c944d2f884e39 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs index 096713c318f8d..71b56cdaf912b 100644 --- a/library/core/src/num/niche_types.rs +++ b/library/core/src/num/niche_types.rs @@ -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); @@ -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] @@ -57,6 +66,8 @@ macro_rules! define_valid_range_type { // by . impl StructuralPartialEq for $name {} + impl Eq for $name {} + impl PartialEq for $name { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 2b0ce99a88173..d40ee565b8e1f 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -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 = 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) { @@ -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 = 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) { diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 0e4926eb49edf..794612e36bbe4 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -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 = 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) { @@ -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 = 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) { diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 48dd1adbc1fa2..da9bacb27cfdb 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -210,6 +210,30 @@ LL | fn non_null_ptr() -> *const usize; = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` +warning: `option_non_zero_usize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:420:13 + | +LL | fn option_non_zero_usize() -> usize; + | ------------------------------------ `option_non_zero_usize` previously declared here +... +LL | fn option_non_zero_usize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> usize` + found `unsafe extern "C" fn() -> Option>` + +warning: `option_non_zero_isize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:421:13 + | +LL | fn option_non_zero_isize() -> isize; + | ------------------------------------ `option_non_zero_isize` previously declared here +... +LL | fn option_non_zero_isize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> isize` + found `unsafe extern "C" fn() -> Option>` + warning: `option_non_zero_usize_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:425:13 | @@ -234,6 +258,18 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; = note: expected `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const isize` +warning: `hidden_niche_transparent` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:481:13 + | +LL | fn hidden_niche_transparent() -> usize; + | --------------------------------------- `hidden_niche_transparent` previously declared here +... +LL | fn hidden_niche_transparent() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> usize` + found `unsafe extern "C" fn() -> Option` + warning: `hidden_niche_transparent_no_niche` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:483:13 | @@ -258,5 +294,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 22 warnings emitted +warning: 25 warnings emitted diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index cc6a2a1c8e532..3dd2a521ff2e1 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -333,7 +333,6 @@ LL | let _val: (NonZero, i32) = mem::uninitialized(); | = note: `std::num::NonZero` 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 @@ -430,7 +429,6 @@ note: because `std::num::NonZero` must be non-null (in this field of the on LL | Banana(NonZero), | ^^^^^^^^^^^^ = 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 diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs new file mode 100644 index 0000000000000..4e3f24520c144 --- /dev/null +++ b/tests/ui/type/pattern_types/matching.rs @@ -0,0 +1,23 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +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() {} diff --git a/tests/ui/type/pattern_types/matching.stderr b/tests/ui/type/pattern_types/matching.stderr new file mode 100644 index 0000000000000..be873d204b20a --- /dev/null +++ b/tests/ui/type/pattern_types/matching.stderr @@ -0,0 +1,20 @@ +error[E0405]: cannot find trait `StructuralPartialEq` in this scope + --> $DIR/matching.rs:7:6 + | +LL | impl StructuralPartialEq for Thing {} + | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | +help: consider importing this trait + | +LL + use std::marker::StructuralPartialEq; + | + +error[E0405]: cannot find trait `StructuralEq` in this scope + --> $DIR/matching.rs:8:6 + | +LL | impl StructuralEq for Thing {} + | ^^^^^^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0405`.