about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-02-09 15:44:54 +0100
committerRalf Jung <post@ralfj.de>2019-02-09 15:44:54 +0100
commit66adf52e7dfd68f04e60744ea9bf130c45befe5e (patch)
treeec29c4358d1921a13a4de039178ad5b5c3f1070f /src
parent312f3827faa8dc3b8e1dc8c1ad685a6222f16f03 (diff)
downloadrust-66adf52e7dfd68f04e60744ea9bf130c45befe5e.tar.gz
rust-66adf52e7dfd68f04e60744ea9bf130c45befe5e.zip
miri: give non-generic functions a stable address
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/interpret/mod.rs31
1 files changed, 23 insertions, 8 deletions
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index efd233f1f38..bb25d1b4209 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -27,7 +27,7 @@ pub use self::pointer::{Pointer, PointerArithmetic};
 use std::fmt;
 use crate::mir;
 use crate::hir::def_id::DefId;
-use crate::ty::{self, TyCtxt, Instance};
+use crate::ty::{self, TyCtxt, Instance, subst::UnpackedKind};
 use crate::ty::layout::{self, Size};
 use std::io;
 use crate::rustc_serialize::{Encoder, Decodable, Encodable};
@@ -318,14 +318,29 @@ impl<'tcx> AllocMap<'tcx> {
         id
     }
 
-    /// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
-    /// by the linker and functions can be duplicated across crates.
-    /// We thus generate a new `AllocId` for every mention of a function. This means that
-    /// `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
     pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId {
-        let id = self.reserve();
-        self.id_to_kind.insert(id, AllocKind::Function(instance));
-        id
+        // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
+        // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
+        // duplicated across crates.
+        // We thus generate a new `AllocId` for every mention of a function. This means that
+        // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
+        // However, formatting code relies on function identity (see #58320), so we only do
+        // this for generic functions.  Lifetime parameters are ignored.
+        let is_generic = instance.substs.into_iter().any(|kind| {
+            match kind.unpack() {
+                UnpackedKind::Lifetime(_) => false,
+                _ => true,
+            }
+        });
+        if is_generic {
+            // Get a fresh ID
+            let id = self.reserve();
+            self.id_to_kind.insert(id, AllocKind::Function(instance));
+            id
+        } else {
+            // Deduplicate
+            self.intern(AllocKind::Function(instance))
+        }
     }
 
     /// Returns `None` in case the `AllocId` is dangling. An `EvalContext` can still have a