about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2022-12-27 12:31:17 +0100
committerRalf Jung <post@ralfj.de>2023-02-06 11:46:32 +0100
commit201ae7387245caa4591d4c8db4c35c170c64faf0 (patch)
tree011ec2bc77cfee914cfab9d89b61c40232046986
parent0c13c172507f01d921808107d2c4ec37b43b982d (diff)
downloadrust-201ae7387245caa4591d4c8db4c35c170c64faf0.tar.gz
rust-201ae7387245caa4591d4c8db4c35c170c64faf0.zip
make PointerKind directly reflect pointer types
The code that consumes PointerKind (`adjust_for_rust_scalar` in rustc_ty_utils)
ended up using PointerKind variants to talk about Rust reference types (& and
&mut) anyway, making the old code structure quite confusing: one always had to
keep in mind which PointerKind corresponds to which type. So this changes
PointerKind to directly reflect the type.

This does not change behavior.
-rw-r--r--compiler/rustc_abi/src/lib.rs21
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs39
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs33
-rw-r--r--tests/codegen/function-arguments-noopt.rs6
4 files changed, 40 insertions, 59 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 5af6206c0bb..9126c516d38 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1439,21 +1439,12 @@ impl<V: Idx> fmt::Debug for LayoutS<V> {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
-    /// Most general case, we know no restrictions to tell LLVM.
-    SharedMutable,
-
-    /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
-    Frozen,
-
-    /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
-    UniqueBorrowed,
-
-    /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
-    UniqueBorrowedPinned,
-
-    /// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
-    /// nor `dereferenceable`.
-    UniqueOwned,
+    /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
+    SharedRef { frozen: bool },
+    /// Mutable reference. `unpin` indicates the absence of any pinned data.
+    MutableRef { unpin: bool },
+    /// Box.
+    Box,
 }
 
 /// Note that this information is advisory only, and backends are free to ignore it.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index cdcd6281f20..1244922c6d4 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -833,32 +833,17 @@ where
                     })
                 }
                 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
-                    let kind = if tcx.sess.opts.optimize == OptLevel::No {
-                        // Use conservative pointer kind if not optimizing. This saves us the
-                        // Freeze/Unpin queries, and can save time in the codegen backend (noalias
-                        // attributes in LLVM have compile-time cost even in unoptimized builds).
-                        PointerKind::SharedMutable
-                    } else {
-                        match mt {
-                            hir::Mutability::Not => {
-                                if ty.is_freeze(tcx, cx.param_env()) {
-                                    PointerKind::Frozen
-                                } else {
-                                    PointerKind::SharedMutable
-                                }
-                            }
-                            hir::Mutability::Mut => {
-                                // References to self-referential structures should not be considered
-                                // noalias, as another pointer to the structure can be obtained, that
-                                // is not based-on the original reference. We consider all !Unpin
-                                // types to be potentially self-referential here.
-                                if ty.is_unpin(tcx, cx.param_env()) {
-                                    PointerKind::UniqueBorrowed
-                                } else {
-                                    PointerKind::UniqueBorrowedPinned
-                                }
-                            }
-                        }
+                    // Use conservative pointer kind if not optimizing. This saves us the
+                    // Freeze/Unpin queries, and can save time in the codegen backend (noalias
+                    // attributes in LLVM have compile-time cost even in unoptimized builds).
+                    let optimize = tcx.sess.opts.optimize != OptLevel::No;
+                    let kind = match mt {
+                        hir::Mutability::Not => PointerKind::SharedRef {
+                            frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
+                        },
+                        hir::Mutability::Mut => PointerKind::MutableRef {
+                            unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
+                        },
                     };
 
                     tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
@@ -929,7 +914,7 @@ where
                     if let Some(ref mut pointee) = result {
                         if let ty::Adt(def, _) = this.ty.kind() {
                             if def.is_box() && offset.bytes() == 0 {
-                                pointee.safe = Some(PointerKind::UniqueOwned);
+                                pointee.safe = Some(PointerKind::Box);
                             }
                         }
                     }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 1c74aeca5ab..884087987ce 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -254,15 +254,15 @@ fn adjust_for_rust_scalar<'tcx>(
         if let Some(kind) = pointee.safe {
             attrs.pointee_align = Some(pointee.align);
 
-            // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
-            // for the entire duration of the function as they can be deallocated
-            // at any time. Same for shared mutable references. If LLVM had a
-            // way to say "dereferenceable on entry" we could use it here.
+            // `Box` are not necessarily dereferenceable for the entire duration of the function as
+            // they can be deallocated at any time. Same for non-frozen shared references (see
+            // <https://github.com/rust-lang/rust/pull/98017>). If LLVM had a way to say
+            // "dereferenceable on entry" we could use it here.
             attrs.pointee_size = match kind {
-                PointerKind::UniqueBorrowed
-                | PointerKind::UniqueBorrowedPinned
-                | PointerKind::Frozen => pointee.size,
-                PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+                PointerKind::Box | PointerKind::SharedRef { frozen: false } => Size::ZERO,
+                PointerKind::SharedRef { frozen: true } | PointerKind::MutableRef { .. } => {
+                    pointee.size
+                }
             };
 
             // The aliasing rules for `Box<T>` are still not decided, but currently we emit
@@ -278,15 +278,14 @@ fn adjust_for_rust_scalar<'tcx>(
             // `&mut` pointer parameters never alias other parameters,
             // or mutable global data
             //
-            // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-            // and can be marked as both `readonly` and `noalias`, as
-            // LLVM's definition of `noalias` is based solely on memory
-            // dependencies rather than pointer equality
+            // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
+            // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
+            // dependencies rather than pointer equality. However this only applies to arguments,
+            // not return values.
             let no_alias = match kind {
-                PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
-                PointerKind::UniqueBorrowed => noalias_mut_ref,
-                PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => true,
+                PointerKind::SharedRef { frozen } => frozen,
+                PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
+                PointerKind::Box => noalias_for_box,
             };
             // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
             // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
@@ -294,7 +293,7 @@ fn adjust_for_rust_scalar<'tcx>(
                 attrs.set(ArgAttribute::NoAlias);
             }
 
-            if kind == PointerKind::Frozen && !is_return {
+            if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
                 attrs.set(ArgAttribute::ReadOnly);
             }
         }
diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs
index ff76405a4ea..0c62e0d35e3 100644
--- a/tests/codegen/function-arguments-noopt.rs
+++ b/tests/codegen/function-arguments-noopt.rs
@@ -29,6 +29,12 @@ pub fn borrow(x: &i32) -> &i32 {
   x
 }
 
+// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x)
+#[no_mangle]
+pub fn borrow_mut(x: &mut i32) -> &mut i32 {
+  x
+}
+
 // CHECK-LABEL: @borrow_call
 #[no_mangle]
 pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {