about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2024-04-11 15:33:37 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2024-04-21 11:08:37 -0700
commit4f4442655ee755b68fc04386f243c637a64f8320 (patch)
tree212fd3f1d1b44129deb808fba652cefbe0e17282
parente6b2b764ecf08e3144274383e8f95e51fcaa6963 (diff)
downloadrust-4f4442655ee755b68fc04386f243c637a64f8320.tar.gz
rust-4f4442655ee755b68fc04386f243c637a64f8320.zip
Add an intrinsic that lowers to AggregateKind::RawPtr
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs5
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs28
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/intrinsics.rs26
-rw-r--r--tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-abort.diff95
-rw-r--r--tests/mir-opt/lower_intrinsics.make_pointers.LowerIntrinsics.panic-unwind.diff95
-rw-r--r--tests/mir-opt/lower_intrinsics.rs10
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);
+}