about summary refs log tree commit diff
path: root/compiler/rustc_target/src
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2022-06-20 07:37:42 +0900
committerGitHub <noreply@github.com>2022-06-20 07:37:42 +0900
commitbfa6cd9c6802efe3d6cef119bed1f78e596062d2 (patch)
treeebc37af8c86354e3fea63cdd955244c15cae172d /compiler/rustc_target/src
parent77316a4aaa0029481397ff2e43f57e60d5226569 (diff)
parentb4b536d34d8d2371a4be95a2b294bbf0088807b7 (diff)
downloadrust-bfa6cd9c6802efe3d6cef119bed1f78e596062d2.tar.gz
rust-bfa6cd9c6802efe3d6cef119bed1f78e596062d2.zip
Rollup merge of #98225 - bjorn3:stable_target_json_hash, r=nagisa
Make debug_triple depend on target json file content rather than file path

This ensures that changes to target json files will force a recompilation. And more importantly that moving the files doesn't force a recompilation.

This should fix https://github.com/Rust-for-Linux/linux/issues/792 (cc ``@ojeda)``
Diffstat (limited to 'compiler/rustc_target/src')
-rw-r--r--compiler/rustc_target/src/spec/mod.rs124
1 files changed, 99 insertions, 25 deletions
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 422af667875..fd0c3f36e72 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -39,11 +39,13 @@ use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::symbol::{sym, Symbol};
 use serde_json::Value;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::convert::TryFrom;
+use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
@@ -2183,7 +2185,7 @@ impl Target {
             TargetTriple::TargetTriple(ref target_triple) => {
                 load_builtin(target_triple).expect("built-in target")
             }
-            TargetTriple::TargetPath(..) => {
+            TargetTriple::TargetJson { .. } => {
                 panic!("built-in targets doens't support target-paths")
             }
         }
@@ -2248,11 +2250,9 @@ impl Target {
 
                 Err(format!("Could not find specification for target {:?}", target_triple))
             }
-            TargetTriple::TargetPath(ref target_path) => {
-                if target_path.is_file() {
-                    return load_file(&target_path);
-                }
-                Err(format!("Target path {:?} is not a valid file", target_path))
+            TargetTriple::TargetJson { ref contents, .. } => {
+                let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
+                Target::from_json(obj)
             }
         }
     }
@@ -2421,10 +2421,77 @@ impl ToJson for Target {
 }
 
 /// Either a target triple string or a path to a JSON file.
-#[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)]
+#[derive(Clone, Debug)]
 pub enum TargetTriple {
     TargetTriple(String),
-    TargetPath(PathBuf),
+    TargetJson {
+        /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
+        /// inconsistencies as it is discarded during serialization.
+        path_for_rustdoc: PathBuf,
+        triple: String,
+        contents: String,
+    },
+}
+
+// Use a manual implementation to ignore the path field
+impl PartialEq for TargetTriple {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
+            (
+                Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
+                Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
+            ) => l_triple == r_triple && l_contents == r_contents,
+            _ => false,
+        }
+    }
+}
+
+// Use a manual implementation to ignore the path field
+impl Hash for TargetTriple {
+    fn hash<H: Hasher>(&self, state: &mut H) -> () {
+        match self {
+            TargetTriple::TargetTriple(triple) => {
+                0u8.hash(state);
+                triple.hash(state)
+            }
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
+                1u8.hash(state);
+                triple.hash(state);
+                contents.hash(state)
+            }
+        }
+    }
+}
+
+// Use a manual implementation to prevent encoding the target json file path in the crate metadata
+impl<S: Encoder> Encodable<S> for TargetTriple {
+    fn encode(&self, s: &mut S) {
+        match self {
+            TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)),
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s
+                .emit_enum_variant(1, |s| {
+                    s.emit_str(triple);
+                    s.emit_str(contents)
+                }),
+        }
+    }
+}
+
+impl<D: Decoder> Decodable<D> for TargetTriple {
+    fn decode(d: &mut D) -> Self {
+        match d.read_usize() {
+            0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
+            1 => TargetTriple::TargetJson {
+                path_for_rustdoc: PathBuf::new(),
+                triple: d.read_str().to_owned(),
+                contents: d.read_str().to_owned(),
+            },
+            _ => {
+                panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
+            }
+        }
+    }
 }
 
 impl TargetTriple {
@@ -2436,7 +2503,19 @@ impl TargetTriple {
     /// Creates a target triple from the passed target path.
     pub fn from_path(path: &Path) -> Result<Self, io::Error> {
         let canonicalized_path = path.canonicalize()?;
-        Ok(TargetTriple::TargetPath(canonicalized_path))
+        let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
+            io::Error::new(
+                io::ErrorKind::InvalidInput,
+                format!("target path {:?} is not a valid file: {}", canonicalized_path, err),
+            )
+        })?;
+        let triple = canonicalized_path
+            .file_stem()
+            .expect("target path must not be empty")
+            .to_str()
+            .expect("target path must be valid unicode")
+            .to_owned();
+        Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
     }
 
     /// Returns a string triple for this target.
@@ -2444,12 +2523,8 @@ impl TargetTriple {
     /// If this target is a path, the file name (without extension) is returned.
     pub fn triple(&self) -> &str {
         match *self {
-            TargetTriple::TargetTriple(ref triple) => triple,
-            TargetTriple::TargetPath(ref path) => path
-                .file_stem()
-                .expect("target path must not be empty")
-                .to_str()
-                .expect("target path must be valid unicode"),
+            TargetTriple::TargetTriple(ref triple)
+            | TargetTriple::TargetJson { ref triple, .. } => triple,
         }
     }
 
@@ -2459,16 +2534,15 @@ impl TargetTriple {
     /// by `triple()`.
     pub fn debug_triple(&self) -> String {
         use std::collections::hash_map::DefaultHasher;
-        use std::hash::{Hash, Hasher};
-
-        let triple = self.triple();
-        if let TargetTriple::TargetPath(ref path) = *self {
-            let mut hasher = DefaultHasher::new();
-            path.hash(&mut hasher);
-            let hash = hasher.finish();
-            format!("{}-{}", triple, hash)
-        } else {
-            triple.into()
+
+        match self {
+            TargetTriple::TargetTriple(triple) => triple.to_owned(),
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
+                let mut hasher = DefaultHasher::new();
+                content.hash(&mut hasher);
+                let hash = hasher.finish();
+                format!("{}-{}", triple, hash)
+            }
         }
     }
 }