]> git.lizzy.rs Git - rust.git/commitdiff
Make metadata encoding deterministic
authorJonas Schievink <jonasschievink@gmail.com>
Tue, 23 Aug 2016 20:02:47 +0000 (22:02 +0200)
committerJonas Schievink <jonasschievink@gmail.com>
Sat, 27 Aug 2016 13:20:45 +0000 (15:20 +0200)
`ty::Predicate` was being used as a key for a hash map, but its hash
implementation indirectly hashed addresses, which vary between each
compiler run. This is fixed by sorting predicates by their ID before
encoding them.

In my tests, rustc is now able to produce deterministic results when
compiling libcore and libstd.

I've beefed up `run-make/reproducible-build` to compare the produced
artifacts bit-by-bit. This doesn't catch everything, but should be a
good start.

cc #34902

src/librustc_metadata/encoder.rs
src/test/run-make/reproducible-build/Makefile
src/test/run-make/reproducible-build/reproducible-build-aux.rs
src/test/run-make/reproducible-build/reproducible-build.rs

index 9a668b69b2eeb45480a5b8d456f7f65f28ae8ac0..f99bdf3b890cb42db8669cd37790c2c362c2f99f 100644 (file)
@@ -862,8 +862,13 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                           xrefs: FnvHashMap<XRef<'tcx>, u32>)
 {
     let mut xref_positions = vec![0; xrefs.len()];
+
+    // Encode XRefs sorted by their ID
+    let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect();
+    sorted_xrefs.sort_by_key(|&(_, id)| id);
+
     rbml_w.start_tag(tag_xref_data);
-    for (xref, id) in xrefs.into_iter() {
+    for (xref, id) in sorted_xrefs.into_iter() {
         xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
         match xref {
             XRef::Predicate(p) => {
index 8e799ca1a430305f784326bbf454088f8f0540d8..8b22dd021a9e78ae1c9583ba85f5900df9c6e5ac 100644 (file)
@@ -1,20 +1,24 @@
 -include ../tools.mk
 all:
        $(RUSTC) reproducible-build-aux.rs
+       mv libreproducible_build_aux.rlib first.rlib
+       $(RUSTC) reproducible-build-aux.rs
+       cp libreproducible_build_aux.rlib second.rlib
+       cmp "first.rlib" "second.rlib" || exit 1
        $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1"
        $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2"
-       nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm"
-       nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm"
-       cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1
+       cmp "$(TMPDIR)/reproducible-build1" "$(TMPDIR)/reproducible-build2" || exit 1
+       $(RUSTC) reproducible-build-aux.rs -g
+       mv libreproducible_build_aux.rlib first.rlib
        $(RUSTC) reproducible-build-aux.rs -g
+       cp libreproducible_build_aux.rlib second.rlib
        $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug"
        $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug"
-       nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm"
-       nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm"
-       cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1
+       cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || exit 1
+       $(RUSTC) reproducible-build-aux.rs -O
+       mv libreproducible_build_aux.rlib first.rlib
        $(RUSTC) reproducible-build-aux.rs -O
+       cp libreproducible_build_aux.rlib second.rlib
        $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt"
        $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt"
-       nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm"
-       nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm"
-       cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1
+       cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || exit 1
index 9ef853e79960b2d57771732bb5762e1b7029da9f..73a62eee265cd5a830e95dfedbd12597ddb691ce 100644 (file)
@@ -33,6 +33,12 @@ pub enum Enum {
 
 pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64);
 
-pub trait Trait<T1, T2> {
+pub trait Marker {}
+impl Marker for char {}
+impl<T, U> Marker for (T, U) {}
+
+pub trait Trait<T1: Marker + Marker + Marker, T2> where T1: 'static {
+    type Assoc: Marker;
+
     fn foo(&self);
 }
index dc7c702e5cc670e2befb493c9b5e8e44add131e1..a732cc11d60619654d580bea4419658148ce0f02 100644 (file)
@@ -67,7 +67,9 @@ impl Trait<i32, u64> for u64 {
     fn foo(&self) {}
 }
 
-impl reproducible_build_aux::Trait<char, String> for TupleStruct {
+impl<T: reproducible_build_aux::Marker + 'static> reproducible_build_aux::Trait<T, String> for TupleStruct {
+    type Assoc = (u8, i16);
+
     fn foo(&self) {}
 }
 
@@ -117,12 +119,10 @@ fn with_fn_once_adapter<F: FnOnce(i32)>(f: F) {
     let _ = reproducible_build_aux::Enum::Variant3 { x: 0 };
     let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4);
 
-    let object_shim: &reproducible_build_aux::Trait<char, String> = &TupleStruct(0, 1, 2, 3);
+    let object_shim: &reproducible_build_aux::Trait<char, String, Assoc=(u8, i16)> = &TupleStruct(0, 1, 2, 3);
     object_shim.foo();
 
     let pointer_shim: &Fn(i32) = &regular_fn;
 
     TupleStruct(1, 2, 3, 4).bar();
 }
-
-