about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/html/render/write_shared.rs18
-rw-r--r--src/librustdoc/html/render/write_shared/tests.rs6
-rw-r--r--src/tools/miri/src/machine.rs46
-rw-r--r--src/tools/miri/tests/panic/target_feature_wasm.rs (renamed from src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs)4
4 files changed, 59 insertions, 15 deletions
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index a18b7a252a4..60dc142b9ff 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -75,11 +75,11 @@ pub(crate) fn write_shared(
     let crate_name = krate.name(cx.tcx());
     let crate_name = crate_name.as_str(); // rand
     let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand"
-    let external_crates = hack_get_external_crate_names(&cx.dst)?;
+    let external_crates = hack_get_external_crate_names(&cx.dst, &cx.shared.resource_suffix)?;
     let info = CrateInfo {
         src_files_js: SourcesPart::get(cx, &crate_name_json)?,
         search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?,
-        all_crates: AllCratesPart::get(crate_name_json.clone())?,
+        all_crates: AllCratesPart::get(crate_name_json.clone(), &cx.shared.resource_suffix)?,
         crates_index: CratesIndexPart::get(&crate_name, &external_crates)?,
         trait_impl: TraitAliasPart::get(cx, &crate_name_json)?,
         type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?,
@@ -291,10 +291,13 @@ impl AllCratesPart {
         SortedTemplate::from_before_after("window.ALL_CRATES = [", "];")
     }
 
-    fn get(crate_name_json: OrderedJson) -> Result<PartsAndLocations<Self>, Error> {
+    fn get(
+        crate_name_json: OrderedJson,
+        resource_suffix: &str,
+    ) -> Result<PartsAndLocations<Self>, Error> {
         // external hack_get_external_crate_names not needed here, because
         // there's no way that we write the search index but not crates.js
-        let path = PathBuf::from("crates.js");
+        let path = suffix_path("crates.js", resource_suffix);
         Ok(PartsAndLocations::with(path, crate_name_json))
     }
 }
@@ -305,8 +308,11 @@ impl AllCratesPart {
 ///
 /// This is to match the current behavior of rustdoc, which allows you to get all crates
 /// on the index page, even if --enable-index-page is only passed to the last crate.
-fn hack_get_external_crate_names(doc_root: &Path) -> Result<Vec<String>, Error> {
-    let path = doc_root.join("crates.js");
+fn hack_get_external_crate_names(
+    doc_root: &Path,
+    resource_suffix: &str,
+) -> Result<Vec<String>, Error> {
+    let path = doc_root.join(suffix_path("crates.js", resource_suffix));
     let Ok(content) = fs::read_to_string(&path) else {
         // they didn't emit invocation specific, so we just say there were no crates
         return Ok(Vec::default());
diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs
index 4d1874b7df5..e282cd99e43 100644
--- a/src/librustdoc/html/render/write_shared/tests.rs
+++ b/src/librustdoc/html/render/write_shared/tests.rs
@@ -6,10 +6,10 @@ use crate::html::render::write_shared::*;
 fn hack_external_crate_names() {
     let path = tempfile::TempDir::new().unwrap();
     let path = path.path();
-    let crates = hack_get_external_crate_names(&path).unwrap();
+    let crates = hack_get_external_crate_names(&path, "").unwrap();
     assert!(crates.is_empty());
     fs::write(path.join("crates.js"), r#"window.ALL_CRATES = ["a","b","c"];"#).unwrap();
-    let crates = hack_get_external_crate_names(&path).unwrap();
+    let crates = hack_get_external_crate_names(&path, "").unwrap();
     assert_eq!(crates, ["a".to_string(), "b".to_string(), "c".to_string()]);
 }
 
@@ -60,7 +60,7 @@ fn all_crates_template() {
 
 #[test]
 fn all_crates_parts() {
-    let parts = AllCratesPart::get(OrderedJson::serialize("crate").unwrap()).unwrap();
+    let parts = AllCratesPart::get(OrderedJson::serialize("crate").unwrap(), "").unwrap();
     assert_eq!(&parts.parts[0].0, Path::new("crates.js"));
     assert_eq!(&parts.parts[0].1.to_string(), r#""crate""#);
 }
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index a7493d48d6a..264b7b269de 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -947,15 +947,47 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     #[inline(always)]
-    fn enforce_abi(_ecx: &MiriInterpCx<'tcx>) -> bool {
-        true
-    }
-
-    #[inline(always)]
     fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'tcx>) -> bool {
         !ecx.tcx.sess.overflow_checks()
     }
 
+    fn check_fn_target_features(
+        ecx: &MiriInterpCx<'tcx>,
+        instance: ty::Instance<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id());
+        if attrs
+            .target_features
+            .iter()
+            .any(|feature| !ecx.tcx.sess.target_features.contains(&feature.name))
+        {
+            let unavailable = attrs
+                .target_features
+                .iter()
+                .filter(|&feature| {
+                    !feature.implied && !ecx.tcx.sess.target_features.contains(&feature.name)
+                })
+                .fold(String::new(), |mut s, feature| {
+                    if !s.is_empty() {
+                        s.push_str(", ");
+                    }
+                    s.push_str(feature.name.as_str());
+                    s
+                });
+            let msg = format!(
+                "calling a function that requires unavailable target features: {unavailable}"
+            );
+            // On WASM, this is not UB, but instead gets rejected during validation of the module
+            // (see #84988).
+            if ecx.tcx.sess.target.is_like_wasm {
+                throw_machine_stop!(TerminationInfo::Abort(msg));
+            } else {
+                throw_ub_format!("{msg}");
+            }
+        }
+        Ok(())
+    }
+
     #[inline(always)]
     fn find_mir_or_eval_fn(
         ecx: &mut MiriInterpCx<'tcx>,
@@ -1060,6 +1092,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx.generate_nan(inputs)
     }
 
+    fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> {
+        Ok(ecx.tcx.sess.ub_checks())
+    }
+
     fn thread_local_static_pointer(
         ecx: &mut MiriInterpCx<'tcx>,
         def_id: DefId,
diff --git a/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs b/src/tools/miri/tests/panic/target_feature_wasm.rs
index 5056f32de44..c67d2983f78 100644
--- a/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs
+++ b/src/tools/miri/tests/panic/target_feature_wasm.rs
@@ -2,7 +2,9 @@
 //@compile-flags: -C target-feature=-simd128
 
 fn main() {
-    // Calling functions with `#[target_feature]` is not unsound on WASM, see #84988
+    // Calling functions with `#[target_feature]` is not unsound on WASM, see #84988.
+    // But if the compiler actually uses the target feature, it will lead to an error when the module is loaded.
+    // We emulate this with an "unsupported" error.
     assert!(!cfg!(target_feature = "simd128"));
     simd128_fn();
 }