diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cf40c3f7f6f8e..82899481f852f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2512,6 +2512,9 @@ pub enum TyPatKind { /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). Range(Option>, Option>, Spanned), + /// A `!null` pattern for raw pointers. + NotNull, + Or(ThinVec>), /// Placeholder for a pattern that wasn't syntactically well formed in some way. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c88aa5c33ea90..d3d3798b79661 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1030,7 +1030,7 @@ macro_rules! common_visitor_and_walkers { visit_opt!(vis, visit_anon_const, end); } TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants), - TyPatKind::Err(_) => {} + TyPatKind::NotNull | TyPatKind::Err(_) => {} } visit_span(vis, span) } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 58dea472f1d3b..bff1bc01de1f0 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -143,7 +143,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } // return inner to be processed in next loop PatKind::Paren(inner) => pattern = inner, - PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), + PatKind::MacCall(_) => { + panic!("{pattern:#?} shouldn't exist here") + } PatKind::Err(guar) => break hir::PatKind::Err(*guar), } }; @@ -464,6 +466,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) }), ), + TyPatKind::NotNull => hir::TyPatKind::NotNull, TyPatKind::Or(variants) => { hir::TyPatKind::Or(self.arena.alloc_from_iter( variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0990c9b27eb09..0b9b119f42cff 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1218,6 +1218,7 @@ impl<'a> State<'a> { self.print_expr_anon_const(end, &[]); } } + rustc_ast::TyPatKind::NotNull => self.word("!null"), rustc_ast::TyPatKind::Or(variants) => { let mut first = true; for pat in variants { diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index b61af0b0aaa12..9768646e5f919 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -28,15 +28,21 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let ty = parser.parse_ty()?; parser.expect_keyword(exp!(Is))?; - let pat = pat_to_ty_pat( - cx, - *parser.parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - )?, - ); + let start = parser.token.span; + let pat = if parser.eat(exp!(Bang)) { + parser.expect_keyword(exp!(Null))?; + ty_pat(TyPatKind::NotNull, start.to(parser.token.span)) + } else { + pat_to_ty_pat( + cx, + *parser.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + )?, + ) + }; if parser.token != token::Eof { parser.unexpected()?; diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 662546e499988..86211dc9be847 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -148,6 +148,11 @@ pub(crate) fn coerce_unsized_into<'tcx>( dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout())); }; match (&src_ty.kind(), &dst_ty.kind()) { + (ty::Pat(a, _), ty::Pat(b, _)) => { + let src = src.cast_pat_ty_to_base(fx.layout_of(*a)); + let dst = dst.place_transmute_type(fx, *b); + return coerce_unsized_into(fx, src, dst); + } (&ty::Ref(..), &ty::Ref(..)) | (&ty::Ref(..), &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(), diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index cbfb215a892a4..4c7ea1d88f3e8 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -379,6 +379,14 @@ impl<'tcx> CValue<'tcx> { assert_eq!(self.layout().backend_repr, layout.backend_repr); CValue(self.0, layout) } + + pub(crate) fn cast_pat_ty_to_base(self, layout: TyAndLayout<'tcx>) -> Self { + let ty::Pat(base, _) = *self.layout().ty.kind() else { + panic!("not a pattern type: {:#?}", self.layout()) + }; + assert_eq!(layout.ty, base); + CValue(self.0, layout) + } } /// A place where you can write a value to or read a value from diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c2d6a26de0fd0..5eea2364324e5 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -230,6 +230,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) -> (Bx::Value, Bx::Value) { debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty); match (src_ty.kind(), dst_ty.kind()) { + (&ty::Pat(a, _), &ty::Pat(b, _)) => unsize_ptr(bx, src, a, b, old_info), (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => { assert_eq!(bx.cx().type_is_sized(a), old_info.is_none()); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9e15f4572d7b9..54487b5d9c7df 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -473,6 +473,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); match (src.layout.ty.kind(), cast_ty.ty.kind()) { + (&ty::Pat(_, s_pat), &ty::Pat(cast_ty, c_pat)) if s_pat == c_pat => { + let src = self.project_field(src, FieldIdx::ZERO)?; + let dest = self.project_field(dest, FieldIdx::ZERO)?; + let cast_ty = self.layout_of(cast_ty)?; + self.unsize_into(&src, cast_ty, &dest) + } (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _)) | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c), (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 7d76d925ef23e..0998c4151187a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1245,9 +1245,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // When you extend this match, make sure to also add tests to // tests/ui/type/pattern_types/validity.rs(( match **pat { - // Range patterns are precisely reflected into `valid_range` and thus + // Range and non-null patterns are precisely reflected into `valid_range` and thus // handled fully by `visit_scalar` (called below). ty::PatternKind::Range { .. } => {}, + ty::PatternKind::NotNull => {}, // FIXME(pattern_types): check that the value is covered by one of the variants. // For now, we rely on layout computation setting the scalar's `valid_range` to diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6f288bb39b953..69d3d613ebe33 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1820,6 +1820,9 @@ pub enum TyPatKind<'hir> { /// A range pattern (e.g., `1..=2` or `1..2`). Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>), + /// A pattern that excludes null pointers + NotNull, + /// A list of patterns where only one needs to be satisfied Or(&'hir [TyPat<'hir>]), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index bebac3a4b7820..d507eeaf8697d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -725,7 +725,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) try_visit!(visitor.visit_const_arg_unambig(upper_bound)); } TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns), - TyPatKind::Err(_) => (), + TyPatKind::NotNull | TyPatKind::Err(_) => (), } V::Result::output() } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4fcd9f8a646e3..94a080f3f53bb 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -99,6 +99,8 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout +hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other + hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}` .label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4779f4fb702b7..3e45bfc962df1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -249,6 +249,18 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) // even if they do not carry that attribute. match (source.kind(), target.kind()) { + (&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => { + if pat_a != pat_b { + return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind { + span, + trait_name, + pat_a: pat_a.to_string(), + pat_b: pat_b.to_string(), + })); + } + Ok(()) + } + (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b)) if r_a == *r_b && mutbl_a == *mutbl_b => { @@ -414,6 +426,18 @@ pub(crate) fn coerce_unsized_info<'tcx>( (mt_a.ty, mt_b.ty, unsize_trait, None, span) }; let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) { + (&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => { + if pat_a != pat_b { + return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind { + span, + trait_name, + pat_a: pat_a.to_string(), + pat_b: pat_b.to_string(), + })); + } + (ty_a, ty_b, coerce_unsized_trait, None, span) + } + (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; @@ -713,13 +737,16 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err let impl_span = tcx.def_span(checker.impl_def_id); let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); - let is_permitted_primitive = match *self_ty.kind() { - ty::Adt(def, _) => def.is_box(), - ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, - _ => false, - }; + fn is_permitted_primitive(self_ty: Ty<'_>) -> bool { + match *self_ty.kind() { + ty::Adt(def, _) => def.is_box(), + ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, + ty::Pat(base, _) => is_permitted_primitive(base), + _ => false, + } + } - if is_permitted_primitive + if is_permitted_primitive(self_ty) && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty)) && layout.layout.is_pointer_like(&tcx.data_layout) { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c75fef9f716d6..6660ed4181084 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -206,12 +206,8 @@ pub(crate) fn orphan_check_impl( (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } - ty::Pat(..) => ( - LocalImpl::Disallow { problematic_kind: "pattern type" }, - NonlocalImpl::DisallowOther, - ), - ty::Bool + | ty::Pat(..) | ty::Char | ty::Int(..) | ty::Uint(..) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a27d1ed6c532b..31dfaf58dc02f 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1271,6 +1271,16 @@ pub(crate) struct CoerceUnsizedNonStruct { pub trait_name: &'static str, } +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_same_pat_kind)] +pub(crate) struct CoerceSamePatKind { + #[primary_span] + pub span: Span, + pub trait_name: &'static str, + pub pat_a: String, + pub pat_b: String, +} + #[derive(Diagnostic)] #[diag(hir_analysis_coerce_unsized_may, code = E0377)] pub(crate) struct CoerceSameStruct { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4c65d0d051021..b7788363fa4f4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2651,6 +2651,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .span_delayed_bug(ty_span, "invalid base type for range pattern")), } } + hir::TyPatKind::NotNull => Ok(ty::PatternKind::NotNull), hir::TyPatKind::Or(patterns) => { self.tcx() .mk_patterns_from_iter(patterns.iter().map(|pat| { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 960ec7f66ab15..09da0e2ec6511 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -340,6 +340,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_const(current, start, variance); self.add_constraints_from_const(current, end, variance); } + ty::PatternKind::NotNull => {} ty::PatternKind::Or(patterns) => { for pat in patterns { self.add_constraints_from_pat(current, variance, pat) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b23b3125c59a3..ed2529362d098 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1869,6 +1869,10 @@ impl<'a> State<'a> { self.word("..="); self.print_const_arg(end); } + TyPatKind::NotNull => { + self.word_space("not"); + self.word("null"); + } TyPatKind::Or(patterns) => { self.popen(); let mut first = true; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fec23354c9122..e276354296154 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -910,6 +910,7 @@ fn pat_ty_is_known_nonnull<'tcx>( // to ensure we aren't wrapping over zero. start > 0 && end >= start } + ty::PatternKind::NotNull => true, ty::PatternKind::Or(patterns) => { patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat)) } @@ -1071,7 +1072,9 @@ fn get_nullable_type_from_pat<'tcx>( pat: ty::Pattern<'tcx>, ) -> Option> { match *pat { - ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, base), + ty::PatternKind::NotNull | ty::PatternKind::Range { .. } => { + get_nullable_type(tcx, typing_env, base) + } ty::PatternKind::Or(patterns) => { let first = get_nullable_type_from_pat(tcx, typing_env, base, patterns[0])?; for &pat in &patterns[1..] { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index aa2ee756bc502..2025802a217ff 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -159,6 +159,9 @@ pub enum SelectionCandidate<'tcx> { /// types generated for a fn pointer type (e.g., `fn(int) -> int`) FnPointerCandidate, + /// Builtin impl of the `PointerLike` trait. + PointerLikeCandidate, + TraitAliasCandidate, /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2ae6b06192a9..e7005a5b9666e 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -822,11 +822,21 @@ where | ty::FnDef(..) | ty::CoroutineWitness(..) | ty::Foreign(..) - | ty::Pat(_, _) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } + // May contain wide pointers + ty::Pat(base, pat) => match *pat { + ty::PatternKind::NotNull => { + assert_eq!(i, 0); + TyMaybeWithLayout::Ty(base) + } + ty::PatternKind::Range { .. } | ty::PatternKind::Or(_) => { + bug!("TyAndLayout::field({this:?}): only applicable to !null patterns") + } + }, + ty::UnsafeBinder(bound_ty) => { let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into()); field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i) diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 5af9b17dd7777..335e5c0647435 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -30,6 +30,7 @@ impl<'tcx> Flags for Pattern<'tcx> { } flags } + ty::PatternKind::NotNull => rustc_type_ir::TypeFlags::empty(), } } @@ -45,6 +46,7 @@ impl<'tcx> Flags for Pattern<'tcx> { } idx } + ty::PatternKind::NotNull => rustc_type_ir::INNERMOST, } } } @@ -91,6 +93,7 @@ impl<'tcx> IrPrint> for TyCtxt<'tcx> { write!(f, "..={end}") } + PatternKind::NotNull => write!(f, "!null"), PatternKind::Or(patterns) => { write!(f, "(")?; let mut first = true; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index dc1d60f3d43c1..a4d7423818ea2 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -59,6 +59,7 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { let end = relation.relate(end_a, end_b)?; Ok(tcx.mk_pat(ty::PatternKind::Range { start, end })) } + (ty::PatternKind::NotNull, ty::PatternKind::NotNull) => Ok(a), (&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => { if a.len() != b.len() { return Err(TypeError::Mismatch); @@ -67,7 +68,10 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { let patterns = tcx.mk_patterns_from_iter(v)?; Ok(tcx.mk_pat(ty::PatternKind::Or(patterns))) } - (ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch), + ( + ty::PatternKind::NotNull | ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), + _, + ) => Err(TypeError::Mismatch), } } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 7dcdd7999f285..0f84645b54094 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -707,6 +707,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; check_equal(self, location, *f_ty); } + // Debug info is allowed to project into pattern types + ty::Pat(base, _) => check_equal(self, location, *base), ty::Adt(adt_def, args) => { // see if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 173030e0326e8..7319dfa4fd713 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1067,6 +1067,7 @@ fn find_tails_for_unsizing<'tcx>( debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic"); match (source_ty.kind(), target_ty.kind()) { + (&ty::Pat(source, _), &ty::Pat(target, _)) => find_tails_for_unsizing(tcx, source, target), ( &ty::Ref(_, source_pointee, _), &ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _), diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index b91548196a305..1d7ff549f1b09 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -139,6 +139,7 @@ pub enum TokenType { SymNomem, SymNoreturn, SymNostack, + SymNull, SymOptions, SymOut, SymPreservesFlags, @@ -273,6 +274,7 @@ impl TokenType { SymNomem, SymNoreturn, SymNostack, + SymNull, SymOptions, SymOut, SymPreservesFlags, @@ -348,6 +350,7 @@ impl TokenType { TokenType::SymNomem => Some(sym::nomem), TokenType::SymNoreturn => Some(sym::noreturn), TokenType::SymNostack => Some(sym::nostack), + TokenType::SymNull => Some(sym::null), TokenType::SymOptions => Some(sym::options), TokenType::SymOut => Some(sym::out), TokenType::SymPreservesFlags => Some(sym::preserves_flags), @@ -562,6 +565,7 @@ macro_rules! exp { (Nomem) => { exp!(@sym, nomem, SymNomem) }; (Noreturn) => { exp!(@sym, noreturn, SymNoreturn) }; (Nostack) => { exp!(@sym, nostack, SymNostack) }; + (Null) => { exp!(@sym, null, SymNull) }; (Options) => { exp!(@sym, options, SymOptions) }; (Out) => { exp!(@sym, out, SymOut) }; (PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) }; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3dc285fdab690..c3c4e01eff101 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -986,7 +986,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.visit_ty_pat(pat) } } - TyPatKind::Err(_) => {} + TyPatKind::NotNull | TyPatKind::Err(_) => {} } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b0c9dba78a659..213c15258359f 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -412,6 +412,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { end: Some(end.stable(tables)), include_end: true, }, + ty::PatternKind::NotNull => todo!(), ty::PatternKind::Or(_) => todo!(), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d66f98871b97d..6a596dd64e5c4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1503,6 +1503,7 @@ symbols! { not, notable_trait, note, + null, object_safe_for_dispatch, of, off, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 49a5e20d7cf8b..fe1055b80db7f 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -267,6 +267,9 @@ impl<'tcx> SymbolMangler<'tcx> { Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?; } } + ty::PatternKind::NotNull => { + self.tcx.types.unit.print(self)?; + } ty::PatternKind::Or(patterns) => { for pat in patterns { self.print_pat(pat)?; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 97ecf9702e620..da50f7a641b50 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -138,6 +138,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut candidates, ); } + Some(LangItem::PointerLike) => { + self.assemble_pointer_like_candidates(obligation, &mut candidates); + } Some(LangItem::AsyncFn | LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => { self.assemble_async_closure_candidates(obligation, &mut candidates); } @@ -501,6 +504,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_pointer_like_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match obligation.self_ty().skip_binder().kind() { + ty::Pat(..) => candidates.vec.push(PointerLikeCandidate), + _ => {} + } + } + fn assemble_async_fn_kind_helper_candidates( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7acf0f990d1b3..c596133c9df4c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -117,6 +117,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, data) } + PointerLikeCandidate => { + let data = self.confirm_pointer_like_candidate(obligation); + ImplSource::Builtin(BuiltinImplSource::Misc, data) + } + TraitAliasCandidate => { let data = self.confirm_trait_alias_candidate(obligation); ImplSource::Builtin(BuiltinImplSource::Misc, data) @@ -665,6 +670,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(nested) } + fn confirm_pointer_like_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> PredicateObligations<'tcx> { + debug!(?obligation, "confirm_pointer_like_candidate"); + let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); + let ty::Pat(base, _) = *self_ty.kind() else { bug!() }; + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); + + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + placeholder_predicate.def_id(), + vec![base], + ) + } + fn confirm_trait_alias_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3a2f9e8ca179f..d2bc2ff201109 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1983,6 +1983,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate | BuiltinUnsizeCandidate + | PointerLikeCandidate | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 416865e861ea8..85a5f7da01a74 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -696,6 +696,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { check(start); check(end); } + ty::PatternKind::NotNull => {} ty::PatternKind::Or(patterns) => { for pat in patterns { self.add_wf_preds_for_pat_ty(base_ty, pat) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9774263e4c951..0ff9dea86e3f5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -213,9 +213,7 @@ fn layout_of_uncached<'tcx>( let mut layout = LayoutData::clone(&layout.0); match *pat { ty::PatternKind::Range { start, end } => { - if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = - &mut layout.backend_repr - { + if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr { scalar.valid_range_mut().start = extract_const_value(cx, ty, start)? .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; @@ -263,6 +261,31 @@ fn layout_of_uncached<'tcx>( bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}") } } + ty::PatternKind::NotNull => { + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + &mut layout.backend_repr + { + scalar.valid_range_mut().start = 1; + let niche = Niche { + offset: Size::ZERO, + value: scalar.primitive(), + valid_range: scalar.valid_range(cx), + }; + + layout.largest_niche = Some(niche); + // Make wide pointer pattern types contain only a single field + // of the wide pointer type itself. + layout.fields = FieldsShape::Arbitrary { + offsets: [Size::ZERO].into_iter().collect(), + memory_index: [0].into_iter().collect(), + } + } else { + bug!( + "pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}" + ) + } + } + ty::PatternKind::Or(variants) => match *variants[0] { ty::PatternKind::Range { .. } => { if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr { @@ -279,7 +302,7 @@ fn layout_of_uncached<'tcx>( .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?, )), - ty::PatternKind::Or(_) => { + ty::PatternKind::NotNull | ty::PatternKind::Or(_) => { unreachable!("mixed or patterns are not allowed") } }) @@ -344,6 +367,7 @@ fn layout_of_uncached<'tcx>( ) } } + ty::PatternKind::NotNull => bug!("or patterns can't contain `!null` patterns"), ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"), }, } diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs index 7e56565917c67..8237254f8c44d 100644 --- a/compiler/rustc_type_ir/src/pattern.rs +++ b/compiler/rustc_type_ir/src/pattern.rs @@ -14,4 +14,5 @@ use crate::Interner; pub enum PatternKind { Range { start: I::Const, end: I::Const }, Or(I::PatList), + NotNull, } diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 737550eb73e99..d1d707b896f0f 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -178,5 +178,6 @@ fn push_ty_pat(stack: &mut TypeWalkerStack, pat: I::Pat) { push_ty_pat::(stack, pat) } } + ty::PatternKind::NotNull => {} } } diff --git a/library/Cargo.lock b/library/Cargo.lock index 966ae72dc2ad1..8e39e7a09f42b 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -353,7 +353,6 @@ name = "std_detect" version = "0.1.5" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 88855831788db..b97370c3f2dc6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -114,6 +114,7 @@ #![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] +#![feature(pattern_type_macro)] #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] @@ -168,6 +169,7 @@ #![feature(never_type)] #![feature(no_core)] #![feature(optimize_attribute)] +#![feature(pattern_types)] #![feature(prelude_import)] #![feature(repr_simd)] #![feature(rustc_allow_const_fn_unstable)] diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs index 91d015b1bc53f..233cca7f17e39 100644 --- a/library/core/src/pat.rs +++ b/library/core/src/pat.rs @@ -1,5 +1,8 @@ //! Helper module for exporting the `pattern_type` macro +use crate::marker::{Freeze, Unsize}; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; + /// Creates a pattern type. /// ```ignore (cannot test this from within core yet) /// type Positive = std::pat::pattern_type!(i32 is 1..); @@ -74,3 +77,16 @@ impl const RangePattern for char { } } } + +impl CoerceUnsized for pattern_type!(*const T is !null) where + T: Unsize +{ +} + +impl, U> DispatchFromDyn for pattern_type!(T is !null) {} + +impl Unpin for pattern_type!(*const T is !null) {} + +unsafe impl Freeze for pattern_type!(*const T is !null) {} + +unsafe impl Freeze for pattern_type!(*mut T is !null) {} diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c37231d093129..49b818e0760f2 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1122,7 +1122,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty_pat(variant); } }, - TyPatKind::Err(_) => {}, + TyPatKind::NotNull | TyPatKind::Err(_) => {}, } } diff --git a/src/tools/miri/tests/pass/pattern-types.rs b/src/tools/miri/tests/pass/pattern-types.rs new file mode 100644 index 0000000000000..b0c35cd1ff4b3 --- /dev/null +++ b/src/tools/miri/tests/pass/pattern-types.rs @@ -0,0 +1,17 @@ +#![feature(pattern_types, pattern_type_macro)] +#![allow(dead_code)] + +use std::mem::transmute; + +pub struct NonNull { + pointer: std::pat::pattern_type!(*const T is !null), +} + +trait Trait {} +impl Trait for () {} + +fn main() { + unsafe { + let _: NonNull = NonNull { pointer: transmute(&mut () as *mut dyn Trait) }; + } +} diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7ec1032dcb421..6b98a67506a80 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1106,7 +1106,7 @@ impl Rewrite for ast::TyPat { } Ok(s) } - ast::TyPatKind::Err(_) => Err(RewriteError::Unknown), + ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown), } } } diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs index 549b0d11dd187..7e2b4cb996f27 100644 --- a/tests/ui/type/pattern_types/bad_pat.rs +++ b/tests/ui/type/pattern_types/bad_pat.rs @@ -10,4 +10,15 @@ type Positive2 = pattern_type!(i32 is 0..=); type Wild = pattern_type!(() is _); //~^ ERROR: pattern not supported in pattern types +// FIXME: confusing diagnostic because `not` can be a binding +type NonNull = pattern_type!(*const () is not null); +//~^ ERROR: expected one of `@` or `|`, found `null` +//~| ERROR: pattern not supported in pattern types + +type NonNull2 = pattern_type!(*const () is !nil); +//~^ ERROR: expected `null`, found `nil` + +// FIXME: reject with a type mismatch +type Mismatch2 = pattern_type!(() is !null); + fn main() {} diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr index d2a5a20bf89b6..e72279542280c 100644 --- a/tests/ui/type/pattern_types/bad_pat.stderr +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -30,6 +30,24 @@ error: pattern not supported in pattern types LL | type Wild = pattern_type!(() is _); | ^ -error: aborting due to 3 previous errors +error: pattern not supported in pattern types + --> $DIR/bad_pat.rs:14:43 + | +LL | type NonNull = pattern_type!(*const () is not null); + | ^^^ + +error: expected one of `@` or `|`, found `null` + --> $DIR/bad_pat.rs:14:47 + | +LL | type NonNull = pattern_type!(*const () is not null); + | ^^^^ expected one of `@` or `|` + +error: expected `null`, found `nil` + --> $DIR/bad_pat.rs:18:45 + | +LL | type NonNull2 = pattern_type!(*const () is !nil); + | ^^^ expected `null` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/type/pattern_types/non_null.rs b/tests/ui/type/pattern_types/non_null.rs new file mode 100644 index 0000000000000..7e86b8b684d17 --- /dev/null +++ b/tests/ui/type/pattern_types/non_null.rs @@ -0,0 +1,21 @@ +//! Show that pattern-types non-null is the same as libstd's + +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" +//@ only-64bit + +#![feature(pattern_type_macro, pattern_types, rustc_attrs)] + +use std::pat::pattern_type; + +#[rustc_layout(debug)] +type NonNull = pattern_type!(*const T is !null); //~ ERROR layout_of + +#[rustc_layout(debug)] +type Test = Option>; //~ ERROR layout_of + +#[rustc_layout(debug)] +type Wide = pattern_type!(*const [u8] is !null); //~ ERROR layout_of + +const _: () = assert!(size_of::>() == size_of::>>()); + +fn main() {} diff --git a/tests/ui/type/pattern_types/non_null.stderr b/tests/ui/type/pattern_types/non_null.stderr new file mode 100644 index 0000000000000..ad61e9a591473 --- /dev/null +++ b/tests/ui/type/pattern_types/non_null.stderr @@ -0,0 +1,218 @@ +error: layout_of((*const T) is !null) = Layout { + size: Size(8 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + } + --> $DIR/non_null.rs:11:1 + | +LL | type NonNull = pattern_type!(*const T is !null); + | ^^^^^^^^^^^^^^^ + +error: layout_of(Option<(*const ()) is !null>) = Layout { + size: Size(8 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: (..=0) | (1..), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Multiple { + tag: Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: (..=0) | (1..), + }, + tag_encoding: Niche { + untagged_variant: 1, + niche_variants: 0..=0, + niche_start: 0, + }, + tag_field: 0, + variants: [ + Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + Layout { + size: Size(8 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + ), + uninhabited: false, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + } + --> $DIR/non_null.rs:14:1 + | +LL | type Test = Option>; + | ^^^^^^^^^ + +error: layout_of((*const [u8]) is !null) = Layout { + size: Size(16 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: ScalarPair( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + Initialized { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: 1..=18446744073709551615, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + } + --> $DIR/non_null.rs:17:1 + | +LL | type Wide = pattern_type!(*const [u8] is !null); + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/type/pattern_types/unsize.rs b/tests/ui/type/pattern_types/unsize.rs new file mode 100644 index 0000000000000..1020dd8c21544 --- /dev/null +++ b/tests/ui/type/pattern_types/unsize.rs @@ -0,0 +1,18 @@ +//! Show that pattern-types with pointer base types can be part of unsizing coercions + +//@ check-pass + +#![feature(pattern_type_macro, pattern_types)] + +use std::pat::pattern_type; + +type NonNull = pattern_type!(*const T is !null); + +trait Trait {} +impl Trait for u32 {} +impl Trait for i32 {} + +fn main() { + let x: NonNull = unsafe { std::mem::transmute(std::ptr::dangling::()) }; + let x: NonNull = x; +}