diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2024-04-11 15:33:37 -0700 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2024-04-21 11:08:37 -0700 |
| commit | 4f4442655ee755b68fc04386f243c637a64f8320 (patch) | |
| tree | 212fd3f1d1b44129deb808fba652cefbe0e17282 | |
| parent | e6b2b764ecf08e3144274383e8f95e51fcaa6963 (diff) | |
| download | rust-4f4442655ee755b68fc04386f243c637a64f8320.tar.gz rust-4f4442655ee755b68fc04386f243c637a64f8320.zip | |
Add an intrinsic that lowers to AggregateKind::RawPtr
8 files changed, 264 insertions, 1 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 527325f1d6f..bf5592c828f 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -946,7 +946,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "input pointer must be thin"); } } else { - self.fail(location, "first operand to raw pointer aggregate must be a raw pointer"); + self.fail( + location, + "first operand to raw pointer aggregate must be a raw pointer", + ); } // FIXME: Check metadata more generally diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index bd64621f077..fb4a76bf089 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -128,6 +128,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::variant_count | sym::is_val_statically_known | sym::ptr_mask + | sym::aggregate_raw_ptr | sym::ub_checks | sym::fadd_algebraic | sym::fsub_algebraic @@ -574,6 +575,10 @@ pub fn check_intrinsic_type( (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) } + // This type check is not particularly useful, but the `where` bounds + // on the definition in `core` do the heavy lifting for checking it. + sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), + sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), sym::simd_eq diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 7e8920604c1..da63fcf23d9 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -287,6 +287,34 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Unreachable; } } + sym::aggregate_raw_ptr => { + let Ok([data, meta]) = <[_; 2]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for aggregate_raw_ptr intrinsic", + ); + }; + let target = target.unwrap(); + let pointer_ty = generic_args.type_at(0); + let kind = if let ty::RawPtr(pointee_ty, mutability) = pointer_ty.kind() { + AggregateKind::RawPtr(*pointee_ty, *mutability) + } else { + span_bug!( + terminator.source_info.span, + "Return type of aggregate_raw_ptr intrinsic must be a raw pointer", + ); + }; + let fields = [data.node, meta.node]; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Aggregate(Box::new(kind), fields.into()), + ))), + }); + + terminator.kind = TerminatorKind::Goto { target }; + } _ => {} } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46bae1c1e98..f5eeb3d4ff1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -361,6 +361,7 @@ symbols! { adt_const_params, advanced_slice_patterns, adx_target_feature, + aggregate_raw_ptr, alias, align, align_offset, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 9406efd7ab2..b49409a9f42 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2779,6 +2779,32 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { unreachable!() } +/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. +/// +/// This is used to implement functions like `slice::from_raw_parts_mut` and +/// `ptr::from_raw_parts` in a way compatible with the compiler being able to +/// change the possible layouts of pointers. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P { + // No fallback because `libcore` doesn't want to know the layout + unreachable!() +} + +#[unstable(feature = "core_intrinsics", issue = "none")] +pub trait AggregateRawPtr<D> { + type Metadata: Copy; +} +impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*const T> for *const P { + type Metadata = <P as ptr::Pointee>::Metadata; +} +impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P { + type Metadata = <P as ptr::Pointee>::Metadata; +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>. // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-abort.diff new file mode 100644 index 00000000000..02934d4c01e --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-abort.diff @@ -0,0 +1,95 @@ +- // MIR for `make_pointers` before LowerIntrinsics ++ // MIR for `make_pointers` after LowerIntrinsics + + fn make_pointers(_1: *const u8, _2: *mut (), _3: usize) -> () { + debug a => _1; + debug b => _2; + debug n => _3; + let mut _0: (); + let _4: *const i32; + let mut _5: *const u8; + let mut _6: (); + let mut _8: *mut (); + let mut _9: (); + let mut _11: *const u8; + let mut _12: usize; + let mut _14: *mut (); + let mut _15: usize; + scope 1 { + debug _thin_const => _4; + let _7: *mut u8; + scope 2 { + debug _thin_mut => _7; + let _10: *const [u16]; + scope 3 { + debug _slice_const => _10; + let _13: *mut [u64]; + scope 4 { + debug _slice_mut => _13; + } + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; + StorageLive(_6); + _6 = (); +- _4 = aggregate_raw_ptr::<*const i32, *const u8, ()>(move _5, move _6) -> [return: bb1, unwind unreachable]; ++ _4 = *const i32 from (move _5, move _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); + StorageLive(_7); + StorageLive(_8); + _8 = _2; + StorageLive(_9); + _9 = (); +- _7 = aggregate_raw_ptr::<*mut u8, *mut (), ()>(move _8, move _9) -> [return: bb2, unwind unreachable]; ++ _7 = *mut u8 from (move _8, move _9); ++ goto -> bb2; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + _11 = _1; + StorageLive(_12); + _12 = _3; +- _10 = aggregate_raw_ptr::<*const [u16], *const u8, usize>(move _11, move _12) -> [return: bb3, unwind unreachable]; ++ _10 = *const [u16] from (move _11, move _12); ++ goto -> bb3; + } + + bb3: { + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + _14 = _2; + StorageLive(_15); + _15 = _3; +- _13 = aggregate_raw_ptr::<*mut [u64], *mut (), usize>(move _14, move _15) -> [return: bb4, unwind unreachable]; ++ _13 = *mut [u64] from (move _14, move _15); ++ goto -> bb4; + } + + bb4: { + StorageDead(_15); + StorageDead(_14); + _0 = const (); + StorageDead(_13); + StorageDead(_10); + StorageDead(_7); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-unwind.diff new file mode 100644 index 00000000000..02934d4c01e --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-unwind.diff @@ -0,0 +1,95 @@ +- // MIR for `make_pointers` before LowerIntrinsics ++ // MIR for `make_pointers` after LowerIntrinsics + + fn make_pointers(_1: *const u8, _2: *mut (), _3: usize) -> () { + debug a => _1; + debug b => _2; + debug n => _3; + let mut _0: (); + let _4: *const i32; + let mut _5: *const u8; + let mut _6: (); + let mut _8: *mut (); + let mut _9: (); + let mut _11: *const u8; + let mut _12: usize; + let mut _14: *mut (); + let mut _15: usize; + scope 1 { + debug _thin_const => _4; + let _7: *mut u8; + scope 2 { + debug _thin_mut => _7; + let _10: *const [u16]; + scope 3 { + debug _slice_const => _10; + let _13: *mut [u64]; + scope 4 { + debug _slice_mut => _13; + } + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; + StorageLive(_6); + _6 = (); +- _4 = aggregate_raw_ptr::<*const i32, *const u8, ()>(move _5, move _6) -> [return: bb1, unwind unreachable]; ++ _4 = *const i32 from (move _5, move _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); + StorageLive(_7); + StorageLive(_8); + _8 = _2; + StorageLive(_9); + _9 = (); +- _7 = aggregate_raw_ptr::<*mut u8, *mut (), ()>(move _8, move _9) -> [return: bb2, unwind unreachable]; ++ _7 = *mut u8 from (move _8, move _9); ++ goto -> bb2; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + _11 = _1; + StorageLive(_12); + _12 = _3; +- _10 = aggregate_raw_ptr::<*const [u16], *const u8, usize>(move _11, move _12) -> [return: bb3, unwind unreachable]; ++ _10 = *const [u16] from (move _11, move _12); ++ goto -> bb3; + } + + bb3: { + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + _14 = _2; + StorageLive(_15); + _15 = _3; +- _13 = aggregate_raw_ptr::<*mut [u64], *mut (), usize>(move _14, move _15) -> [return: bb4, unwind unreachable]; ++ _13 = *mut [u64] from (move _14, move _15); ++ goto -> bb4; + } + + bb4: { + StorageDead(_15); + StorageDead(_14); + _0 = const (); + StorageDead(_13); + StorageDead(_10); + StorageDead(_7); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 693425c0041..12e526ab074 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -248,3 +248,13 @@ pub fn three_way_compare_signed(a: i16, b: i16) { pub fn three_way_compare_unsigned(a: u32, b: u32) { let _x = core::intrinsics::three_way_compare(a, b); } + +// EMIT_MIR lower_intrinsics.make_pointers.LowerIntrinsics.diff +pub fn make_pointers(a: *const u8, b: *mut (), n: usize) { + use std::intrinsics::aggregate_raw_ptr; + + let _thin_const: *const i32 = aggregate_raw_ptr(a, ()); + let _thin_mut: *mut u8 = aggregate_raw_ptr(b, ()); + let _slice_const: *const [u16] = aggregate_raw_ptr(a, n); + let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n); +} |
