From c9ca4f8154561609041c7839632dc7645f846a88 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 13 Apr 2025 22:57:37 +0800 Subject: [PATCH] Implement pin-project in pattern matching for `&pin mut|const T` --- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 5 +- compiler/rustc_borrowck/src/type_check/mod.rs | 7 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- .../src/intrinsics/mod.rs | 6 +- .../src/intrinsics/simd.rs | 2 +- compiler/rustc_codegen_cranelift/src/num.rs | 4 +- .../rustc_codegen_cranelift/src/unsize.rs | 2 +- .../src/value_and_place.rs | 2 +- .../rustc_codegen_cranelift/src/vtable.rs | 3 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/interpret/intrinsics.rs | 6 +- .../src/interpret/operator.rs | 2 +- .../rustc_const_eval/src/interpret/place.rs | 7 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 41 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 55 ++- compiler/rustc_hir_typeck/src/place_op.rs | 4 +- compiler/rustc_hir_typeck/src/writeback.rs | 4 + compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/thir.rs | 2 + compiler/rustc_middle/src/ty/adt.rs | 11 + compiler/rustc_middle/src/ty/sty.rs | 16 +- .../rustc_middle/src/ty/typeck_results.rs | 18 +- compiler/rustc_middle/src/ty/util.rs | 22 + .../src/builder/matches/match_pair.rs | 3 +- .../src/builder/matches/mod.rs | 62 ++- .../src/thir/pattern/check_match.rs | 4 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 7 +- compiler/rustc_mir_build/src/thir/print.rs | 3 +- .../rustc_mir_transform/src/check_pointers.rs | 2 +- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 10 +- .../src/mentioned_items.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 11 +- .../src/partitioning/autodiff.rs | 2 +- .../rustc_pattern_analysis/src/constructor.rs | 26 +- compiler/rustc_pattern_analysis/src/rustc.rs | 53 ++- .../rustc_pattern_analysis/src/rustc/print.rs | 8 +- .../rustc_pattern_analysis/src/usefulness.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 5 +- .../clippy_lints/src/operators/cmp_owned.rs | 2 +- .../clippy/clippy_utils/src/eager_or_lazy.rs | 7 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 2 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- src/tools/miri/src/intrinsics/simd.rs | 2 +- .../miri/src/shims/unix/foreign_items.rs | 2 +- .../diagnostics/match_check/pat_analysis.rs | 10 +- ...ct_pattern_match.bar_const.built.after.mir | 31 ++ ...ject_pattern_match.bar_mut.built.after.mir | 31 ++ ...attern_match.baz_baz_const.built.after.mir | 390 ++++++++++++++++++ ..._pattern_match.baz_baz_mut.built.after.mir | 390 ++++++++++++++++++ ...ct_pattern_match.baz_const.built.after.mir | 72 ++++ ...ject_pattern_match.baz_mut.built.after.mir | 72 ++++ ...attern_match.foo_bar_const.built.after.mir | 43 ++ ..._pattern_match.foo_bar_mut.built.after.mir | 43 ++ ...ct_pattern_match.foo_const.built.after.mir | 31 ++ ...ject_pattern_match.foo_mut.built.after.mir | 31 ++ .../pin-ergonomics/project_pattern_match.rs | 95 +++++ .../project-pattern-match.normal.stderr | 313 ++++++++++++++ .../pin-ergonomics/project-pattern-match.rs | 192 +++++++++ tests/ui/thir-print/thir-tree-match.stdout | 1 + 72 files changed, 2092 insertions(+), 129 deletions(-) create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.rs create mode 100644 tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr create mode 100644 tests/ui/async-await/pin-ergonomics/project-pattern-match.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 56cc43275851..2d86eb06d9de 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1588,7 +1588,7 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty = decl_ty.builtin_deref(true).unwrap(); + let ty = decl_ty.builtin_deref(true, tcx).unwrap(); Some(AmpMutSugg { has_sugg: false, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b66142eb2ce..d5420c82c201 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2472,7 +2472,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Check the kind of deref to decide match base_ty.kind() { - ty::Ref(_, _, mutbl) => { + _ if let Some((_, _, _, mutbl)) = + base_ty.is_ref_or_pin_ref(self.infcx.tcx) => + { + // FIXME(pin_ergonomics): handle `&pin mut|const T` match mutbl { // Shared borrowed data is never mutable hir::Mutability::Not => Err(place), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3c00b819a96b..597bc480abee 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); + let literal_ty = constant.const_.ty().builtin_deref(true, tcx).unwrap(); if let Err(terr) = self.eq_types(literal_ty, normalized_ty, locations, ConstraintCategory::Boring) @@ -2360,7 +2360,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind() { - ty::Ref(ref_region, _, mutbl) => { + _ if let Some((ref_region, _, _, mutbl)) = + base_ty.is_ref_or_pin_ref(tcx) => + { + // FIXME(pin_ergonomics): handle `&pin mut|const T` constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.as_var(), sub: borrow_region.as_var(), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index adaa754491e5..0483a23826b8 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -729,7 +729,7 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true).is_some_and(|pointee_ty| { + ty.builtin_deref(true, fx.tcx).is_some_and(|pointee_ty| { fx.tcx .type_has_metadata(pointee_ty, ty::TypingEnv::fully_monomorphized()) }) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index d3f47ad72633..1a897d907572 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -583,7 +583,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (base, offset); intrinsic); let offset = offset.load_scalar(fx); - let pointee_ty = base.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = base.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = if pointee_size != 1 { fx.bcx.ins().imul_imm(offset, pointee_size as i64) @@ -609,7 +609,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = val.load_scalar(fx); let count = count.load_scalar(fx); - let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = dst.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let count = if pointee_size != 1 { fx.bcx.ins().imul_imm(count, pointee_size as i64) @@ -717,7 +717,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // Cranelift treats loads as volatile by default // FIXME correctly handle unaligned_volatile_load - let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true, fx.tcx).unwrap()); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); ret.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index dd6d8dbb6f5e..4d483616db46 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -897,7 +897,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (ptr, offset); intrinsic); let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); - let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap(); + let pointee_ty = ptr_lane_ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); let ret_lane_layout = fx.layout_of(ret_lane_ty); diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 2a4d1e3ae571..f961b42c8b6f 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -398,7 +398,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( let is_thin_ptr = in_lhs .layout() .ty - .builtin_deref(true) + .builtin_deref(true, fx.tcx) .map(|ty| !fx.tcx.type_has_metadata(ty, ty::TypingEnv::fully_monomorphized())) .unwrap_or(true); @@ -411,7 +411,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) } BinOp::Offset => { - let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = in_lhs.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f8bbb2149201..a8d6f23967a5 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -138,7 +138,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( let dst_ty = dst.layout().ty; let mut coerce_ptr = || { let (base, info) = - if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() { + if fx.layout_of(src.layout().ty.builtin_deref(true, fx.tcx).unwrap()).is_unsized() { let (old_base, old_info) = src.load_scalar_pair(fx); unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) } else { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index f8a19589fdd7..6eacf4c71754 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -831,7 +831,7 @@ impl<'tcx> CPlace<'tcx> { } pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { - let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true, fx.tcx).unwrap()); if fx.tcx.type_has_metadata(inner_layout.ty, ty::TypingEnv::fully_monomorphized()) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 9d9e0462a9b7..691853a972af 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -59,7 +59,8 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { if ty.is_dyn_star() { - let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = + fx.layout_of(arg.layout().ty.builtin_deref(true, fx.tcx).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let vtable = diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8294e29d07df..02e5ba423e2d 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -626,7 +626,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; if element_type_index >= 0 { let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument"); + let pointee_ty = arg_ty.builtin_deref(true, bx.tcx).expect("Must be pointer argument"); let element_type_attr = unsafe { llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) }; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d1d6bcebd33a..8d563ae202d4 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2532,7 +2532,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_arith_offset { // This also checks that the first operand is a ptr type. - let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { + let pointee = in_elem.builtin_deref(true, bx.tcx).unwrap_or_else(|| { span_bug!(span, "must be called with a vector of pointer types as first argument") }); let layout = bx.layout_of(pointee); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d184ce3d61de..ccd3ce2f0143 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1106,7 +1106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { + if !op.layout.ty.builtin_deref(true, bx.tcx()).unwrap().is_dyn_star() { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 5924c8991ad6..89830098c654 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -130,7 +130,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self { bx.cx().layout_of( - self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), + self.ty + .builtin_deref(true, bx.tcx()) + .unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), ) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index eade9e52de95..bc32a03dd46e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let projected_ty = self .layout .ty - .builtin_deref(true) + .builtin_deref(true, cx.tcx()) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)); let layout = cx.layout_of(projected_ty); @@ -701,7 +701,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let unsized_ty = indirect_dest .layout .ty - .builtin_deref(true) + .builtin_deref(true, bx.tcx()) .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 5c14fe5cd10b..9cb66d3d92be 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::BitXor => bx.xor(lhs, rhs), mir::BinOp::Offset => { let pointee_type = lhs_ty - .builtin_deref(true) + .builtin_deref(true, bx.tcx()) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", lhs_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce8eceebdf8d..cb72a05d2e97 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -216,7 +216,7 @@ pub(super) fn op_to_const<'tcx>( // This codepath solely exists for `valtree_to_const_value` to not need to generate // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs + let pointee_ty = imm.layout.ty.builtin_deref(false, *ecx.tcx).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4ca317e3a1e5..8c7a4f1c1da6 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,7 +636,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; let (size, align) = (layout.size, layout.align.abi); let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { @@ -696,7 +696,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { count: &OpTy<'tcx, >::Provenance>, name: &'static str, ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(dst.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; let dst = self.read_pointer(dst)?; let byte = self.read_scalar(byte)?.to_u8()?; @@ -735,7 +735,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { lhs: &OpTy<'tcx, >::Provenance>, rhs: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; assert!(layout.is_sized()); let get_bytes = |this: &InterpCx<'tcx, M>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 899670aeb62d..810b8ceef5ec 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Pointer ops that are always supported. Offset => { let ptr = left.to_scalar().to_pointer(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); + let pointee_ty = left.layout.ty.builtin_deref(true, *self.tcx).unwrap(); let pointee_layout = self.layout_of(pointee_ty)?; assert!(pointee_layout.is_sized()); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f5d3de7b1b27..29e67ab06f0e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -419,8 +419,11 @@ where &self, val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type"); + let pointee_type = val + .layout + .ty + .builtin_deref(true, *self.tcx) + .expect("`ref_to_mplace` called on non-ptr type"); let layout = self.layout_of(pointee_type)?; let (ptr, meta) = val.to_scalar_and_meta(); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index d7e97f32bae9..1bc00f9266d2 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -126,7 +126,7 @@ fn check_validity_requirement_lax<'tcx>( } // Special magic check for references and boxes (i.e., special pointer types). - if let Some(pointee) = this.ty.builtin_deref(false) { + if let Some(pointee) = this.ty.builtin_deref(false, cx.tcx()) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. if pointee.align.abi.bytes() > 1 { diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 99e495d92669..972e2aa0d2c4 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -77,27 +77,28 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // be better to skip this clause and use the Overloaded case only, since &T // and &mut T implement Receiver. But built-in derefs apply equally to Receiver // and Deref, and this has benefits for const and the emitted MIR. - let (kind, new_ty) = - if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); - // NOTE: we may still need to normalize the built-in deref in case - // we have some type like `&::Assoc`, since users of - // autoderef expect this type to have been structurally normalized. - if self.infcx.next_trait_solver() - && let ty::Alias(..) = ty.kind() - { - let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; - self.state.obligations.extend(obligations); - (AutoderefKind::Builtin, normalized_ty) - } else { - (AutoderefKind::Builtin, ty) - } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - // The overloaded deref check already normalizes the pointee type. - (AutoderefKind::Overloaded, ty) + let (kind, new_ty) = if let Some(ty) = + self.state.cur_ty.builtin_deref(self.include_raw_pointers, self.infcx.tcx) + { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) } else { - return None; - }; + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; self.state.steps.push((self.state.cur_ty, kind)); debug!( diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 33d5a86beb3b..2b84eebe7d80 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1808,7 +1808,7 @@ fn check_method_receiver<'tcx>( match receiver_validity_err { ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => { let hint = match receiver_ty - .builtin_deref(false) + .builtin_deref(false, tcx) .unwrap_or(receiver_ty) .ty_adt_def() .and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did())) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index f5e0f01e4c57..40f7cc0db356 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1265,7 +1265,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx match self .cx .try_structurally_resolve_type(pat.span, base_ty) - .builtin_deref(false) + .builtin_deref(false, self.cx.tcx()) { Some(ty) => Ok(ty), None => { @@ -1555,7 +1555,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let deref_ty = match self .cx .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) - .builtin_deref(true) + .builtin_deref(true, self.cx.tcx()) { Some(ty) => ty, None => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 87d92b3fbde8..4858010cb5da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -703,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true).unwrap() + ret_ty.builtin_deref(true, self.tcx).unwrap() } pub(crate) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e5e4fc7f8b77..eb4668f9c194 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -18,7 +18,7 @@ use rustc_hir::{ use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error; use rustc_infer::infer; use rustc_middle::traits::PatternOriginExpr; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_session::parse::feature_err; @@ -91,6 +91,7 @@ struct TopInfo<'tcx> { #[derive(Copy, Clone)] struct PatInfo<'tcx> { + pinnedness: Pinnedness, binding_mode: ByRef, max_ref_mutbl: MutblCap, top_info: TopInfo<'tcx>, @@ -369,6 +370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; let pat_info = PatInfo { + pinnedness: Pinnedness::Not, binding_mode: ByRef::No, max_ref_mutbl: MutblCap::Mut, top_info, @@ -474,6 +476,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(pat.span, "Pattern mutability cap violated!"); } + // If the expected type is `Unpin`, then remove the pinnedness in `pat_info`. + let pat_info = if pat_info.pinnedness == Pinnedness::Pinned + && expected.is_unpin(self.tcx, self.typing_env(self.param_env)) + { + PatInfo { pinnedness: Pinnedness::Not, ..pat_info } + } else { + pat_info + }; + // Resolve type if needed. let expected = if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes @@ -486,11 +497,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info }; match pat.kind { - // Peel off a `&` or `&mut` from the scrutinee type. See the examples in - // `tests/ui/rfcs/rfc-2005-default-binding-mode`. + // Peel off a `&`, `&mut`, `&pin const` or `&pin mut` from the scrutinee type. + // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode` + // and `tests/ui/async-await/pin-ergonomics/project-pattern-match`. _ if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes - && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + && let Some((_, pinnedness, inner_ty, inner_mutability)) = + expected.is_ref_or_pin_ref(self.tcx) => { debug!("inspecting {:?}", expected); @@ -514,6 +527,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ByRef::Yes(Mutability::Not) => Mutability::Not, }); + let pinnedness = if pinnedness == Pinnedness::Pinned + || pat_info.pinnedness == Pinnedness::Pinned + { + Pinnedness::Pinned + } else { + Pinnedness::Not + }; + let mut max_ref_mutbl = pat_info.max_ref_mutbl; if self.downgrade_mut_inside_shared() { binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl()); @@ -524,7 +545,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("default binding mode is now {:?}", binding_mode); // Use the old pat info to keep `current_depth` to its old value. - let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info }; + let new_pat_info = + PatInfo { pinnedness, binding_mode, max_ref_mutbl, ..old_pat_info }; // Recurse with the new expected type. self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info) } @@ -956,7 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; + let PatInfo { pinnedness, binding_mode: def_br, top_info: ti, .. } = pat_info; // Determine the binding mode... let bm = match user_bind_annot { @@ -1029,7 +1051,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // ...and store it in a side table: - self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); + { + let mut typeck_results = self.typeck_results.borrow_mut(); + typeck_results.pat_binding_modes_mut().insert(pat.hir_id, bm); + if pinnedness == Pinnedness::Pinned { + typeck_results.pinned_pat_bindings_mut().insert(pat.hir_id); + } + } debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); @@ -1049,6 +1077,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; + // Wrapping the type into `Pin` if the pattern is pinned + let eq_ty = if pinnedness == Pinnedness::Pinned { + Ty::new_adt( + self.tcx, + self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, Some(pat.span))), + self.tcx.mk_args(&[eq_ty.into()]), + ) + } else { + eq_ty + }; + // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti); @@ -1256,7 +1295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed> { if let PatKind::Binding(..) = inner.kind - && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true) + && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true, self.tcx) && let ty::Dynamic(..) = pointee_ty.kind() { // This is "x = dyn SomeTrait" being reduced from diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 4fc903cf68b8..42ac4ca90d01 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_ty: Ty<'tcx>, ) -> Option> { - if let Some(ty) = oprnd_ty.builtin_deref(true) { + if let Some(ty) = oprnd_ty.builtin_deref(true, self.tcx) { return Some(ty); } @@ -356,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted(base_expr) - .builtin_deref(false) + .builtin_deref(false, self.tcx) .expect("place op takes something that is not a ref"); let arg_ty = match op { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6ba7435cb790..cca84dca5001 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -319,7 +319,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::PatKind::Binding(..) => { let typeck_results = self.fcx.typeck_results.borrow(); let bm = typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span); + let pinnedness = typeck_results.pat_binding_pinnedness(p.hir_id); self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm); + if pinnedness == ty::Pinnedness::Pinned { + self.typeck_results.pinned_pat_bindings_mut().insert(p.hir_id); + } } hir::PatKind::Struct(_, fields, _) => { for field in fields { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d59b6df44ed5..1a81f057a902 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -176,7 +176,7 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + let ty = self.ty.builtin_deref(true, tcx).unwrap_or_else(|| { bug!("deref projection of non-dereferenceable ty {:?}", self) }); PlaceTy::from_ty(ty) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index c168142fb1ec..35f4568fabb2 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -762,6 +762,8 @@ pub enum PatKind<'tcx> { Binding { name: Symbol, #[type_visitable(ignore)] + pinnedness: ty::Pinnedness, + #[type_visitable(ignore)] mode: BindingMode, #[type_visitable(ignore)] var: LocalVarId, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index d92b4f9c06be..a90e13d46134 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -55,6 +55,8 @@ bitflags::bitflags! { const IS_UNSAFE_CELL = 1 << 9; /// Indicates whether the type is `UnsafePinned`. const IS_UNSAFE_PINNED = 1 << 10; + /// Indicates whether the type is `Pin`. + const IS_PIN = 1 << 11; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -307,6 +309,9 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::UnsafePinned) { flags |= AdtFlags::IS_UNSAFE_PINNED; } + if tcx.is_lang_item(did, LangItem::Pin) { + flags |= AdtFlags::IS_PIN; + } AdtDefData { did, variants, flags, repr } } @@ -422,6 +427,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } + /// Returns `true` if this is `Pin`. + #[inline] + pub fn is_pin(self) -> bool { + self.flags().contains(AdtFlags::IS_PIN) + } + /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 301ae6045743..0a3fe1fc52ef 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1274,6 +1274,13 @@ impl<'tcx> Ty<'tcx> { } } + pub fn pinned_ty(self) -> Option> { + match self.kind() { + Adt(def, args) if def.is_pin() => Some(args.type_at(0)), + _ => None, + } + } + /// Panics if called on any type other than `Box`. pub fn expect_boxed_ty(self) -> Ty<'tcx> { self.boxed_ty() @@ -1423,9 +1430,14 @@ impl<'tcx> Ty<'tcx> { /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(self, explicit: bool) -> Option> { + pub fn builtin_deref(self, explicit: bool, tcx: TyCtxt<'tcx>) -> Option> { match *self.kind() { _ if let Some(boxed) = self.boxed_ty() => Some(boxed), + _ if let Some(pinned) = self.pinned_ty() + && let Ref(_, ty, _) = *pinned.kind() => + { + tcx.features().pin_ergonomics().then_some(ty) + } Ref(_, ty, _) => Some(ty), RawPtr(ty, _) if explicit => Some(ty), _ => None, @@ -1765,7 +1777,7 @@ impl<'tcx> Ty<'tcx> { /// Panics if `self` is not dereferencable. #[track_caller] pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let Some(pointee_ty) = self.builtin_deref(true) else { + let Some(pointee_ty) = self.builtin_deref(true, tcx) else { bug!("Type {self:?} is not a pointer or reference type") }; if pointee_ty.is_trivially_sized(tcx) { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4c5c669771fb..569dabcbd22d 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -24,7 +24,7 @@ use crate::mir::FakeReadCause; use crate::traits::ObligationCause; use crate::ty::{ self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, - GenericArgsRef, Ty, UserArgs, tls, + GenericArgsRef, Pinnedness, Ty, UserArgs, tls, }; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] @@ -73,6 +73,9 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap, + /// Stores the pinned pattern bindings. + pinned_pat_bindings: ItemLocalSet, + /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated /// to a form valid in all Editions, either as a lint diagnostic or hard error. rust_2024_migration_desugared_pats: ItemLocalMap, @@ -226,6 +229,7 @@ impl<'tcx> TypeckResults<'tcx> { node_args: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), + pinned_pat_bindings: Default::default(), pat_adjustments: Default::default(), rust_2024_migration_desugared_pats: Default::default(), skipped_ref_pats: Default::default(), @@ -412,6 +416,18 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } } + pub fn pat_binding_pinnedness(&self, id: HirId) -> Pinnedness { + if self.pinned_pat_bindings().contains(id) { Pinnedness::Pinned } else { Pinnedness::Not } + } + + pub fn pinned_pat_bindings(&self) -> LocalSetInContext<'_> { + LocalSetInContext { hir_owner: self.hir_owner, data: &self.pinned_pat_bindings } + } + + pub fn pinned_pat_bindings_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.pinned_pat_bindings } + } + pub fn pat_adjustments( &self, ) -> LocalTableInContext<'_, Vec>> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 08cee1101d0a..8aeb09ba7476 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1545,6 +1545,28 @@ impl<'tcx> Ty<'tcx> { ty } + /// Destructs a reference type `&'a [mut] T` or a pinned reference type + /// `&'a pin const|mut T` into `'a` the region, `[pin]` the pinnedness, + /// `T` the inner type, and `mut|const` the mutability. + pub fn is_ref_or_pin_ref( + self, + tcx: TyCtxt<'tcx>, + ) -> Option<(ty::Region<'tcx>, ty::Pinnedness, Ty<'tcx>, ty::Mutability)> { + match self.kind() { + &ty::Ref(region, inner_ty, mutbl) => { + Some((region, ty::Pinnedness::Not, inner_ty, mutbl)) + } + ty::Adt(adt, args) + if adt.is_pin() + && let &ty::Ref(region, inner_ty, mutbl) = args.type_at(0).kind() + && tcx.features().pin_ergonomics() => + { + Some((region, ty::Pinnedness::Pinned, inner_ty, mutbl)) + } + _ => None, + } + } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index d66b38c5b005..210891ecbdeb 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -159,7 +159,7 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::Binding { mode, var, ref subpattern, .. } => { + PatKind::Binding { mode, var, ref subpattern, pinnedness, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` // before establishing the binding for `x`. @@ -198,6 +198,7 @@ impl<'tcx> MatchPairTree<'tcx> { source, var_id: var, binding_mode: mode, + pinnedness, }); } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 977d4f3e931b..21efca43c3f0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,20 +5,20 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use std::assert_matches::assert_matches; +use std::assert_matches::{assert_matches, debug_assert_matches}; use std::borrow::Borrow; use std::mem; use std::sync::Arc; -use rustc_abi::VariantIdx; +use rustc_abi::{FIRST_VARIANT, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; -use rustc_middle::bug; +use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -1230,6 +1230,7 @@ struct Binding<'tcx> { source: Place<'tcx>, var_id: LocalVarId, binding_mode: BindingMode, + pinnedness: ty::Pinnedness, } /// Indicates that the type of `source` must be a subtype of the @@ -2715,6 +2716,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + let rvalue = match binding.pinnedness { + ty::Pinnedness::Not => rvalue, + ty::Pinnedness::Pinned => { + self.pin_borrowed_local(block, value_for_arm.local, rvalue, source_info) + } + }; self.cfg.push_assign(block, source_info, value_for_arm, rvalue); // For the guard binding, take a shared reference to that reference. let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm); @@ -2758,13 +2765,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = match binding.binding_mode.0 { ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)), ByRef::Yes(mutbl) => { - Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source) + let rvalue = + Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + match binding.pinnedness { + ty::Pinnedness::Not => rvalue, + ty::Pinnedness::Pinned => { + self.pin_borrowed_local(block, local.local, rvalue, source_info) + } + } } }; self.cfg.push_assign(block, source_info, local, rvalue); } } + /// Given an rvalue `&[mut]borrow` and a local `local`, generate the pinned borrow for it: + /// ```ignore (illustrative) + /// pinned_temp = &borrow; + /// local = Pin { __pointer: move pinned_temp }; + /// ``` + fn pin_borrowed_local( + &mut self, + block: BasicBlock, + local: Local, + borrow: Rvalue<'tcx>, + source_info: SourceInfo, + ) -> Rvalue<'tcx> { + debug_assert_matches!(borrow, Rvalue::Ref(..)); + + let local_ty = self.local_decls[local].ty; + + let pinned_ty = local_ty.pinned_ty().unwrap_or_else(|| { + span_bug!( + source_info.span, + "expect type `Pin` for a pinned binding, found type {:?}", + local_ty + ) + }); + let pinned_temp = + Place::from(self.local_decls.push(LocalDecl::new(pinned_ty, source_info.span))); + self.cfg.push_assign(block, source_info, pinned_temp, borrow); + Rvalue::Aggregate( + Box::new(AggregateKind::Adt( + self.tcx.require_lang_item(LangItem::Pin, Some(source_info.span)), + FIRST_VARIANT, + self.tcx.mk_args(&[pinned_ty.into()]), + None, + None, + )), + std::iter::once(Operand::Move(pinned_temp)).collect(), + ) + } + /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound /// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The /// first local is a binding for occurrences of `var` in the guard, which diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 78583a402fe9..2a187bb0e0eb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -974,7 +974,7 @@ fn report_unreachable_pattern<'p, 'tcx>( if cx.is_uninhabited(ty) { lint.matches_no_values_ty = ty; false // No need to dig further. - } else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) { + } else if matches!(subpat.ctor(), Constructor::Ref(_) | Constructor::UnionField) { false // Don't explore further since they are not by-value. } else { true @@ -1195,7 +1195,7 @@ fn report_arm_reachability<'p, 'tcx>( fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { match pat.ctor() { Constructor::Wildcard => true, - Constructor::Struct | Constructor::Ref => { + Constructor::Struct | Constructor::Ref(_) => { pat.iter_fields().all(|ipat| pat_is_catchall(&ipat.pat)) } _ => false, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8f058efdfacd..77ef5499b8ce 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -349,6 +349,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); + let pinnedness = self.typeck_results.pat_binding_pinnedness(pat.hir_id); + if let Some(s) = &mut self.rust_2024_migration { s.visit_binding(pat.span, mode, explicit_ba, ident); } @@ -357,8 +359,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; if let hir::ByRef::Yes(_) = mode.0 { - if let ty::Ref(_, rty, _) = ty.kind() { - ty = *rty; + if let Some((_, _, rty, _)) = ty.is_ref_or_pin_ref(self.tcx) { + ty = rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); } @@ -366,6 +368,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Binding { mode, + pinnedness, name: ident.name, var: LocalVarId(id), ty: var_ty, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 37248941e2c4..248f35708ec6 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -678,9 +678,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 3); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => { + PatKind::Binding { name, pinnedness, mode, var, ty, subpattern, is_primary } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("pinnedness: {:?}", pinnedness), depth_lvl + 2); print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index 2d04b6219358..52c647307aa8 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { } let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer"); + pointer_ty.builtin_deref(true, self.tcx).expect("no builtin_deref for an raw pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.typing_env) { trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 90173da17f0f..19c5d99752d0 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -391,7 +391,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { if let Some(target_len) = self.map.find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) - && let Some(operand_ty) = operand_ty.builtin_deref(true) + && let Some(operand_ty) = operand_ty.builtin_deref(true, self.tcx) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar_int(self.tcx, self.typing_env) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8b8d1efbbd2e..3bdcce5e3522 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -643,7 +643,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Deref => { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() - && let Some(pointee_ty) = ty.builtin_deref(true) + && let Some(pointee_ty) = ty.builtin_deref(true, self.tcx) && pointee_ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the @@ -1171,8 +1171,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { to, .. }, - ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() - && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => + ) if let ty::Slice(..) = to.builtin_deref(true, self.tcx).unwrap().kind() + && let ty::Array(_, len) = from.builtin_deref(true, self.tcx).unwrap().kind() => { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } @@ -1503,9 +1503,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = from.builtin_deref(true) + && let Some(from) = from.builtin_deref(true, self.tcx) && let ty::Array(_, len) = from.kind() - && let Some(to) = to.builtin_deref(true) + && let Some(to) = to.builtin_deref(true, self.tcx) && let ty::Slice(..) = to.kind() { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 9fd8d81d64a2..28f135459064 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -83,8 +83,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); let may_involve_vtable = match ( - source_ty.builtin_deref(true).map(|t| t.kind()), - target_ty.builtin_deref(true).map(|t| t.kind()), + source_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), + target_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), ) { // &str/&[T] unsizing (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 66fe3ef4141f..fa63d157a1a1 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1431,7 +1431,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } if let Rvalue::CopyForDeref(place) = rvalue { - if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() { + if place + .ty(&self.body.local_decls, self.tcx) + .ty + .builtin_deref(true, self.tcx) + .is_none() + { self.fail( location, "`CopyForDeref` should only be used for dereferenceable types", @@ -1468,7 +1473,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { CopyNonOverlapping { src, dst, count }, )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); - let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { + let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true, self.tcx) { src_deref } else { self.fail( @@ -1478,7 +1483,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; let dst_ty = dst.ty(&self.body.local_decls, self.tcx); - let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { + let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true, self.tcx) { dst_deref } else { self.fail( diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs index 22d593b80b89..d0e7f3fc2136 100644 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -20,7 +20,7 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec let mut new_activities = vec![]; let mut new_positions = vec![]; for (i, ty) in sig.inputs().iter().enumerate() { - if let Some(inner_ty) = ty.builtin_deref(true) { + if let Some(inner_ty) = ty.builtin_deref(true, tcx) { if inner_ty.is_slice() { // Now we need to figure out the size of each slice element in memory to allow // safety checks and usability improvements in the backend. diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 4ce868f014f4..50da2a7aaaf4 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -183,6 +183,7 @@ use std::iter::once; use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::IndexVec; use rustc_index::bit_set::{DenseBitSet, GrowableBitSet}; +use rustc_middle::ty::Pinnedness; use smallvec::SmallVec; use self::Constructor::*; @@ -679,8 +680,8 @@ pub enum Constructor { Struct, /// Enum variants. Variant(Cx::VariantIdx), - /// References - Ref, + /// References or pinned reference + Ref(Pinnedness), /// Array and slice patterns. Slice(Slice), /// Union field accesses. @@ -730,7 +731,7 @@ impl Clone for Constructor { match self { Constructor::Struct => Constructor::Struct, Constructor::Variant(idx) => Constructor::Variant(*idx), - Constructor::Ref => Constructor::Ref, + Constructor::Ref(pinnedness) => Constructor::Ref(*pinnedness), Constructor::Slice(slice) => Constructor::Slice(*slice), Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), @@ -808,7 +809,7 @@ impl Constructor { (Missing { .. } | NonExhaustive | Hidden, _) => false, (Struct, Struct) => true, - (Ref, Ref) => true, + (Ref(self_pin), Ref(other_pin)) => self_pin == other_pin, (UnionField, UnionField) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, (Bool(self_b), Bool(other_b)) => self_b == other_b, @@ -901,9 +902,12 @@ impl Constructor { // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to detect strings here. However a string literal pattern will never // be reported as a non-exhaustiveness witness, so we can ignore this issue. - Ref => { + Ref(Pinnedness::Not) => { write!(f, "&{:?}", fields.next().unwrap())?; } + Ref(Pinnedness::Pinned) => { + write!(f, "&pin {:?}", fields.next().unwrap())?; + } Slice(slice) => { write!(f, "[")?; match slice.kind { @@ -972,8 +976,8 @@ pub enum ConstructorSet { /// This type has the following list of constructors. If `variants` is empty and /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead. Variants { variants: IndexVec, non_exhaustive: bool }, - /// The type is `&T`. - Ref, + /// The type is `&T` or `&pin T`. + Ref(Pinnedness), /// The type is a union. Union, /// Booleans. @@ -1057,11 +1061,11 @@ impl ConstructorSet { missing.push(Struct); } } - ConstructorSet::Ref => { + ConstructorSet::Ref(pinnedness) => { if !seen.is_empty() { - present.push(Ref); + present.push(Ref(*pinnedness)); } else { - missing.push(Ref); + missing.push(Ref(*pinnedness)); } } ConstructorSet::Union => { @@ -1179,7 +1183,7 @@ impl ConstructorSet { match self { ConstructorSet::Bool | ConstructorSet::Integers { .. } - | ConstructorSet::Ref + | ConstructorSet::Ref(_) | ConstructorSet::Union | ConstructorSet::Unlistable => false, ConstructorSet::NoConstructors => true, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7c12f69f14c1..c4ff6024bac6 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -239,6 +239,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. reveal_and_alloc(cx, once(args.type_at(0))) + } else if adt.is_pin() + && let ty::Ref(_, rty, _) = args.type_at(0).kind() + && self.tcx.features().pin_ergonomics() + { + reveal_and_alloc(cx, once(*rty)) } else { let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); @@ -258,8 +263,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => match ty.kind() { - ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)), + Ref(expected_pinnedness) => match ty.is_ref_or_pin_ref(self.tcx) { + Some((_, pinnedness, rty, _)) if pinnedness == *expected_pinnedness => { + reveal_and_alloc(cx, once(rty)) + } _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"), }, Slice(slice) => match *ty.kind() { @@ -296,7 +303,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => 1, + Ref(_) => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing @@ -373,6 +380,13 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { subtype_is_empty: cx.is_uninhabited(*sub_ty), } } + ty::Adt(adt, args) + if adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { + ConstructorSet::Ref(ty::Pinnedness::Pinned) + } ty::Adt(def, args) if def.is_enum() => { let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty); if def.variants().is_empty() && !is_declared_nonexhaustive { @@ -415,7 +429,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) } } - ty::Ref(..) => ConstructorSet::Ref, + ty::Ref(..) => ConstructorSet::Ref(ty::Pinnedness::Not), ty::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. // FIXME(Nadrieril): which of these are actually allowed? @@ -484,7 +498,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ctor = match ty.kind() { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, - ty::Ref(..) => Ref, + // This is a pin ref pattern. + ty::Adt(adt, args) + if adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { + Ref(ty::Pinnedness::Pinned) + } + ty::Ref(..) => Ref(ty::Pinnedness::Not), _ => span_bug!( pat.span, "pattern has unexpected type: pat: {:?}, ty: {:?}", @@ -509,7 +531,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index())) .collect(); } - ty::Adt(adt, _) if adt.is_box() => { + ty::Adt(adt, args) + if adt.is_box() + || adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, @@ -528,7 +555,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } else { fields = vec![]; } - ctor = Struct; + if adt.is_pin() { + debug_assert!(args.type_at(0).is_ref()); + ctor = Ref(ty::Pinnedness::Pinned); + } else { + ctor = Struct; + } arity = 1; } ty::Adt(adt, _) => { @@ -639,7 +671,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); - ctor = Ref; + ctor = Ref(ty::Pinnedness::Not); fields = vec![subpattern.at_index(0)]; arity = 1; } @@ -869,9 +901,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .unwrap(); s } - Ref => { + Ref(_) => { let mut s = String::new(); - print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); + print::write_ref_like(&mut s, self.tcx, pat.ty().inner(), &print(&pat.fields[0])) + .unwrap(); s } Slice(slice) => { diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 7649f72f8681..3d8b2d845a31 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -127,13 +127,17 @@ pub(crate) fn write_struct_like<'tcx>( pub(crate) fn write_ref_like<'tcx>( f: &mut impl fmt::Write, + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, subpattern: &str, ) -> fmt::Result { - match ty.kind() { - ty::Ref(_, _, mutbl) => { + match ty.is_ref_or_pin_ref(tcx) { + Some((_, ty::Pinnedness::Not, _, mutbl)) => { write!(f, "&{}", mutbl.prefix_str())?; } + Some((_, ty::Pinnedness::Pinned, _, mutbl)) => { + write!(f, "&pin {} ", mutbl.ptr_str())?; + } _ => bug!("{ty} is a bad ref pattern type"), } write!(f, "{subpattern}") diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 11ebbea07fa4..fd0fad776c48 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -866,7 +866,7 @@ impl PlaceValidity { /// inside `&` and union fields where validity is reset to `MaybeInvalid`. fn specialize(self, ctor: &Constructor) -> Self { // We preserve validity except when we go inside a reference or a union field. - if matches!(ctor, Constructor::Ref | Constructor::UnionField) { + if matches!(ctor, Constructor::Ref(_) | Constructor::UnionField) { // Validity of `x: &T` does not imply validity of `*x: T`. MaybeInvalid } else { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f310aa655002..5f72a8a71ad3 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -721,8 +721,9 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { hir::Mutability::Mut => "Q", }); - let pointee_ty = - ct_ty.builtin_deref(true).expect("tried to dereference on non-ptr type"); + let pointee_ty = ct_ty + .builtin_deref(true, self.tcx) + .expect("tried to dereference on non-ptr type"); let dereferenced_const = ty::Const::new_value(self.tcx, valtree, pointee_ty); dereferenced_const.print(self)?; } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index cf6b8992973a..9b3f1dea743a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -67,7 +67,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty - .builtin_deref(true) + .builtin_deref(true, cx.tcx) .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty)) .unwrap_or_default(); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 4543a20cc2cd..e9505c0eb575 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -212,7 +212,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // Custom `Deref` impl might have side effects ExprKind::Unary(UnOp::Deref, e) - if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => + if self + .cx + .typeck_results() + .expr_ty(e) + .builtin_deref(true, self.cx.tcx) + .is_none() => { self.eagerness |= NoChange; }, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5d0401010db6..13e1c7716383 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -141,7 +141,7 @@ fn check_rvalue<'tcx>( _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => { - let Some(pointee_ty) = cast_ty.builtin_deref(true) else { + let Some(pointee_ty) = cast_ty.builtin_deref(true, cx.tcx) else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 18a5a0612bb0..dbce919519e8 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -127,7 +127,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). - let pointee = ty.builtin_deref(true).unwrap(); + let pointee = ty.builtin_deref(true, *cx.tcx).unwrap(); if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f39a606513d5..6f771d8b2029 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -164,7 +164,7 @@ impl<'tcx> NewPermission { cx: &crate::MiriInterpCx<'tcx>, zero_size: bool, ) -> Option { - let pointee = ty.builtin_deref(true).unwrap(); + let pointee = ty.builtin_deref(true, *cx.tcx).unwrap(); pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index de5da6ec898a..c520e58031b5 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -275,7 +275,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Op::WrappingOffset => { let ptr = left.to_scalar().to_pointer(this)?; let offset_count = right.to_scalar().to_target_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); + let pointee_ty = left.layout.ty.builtin_deref(true, *this.tcx).unwrap(); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset_bytes = offset_count.wrapping_mul(pointee_size); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 5e6259c35744..3edd9d762f4a 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -469,7 +469,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Figure out how large a pthread TLS key actually is. // To this end, deref the argument type. This is `libc::pthread_key_t`. let key_type = key.layout.ty - .builtin_deref(true) + .builtin_deref(true, *this.tcx) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." ))?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 91eb59fb3140..23a67d1cd20b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -165,7 +165,7 @@ impl<'db> MatchCheckCtx<'db> { ctor = match pat.ty.kind(Interner) { // This is a box pattern. TyKind::Adt(adt, _) if is_box(self.db, adt.0) => Struct, - TyKind::Ref(..) => Ref, + TyKind::Ref(..) => Ref(rustc_ast_ir::Pinnedness::Not), _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); Wildcard @@ -299,7 +299,7 @@ impl<'db> MatchCheckCtx<'db> { // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we // ignore this issue. - Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + Ref(_) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, @@ -349,7 +349,7 @@ impl PatCx for MatchCheckCtx<'_> { 0 } }, - Ref => 1, + Ref(_) => 1, Slice(..) => unimplemented!(), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited @@ -404,7 +404,7 @@ impl PatCx for MatchCheckCtx<'_> { single(ty.clone()) } }, - Ref => match ty.kind(Interner) { + Ref(_) => match ty.kind(Interner) { TyKind::Ref(.., rty) => single(rty.clone()), ty_kind => { never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind); @@ -474,7 +474,7 @@ impl PatCx for MatchCheckCtx<'_> { TyKind::Adt(..) | TyKind::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty) } } - TyKind::Ref(..) => ConstructorSet::Ref, + TyKind::Ref(..) => ConstructorSet::Ref(rustc_ast_ir::Pinnedness::Not), TyKind::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. _ => ConstructorSet::Unlistable, diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir new file mode 100644 index 000000000000..d99480556ae0 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `bar_const` after built + +fn bar_const(_1: Pin<&Bar>) -> () { + debug bar => _1; + let mut _0: (); + let _2: std::pin::Pin<&T>; + let _3: &U; + let mut _4: &T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &((*_1).0: T); + _2 = Pin::<&T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &((*_1).1: U); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir new file mode 100644 index 000000000000..f2d2e36fc1d0 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `bar_mut` after built + +fn bar_mut(_1: Pin<&mut Bar>) -> () { + debug bar => _1; + let mut _0: (); + let _2: std::pin::Pin<&mut T>; + let _3: &mut U; + let mut _4: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &mut ((*_1).0: T); + _2 = Pin::<&mut T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &mut ((*_1).1: U); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir new file mode 100644 index 000000000000..03c6c0d9d104 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir @@ -0,0 +1,390 @@ +// MIR for `baz_baz_const` after built + +fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { + debug baz => _1; + let mut _0: (); + let mut _2: isize; + let mut _3: isize; + let mut _4: isize; + let mut _5: isize; + let mut _6: isize; + let mut _7: isize; + let mut _8: isize; + let _9: std::pin::Pin<&T>; + let _10: &U; + let _11: std::pin::Pin<&T>; + let _12: &U; + let mut _13: &T; + let mut _14: &T; + let _15: std::pin::Pin<&T>; + let _16: &U; + let _17: std::pin::Pin<&T>; + let _18: &U; + let mut _19: &T; + let mut _20: &T; + let _21: std::pin::Pin<&T>; + let _22: &U; + let _23: std::pin::Pin<&T>; + let _24: &U; + let mut _25: &T; + let mut _26: &T; + let _27: std::pin::Pin<&T>; + let _28: &U; + let _29: std::pin::Pin<&T>; + let _30: &U; + let mut _31: &T; + let mut _32: &T; + let _33: std::pin::Pin<&T>; + let _34: &U; + let _35: std::pin::Pin<&T>; + let _36: &U; + let mut _37: &T; + let mut _38: &T; + let _39: std::pin::Pin<&T>; + let _40: &U; + let _41: std::pin::Pin<&T>; + let _42: &U; + let mut _43: &T; + let mut _44: &T; + let _45: std::pin::Pin<&T>; + let _46: &U; + let _47: std::pin::Pin<&T>; + let _48: &U; + let mut _49: &T; + let mut _50: &T; + let _51: std::pin::Pin<&T>; + let _52: &U; + let _53: std::pin::Pin<&T>; + let _54: &U; + let mut _55: &T; + let mut _56: &T; + scope 1 { + debug x => _9; + debug y => _10; + debug z => _11; + debug w => _12; + } + scope 2 { + debug x => _15; + debug y => _16; + debug z => _17; + debug w => _18; + } + scope 3 { + debug x => _21; + debug y => _22; + debug z => _23; + debug w => _24; + } + scope 4 { + debug x => _27; + debug y => _28; + debug z => _29; + debug w => _30; + } + scope 5 { + debug x => _33; + debug y => _34; + debug z => _35; + debug w => _36; + } + scope 6 { + debug x => _39; + debug y => _40; + debug z => _41; + debug w => _42; + } + scope 7 { + debug x => _45; + debug y => _46; + debug z => _47; + debug w => _48; + } + scope 8 { + debug x => _51; + debug y => _52; + debug z => _53; + debug w => _54; + } + + bb0: { + PlaceMention(_1); + _8 = discriminant((*_1)); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*_1) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*_1) as Foo).1: Baz)); + switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5]; + } + + bb5: { + goto -> bb3; + } + + bb6: { + falseEdge -> [real: bb36, imaginary: bb8]; + } + + bb7: { + goto -> bb5; + } + + bb8: { + falseEdge -> [real: bb35, imaginary: bb10]; + } + + bb9: { + goto -> bb5; + } + + bb10: { + _3 = discriminant((((*_1) as Foo).1: Baz)); + switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11]; + } + + bb11: { + goto -> bb3; + } + + bb12: { + falseEdge -> [real: bb34, imaginary: bb14]; + } + + bb13: { + goto -> bb11; + } + + bb14: { + falseEdge -> [real: bb33, imaginary: bb16]; + } + + bb15: { + goto -> bb11; + } + + bb16: { + _7 = discriminant((((*_1) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*_1) as Bar).1: Baz)); + switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19]; + } + + bb19: { + goto -> bb17; + } + + bb20: { + falseEdge -> [real: bb32, imaginary: bb22]; + } + + bb21: { + goto -> bb19; + } + + bb22: { + falseEdge -> [real: bb31, imaginary: bb24]; + } + + bb23: { + goto -> bb19; + } + + bb24: { + _6 = discriminant((((*_1) as Bar).1: Baz)); + switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25]; + } + + bb25: { + goto -> bb17; + } + + bb26: { + falseEdge -> [real: bb30, imaginary: bb28]; + } + + bb27: { + goto -> bb25; + } + + bb28: { + StorageLive(_51); + _55 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); + _51 = Pin::<&T> { __pointer: move _55 }; + StorageLive(_52); + _52 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_53); + _56 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); + _53 = Pin::<&T> { __pointer: move _56 }; + StorageLive(_54); + _54 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); + StorageDead(_51); + goto -> bb37; + } + + bb29: { + goto -> bb25; + } + + bb30: { + StorageLive(_45); + _49 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); + _45 = Pin::<&T> { __pointer: move _49 }; + StorageLive(_46); + _46 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_47); + _50 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); + _47 = Pin::<&T> { __pointer: move _50 }; + StorageLive(_48); + _48 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_48); + StorageDead(_47); + StorageDead(_46); + StorageDead(_45); + goto -> bb37; + } + + bb31: { + StorageLive(_39); + _43 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); + _39 = Pin::<&T> { __pointer: move _43 }; + StorageLive(_40); + _40 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_41); + _44 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); + _41 = Pin::<&T> { __pointer: move _44 }; + StorageLive(_42); + _42 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_42); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); + goto -> bb37; + } + + bb32: { + StorageLive(_33); + _37 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); + _33 = Pin::<&T> { __pointer: move _37 }; + StorageLive(_34); + _34 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_35); + _38 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); + _35 = Pin::<&T> { __pointer: move _38 }; + StorageLive(_36); + _36 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_36); + StorageDead(_35); + StorageDead(_34); + StorageDead(_33); + goto -> bb37; + } + + bb33: { + StorageLive(_27); + _31 = &(((((*_1) as Foo).0: Baz) as Bar).0: T); + _27 = Pin::<&T> { __pointer: move _31 }; + StorageLive(_28); + _28 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_29); + _32 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); + _29 = Pin::<&T> { __pointer: move _32 }; + StorageLive(_30); + _30 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + goto -> bb37; + } + + bb34: { + StorageLive(_21); + _25 = &(((((*_1) as Foo).0: Baz) as Bar).0: T); + _21 = Pin::<&T> { __pointer: move _25 }; + StorageLive(_22); + _22 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_23); + _26 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); + _23 = Pin::<&T> { __pointer: move _26 }; + StorageLive(_24); + _24 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageDead(_21); + goto -> bb37; + } + + bb35: { + StorageLive(_15); + _19 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); + _15 = Pin::<&T> { __pointer: move _19 }; + StorageLive(_16); + _16 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_17); + _20 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); + _17 = Pin::<&T> { __pointer: move _20 }; + StorageLive(_18); + _18 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + goto -> bb37; + } + + bb36: { + StorageLive(_9); + _13 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&T> { __pointer: move _13 }; + StorageLive(_10); + _10 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_11); + _14 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&T> { __pointer: move _14 }; + StorageLive(_12); + _12 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); + goto -> bb37; + } + + bb37: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir new file mode 100644 index 000000000000..7627c7f047a8 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir @@ -0,0 +1,390 @@ +// MIR for `baz_baz_mut` after built + +fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { + debug baz => _1; + let mut _0: (); + let mut _2: isize; + let mut _3: isize; + let mut _4: isize; + let mut _5: isize; + let mut _6: isize; + let mut _7: isize; + let mut _8: isize; + let _9: std::pin::Pin<&mut T>; + let _10: &mut U; + let _11: std::pin::Pin<&mut T>; + let _12: &mut U; + let mut _13: &mut T; + let mut _14: &mut T; + let _15: std::pin::Pin<&mut T>; + let _16: &mut U; + let _17: std::pin::Pin<&mut T>; + let _18: &mut U; + let mut _19: &mut T; + let mut _20: &mut T; + let _21: std::pin::Pin<&mut T>; + let _22: &mut U; + let _23: std::pin::Pin<&mut T>; + let _24: &mut U; + let mut _25: &mut T; + let mut _26: &mut T; + let _27: std::pin::Pin<&mut T>; + let _28: &mut U; + let _29: std::pin::Pin<&mut T>; + let _30: &mut U; + let mut _31: &mut T; + let mut _32: &mut T; + let _33: std::pin::Pin<&mut T>; + let _34: &mut U; + let _35: std::pin::Pin<&mut T>; + let _36: &mut U; + let mut _37: &mut T; + let mut _38: &mut T; + let _39: std::pin::Pin<&mut T>; + let _40: &mut U; + let _41: std::pin::Pin<&mut T>; + let _42: &mut U; + let mut _43: &mut T; + let mut _44: &mut T; + let _45: std::pin::Pin<&mut T>; + let _46: &mut U; + let _47: std::pin::Pin<&mut T>; + let _48: &mut U; + let mut _49: &mut T; + let mut _50: &mut T; + let _51: std::pin::Pin<&mut T>; + let _52: &mut U; + let _53: std::pin::Pin<&mut T>; + let _54: &mut U; + let mut _55: &mut T; + let mut _56: &mut T; + scope 1 { + debug x => _9; + debug y => _10; + debug z => _11; + debug w => _12; + } + scope 2 { + debug x => _15; + debug y => _16; + debug z => _17; + debug w => _18; + } + scope 3 { + debug x => _21; + debug y => _22; + debug z => _23; + debug w => _24; + } + scope 4 { + debug x => _27; + debug y => _28; + debug z => _29; + debug w => _30; + } + scope 5 { + debug x => _33; + debug y => _34; + debug z => _35; + debug w => _36; + } + scope 6 { + debug x => _39; + debug y => _40; + debug z => _41; + debug w => _42; + } + scope 7 { + debug x => _45; + debug y => _46; + debug z => _47; + debug w => _48; + } + scope 8 { + debug x => _51; + debug y => _52; + debug z => _53; + debug w => _54; + } + + bb0: { + PlaceMention(_1); + _8 = discriminant((*_1)); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*_1) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*_1) as Foo).1: Baz)); + switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5]; + } + + bb5: { + goto -> bb3; + } + + bb6: { + falseEdge -> [real: bb36, imaginary: bb8]; + } + + bb7: { + goto -> bb5; + } + + bb8: { + falseEdge -> [real: bb35, imaginary: bb10]; + } + + bb9: { + goto -> bb5; + } + + bb10: { + _3 = discriminant((((*_1) as Foo).1: Baz)); + switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11]; + } + + bb11: { + goto -> bb3; + } + + bb12: { + falseEdge -> [real: bb34, imaginary: bb14]; + } + + bb13: { + goto -> bb11; + } + + bb14: { + falseEdge -> [real: bb33, imaginary: bb16]; + } + + bb15: { + goto -> bb11; + } + + bb16: { + _7 = discriminant((((*_1) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*_1) as Bar).1: Baz)); + switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19]; + } + + bb19: { + goto -> bb17; + } + + bb20: { + falseEdge -> [real: bb32, imaginary: bb22]; + } + + bb21: { + goto -> bb19; + } + + bb22: { + falseEdge -> [real: bb31, imaginary: bb24]; + } + + bb23: { + goto -> bb19; + } + + bb24: { + _6 = discriminant((((*_1) as Bar).1: Baz)); + switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25]; + } + + bb25: { + goto -> bb17; + } + + bb26: { + falseEdge -> [real: bb30, imaginary: bb28]; + } + + bb27: { + goto -> bb25; + } + + bb28: { + StorageLive(_51); + _55 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); + _51 = Pin::<&mut T> { __pointer: move _55 }; + StorageLive(_52); + _52 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_53); + _56 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); + _53 = Pin::<&mut T> { __pointer: move _56 }; + StorageLive(_54); + _54 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); + StorageDead(_51); + goto -> bb37; + } + + bb29: { + goto -> bb25; + } + + bb30: { + StorageLive(_45); + _49 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); + _45 = Pin::<&mut T> { __pointer: move _49 }; + StorageLive(_46); + _46 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_47); + _50 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); + _47 = Pin::<&mut T> { __pointer: move _50 }; + StorageLive(_48); + _48 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_48); + StorageDead(_47); + StorageDead(_46); + StorageDead(_45); + goto -> bb37; + } + + bb31: { + StorageLive(_39); + _43 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); + _39 = Pin::<&mut T> { __pointer: move _43 }; + StorageLive(_40); + _40 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_41); + _44 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); + _41 = Pin::<&mut T> { __pointer: move _44 }; + StorageLive(_42); + _42 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_42); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); + goto -> bb37; + } + + bb32: { + StorageLive(_33); + _37 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); + _33 = Pin::<&mut T> { __pointer: move _37 }; + StorageLive(_34); + _34 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_35); + _38 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); + _35 = Pin::<&mut T> { __pointer: move _38 }; + StorageLive(_36); + _36 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_36); + StorageDead(_35); + StorageDead(_34); + StorageDead(_33); + goto -> bb37; + } + + bb33: { + StorageLive(_27); + _31 = &mut (((((*_1) as Foo).0: Baz) as Bar).0: T); + _27 = Pin::<&mut T> { __pointer: move _31 }; + StorageLive(_28); + _28 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_29); + _32 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); + _29 = Pin::<&mut T> { __pointer: move _32 }; + StorageLive(_30); + _30 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + goto -> bb37; + } + + bb34: { + StorageLive(_21); + _25 = &mut (((((*_1) as Foo).0: Baz) as Bar).0: T); + _21 = Pin::<&mut T> { __pointer: move _25 }; + StorageLive(_22); + _22 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_23); + _26 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); + _23 = Pin::<&mut T> { __pointer: move _26 }; + StorageLive(_24); + _24 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageDead(_21); + goto -> bb37; + } + + bb35: { + StorageLive(_15); + _19 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); + _15 = Pin::<&mut T> { __pointer: move _19 }; + StorageLive(_16); + _16 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_17); + _20 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); + _17 = Pin::<&mut T> { __pointer: move _20 }; + StorageLive(_18); + _18 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + goto -> bb37; + } + + bb36: { + StorageLive(_9); + _13 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&mut T> { __pointer: move _13 }; + StorageLive(_10); + _10 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_11); + _14 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&mut T> { __pointer: move _14 }; + StorageLive(_12); + _12 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); + goto -> bb37; + } + + bb37: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir new file mode 100644 index 000000000000..2de14b4d14e1 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir @@ -0,0 +1,72 @@ +// MIR for `baz_const` after built + +fn baz_const(_1: Pin<&Baz>) -> () { + debug baz => _1; + let mut _0: (); + let mut _2: isize; + let _3: std::pin::Pin<&T>; + let _4: &U; + let mut _5: &T; + let _6: std::pin::Pin<&T>; + let _7: &U; + let mut _8: &T; + scope 1 { + debug x => _3; + debug y => _4; + } + scope 2 { + debug x => _6; + debug y => _7; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + falseEdge -> [real: bb6, imaginary: bb4]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + StorageLive(_6); + _8 = &(((*_1) as Bar).0: T); + _6 = Pin::<&T> { __pointer: move _8 }; + StorageLive(_7); + _7 = &(((*_1) as Bar).1: U); + _0 = const (); + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb5: { + goto -> bb1; + } + + bb6: { + StorageLive(_3); + _5 = &(((*_1) as Foo).0: T); + _3 = Pin::<&T> { __pointer: move _5 }; + StorageLive(_4); + _4 = &(((*_1) as Foo).1: U); + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb7; + } + + bb7: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir new file mode 100644 index 000000000000..9377d3a1dbc0 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir @@ -0,0 +1,72 @@ +// MIR for `baz_mut` after built + +fn baz_mut(_1: Pin<&mut Baz>) -> () { + debug baz => _1; + let mut _0: (); + let mut _2: isize; + let _3: std::pin::Pin<&mut T>; + let _4: &mut U; + let mut _5: &mut T; + let _6: std::pin::Pin<&mut T>; + let _7: &mut U; + let mut _8: &mut T; + scope 1 { + debug x => _3; + debug y => _4; + } + scope 2 { + debug x => _6; + debug y => _7; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + falseEdge -> [real: bb6, imaginary: bb4]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + StorageLive(_6); + _8 = &mut (((*_1) as Bar).0: T); + _6 = Pin::<&mut T> { __pointer: move _8 }; + StorageLive(_7); + _7 = &mut (((*_1) as Bar).1: U); + _0 = const (); + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb5: { + goto -> bb1; + } + + bb6: { + StorageLive(_3); + _5 = &mut (((*_1) as Foo).0: T); + _3 = Pin::<&mut T> { __pointer: move _5 }; + StorageLive(_4); + _4 = &mut (((*_1) as Foo).1: U); + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb7; + } + + bb7: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir new file mode 100644 index 000000000000..363d6a7e9874 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir @@ -0,0 +1,43 @@ +// MIR for `foo_bar_const` after built + +fn foo_bar_const(_1: Pin<&Foo, Bar>>) -> () { + debug foo => _1; + let mut _0: (); + let _2: std::pin::Pin<&T>; + let _3: &U; + let _4: std::pin::Pin<&T>; + let _5: &U; + let mut _6: &T; + let mut _7: &T; + scope 1 { + debug x => _2; + debug y => _3; + debug z => _4; + debug w => _5; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _6 = &(((*_1).0: Bar).0: T); + _2 = Pin::<&T> { __pointer: move _6 }; + StorageLive(_3); + _3 = &(((*_1).0: Bar).1: U); + StorageLive(_4); + _7 = &(((*_1).1: Bar).0: T); + _4 = Pin::<&T> { __pointer: move _7 }; + StorageLive(_5); + _5 = &(((*_1).1: Bar).1: U); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir new file mode 100644 index 000000000000..c5871a2fb4a2 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir @@ -0,0 +1,43 @@ +// MIR for `foo_bar_mut` after built + +fn foo_bar_mut(_1: Pin<&mut Foo, Bar>>) -> () { + debug foo => _1; + let mut _0: (); + let _2: std::pin::Pin<&mut T>; + let _3: &mut U; + let _4: std::pin::Pin<&mut T>; + let _5: &mut U; + let mut _6: &mut T; + let mut _7: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + debug z => _4; + debug w => _5; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _6 = &mut (((*_1).0: Bar).0: T); + _2 = Pin::<&mut T> { __pointer: move _6 }; + StorageLive(_3); + _3 = &mut (((*_1).0: Bar).1: U); + StorageLive(_4); + _7 = &mut (((*_1).1: Bar).0: T); + _4 = Pin::<&mut T> { __pointer: move _7 }; + StorageLive(_5); + _5 = &mut (((*_1).1: Bar).1: U); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir new file mode 100644 index 000000000000..95d62aacfb77 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `foo_const` after built + +fn foo_const(_1: Pin<&Foo>) -> () { + debug foo => _1; + let mut _0: (); + let _2: std::pin::Pin<&T>; + let _3: &U; + let mut _4: &T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &((*_1).0: T); + _2 = Pin::<&T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &((*_1).1: U); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir new file mode 100644 index 000000000000..043e7a9bbd51 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `foo_mut` after built + +fn foo_mut(_1: Pin<&mut Foo>) -> () { + debug foo => _1; + let mut _0: (); + let _2: std::pin::Pin<&mut T>; + let _3: &mut U; + let mut _4: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &mut ((*_1).0: T); + _2 = Pin::<&mut T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &mut ((*_1).1: U); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.rs b/tests/mir-opt/pin-ergonomics/project_pattern_match.rs new file mode 100644 index 000000000000..8808111f303b --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.rs @@ -0,0 +1,95 @@ +// skip-filecheck +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// This test verifies that a `&pin mut Foo` can be projected to a pinned +// reference `&pin mut T` of a `?Unpin` field , and can be projected to +// an unpinned reference `&mut U` of an `Unpin` field . + +struct Foo { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +// EMIT_MIR project_pattern_match.foo_mut.built.after.mir +fn foo_mut(foo: &pin mut Foo) { + let Foo { x, y } = foo; +} + +// EMIT_MIR project_pattern_match.foo_const.built.after.mir +fn foo_const(foo: &pin const Foo) { + let Foo { x, y } = foo; +} + +// EMIT_MIR project_pattern_match.bar_mut.built.after.mir +fn bar_mut(bar: &pin mut Bar) { + let Bar(x, y) = bar; +} + +// EMIT_MIR project_pattern_match.bar_const.built.after.mir +fn bar_const(bar: &pin const Bar) { + let Bar(x, y) = bar; +} + +// EMIT_MIR project_pattern_match.foo_bar_mut.built.after.mir +fn foo_bar_mut(foo: &pin mut Foo, Bar>) { + let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; +} + +// EMIT_MIR project_pattern_match.foo_bar_const.built.after.mir +fn foo_bar_const(foo: &pin const Foo, Bar>) { + let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; +} + +// EMIT_MIR project_pattern_match.baz_mut.built.after.mir +fn baz_mut(baz: &pin mut Baz) { + match baz { + Baz::Foo(x, y) => {} + Baz::Bar { x, y } => {} + } +} + +// EMIT_MIR project_pattern_match.baz_const.built.after.mir +fn baz_const(baz: &pin const Baz) { + match baz { + Baz::Foo(x, y) => {} + Baz::Bar { x, y } => {} + } +} + +// EMIT_MIR project_pattern_match.baz_baz_mut.built.after.mir +fn baz_baz_mut(baz: &pin mut Baz, Baz>) { + match baz { + Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {} + Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {} + Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {} + Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {} + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {} + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {} + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {} + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {} + } +} + +// EMIT_MIR project_pattern_match.baz_baz_const.built.after.mir +fn baz_baz_const(baz: &pin const Baz, Baz>) { + match baz { + Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {} + Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {} + Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {} + Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {} + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {} + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {} + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {} + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {} + } +} + +fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr new file mode 100644 index 000000000000..04284fbd6806 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr @@ -0,0 +1,313 @@ +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:41:9 + | +LL | let Foo { x, y } = foo; + | ^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo>` + | | + | expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:48:9 + | +LL | let Foo { x, y } = foo; + | ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo>` + | | + | expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:55:9 + | +LL | let Bar(x, y) = bar; + | ^^^^^^^^^ --- this expression has type `Pin<&mut Bar>` + | | + | expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar(x, y) = *bar; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:62:9 + | +LL | let Bar(x, y) = bar; + | ^^^^^^^^^ --- this expression has type `Pin<&Bar>` + | | + | expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar(x, y) = *bar; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:69:9 + | +LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo, Bar>>` + | | + | expected `Pin<&mut Foo, Bar>>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo, Bar>>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:78:9 + | +LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&Foo, Bar>>` + | | + | expected `Pin<&Foo, Bar>>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo, Bar>>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:88:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz>` +LL | Baz::Foo(x, y) => { + | ^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:93:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz>` +... +LL | Baz::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:103:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz>` +LL | Baz::Foo(x, y) => { + | ^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:108:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz>` +... +LL | Baz::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:118:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz, Baz>>` +LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:125:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz, Baz>>` +... +LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:132:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz, Baz>>` +... +LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:139:9 + | +LL | match baz { + | --- this expression has type `Pin<&mut Baz, Baz>>` +... +LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:151:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +LL | Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => { + | ^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:156:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +... +LL | Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:161:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +... +LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:168:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +... +LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:175:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +... +LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:182:9 + | +LL | match baz { + | --- this expression has type `Pin<&Baz, Baz>>` +... +LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + found enum `Baz<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *baz { + | + + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs new file mode 100644 index 000000000000..8f290e55a8dc --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs @@ -0,0 +1,192 @@ +//@ revisions: pin_project normal +//@ edition:2024 +//@[pin_project] check-pass +#![cfg_attr(pin_project, feature(pin_ergonomics))] +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +use std::pin::Pin; + +// This test verifies that a `&pin mut Foo` can be projected to a pinned +// reference `&pin mut T` of a `?Unpin` field , and can be projected to +// an unpinned reference `&mut U` of an `Unpin` field . + +struct Foo { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +trait IsPinMut {} +trait IsPinConst {} +trait IsRefMut {} +trait IsRef {} +impl IsPinMut for Pin<&mut T> {} +impl IsPinConst for Pin<&T> {} +impl IsRefMut for &mut T {} +impl IsRef for &T {} + +fn assert_pin_mut(_: T) {} +fn assert_pin_const(_: T) {} +fn assert_ref_mut(_: T) {} +fn assert_ref(_: T) {} + +fn foo_mut(foo: Pin<&mut Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); +} + +fn foo_const(foo: Pin<&Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); +} + +fn bar_mut(bar: Pin<&mut Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); +} + +fn bar_const(bar: Pin<&Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); +} + +fn foo_bar_mut(foo: Pin<&mut Foo, Bar>>) { + let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + assert_pin_mut(z); + assert_ref_mut(w); +} + +fn foo_bar_const(foo: Pin<&Foo, Bar>>) { + let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + assert_pin_const(z); + assert_ref(w); +} + +fn baz_mut(baz: Pin<&mut Baz>) { + match baz { + Baz::Foo(x, y) => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + } + Baz::Bar { x, y } => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + } + } +} + +fn baz_const(baz: Pin<&Baz>) { + match baz { + Baz::Foo(x, y) => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + } + Baz::Bar { x, y } => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + } + } +} + +fn baz_baz_mut(baz: Pin<&mut Baz, Baz>>) { + match baz { + Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + assert_pin_mut(z); + assert_ref_mut(w); + } + Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + assert_pin_mut(z); + assert_ref_mut(w); + } + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + assert_pin_mut(z); + assert_ref_mut(w); + } + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + assert_pin_mut(z); + assert_ref_mut(w); + } + } +} + +fn baz_baz_const(baz: Pin<&Baz, Baz>>) { + match baz { + Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + } + Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + } + Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + assert_pin_const(z); + assert_ref(w); + } + Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + assert_pin_const(z); + assert_ref(w); + } + Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + assert_pin_const(z); + assert_ref(w); + } + Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + assert_pin_const(z); + assert_ref(w); + } + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e..282459103bb1 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -12,6 +12,7 @@ params: [ kind: PatKind { Binding { name: "foo" + pinnedness: Not mode: BindingMode(No, Not) var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2)) ty: Foo