From 50835bf1943193f7a78cc39b17f6e90b72bff5a4 Mon Sep 17 00:00:00 2001
From: ltdk
Date: Sat, 27 Jul 2024 01:51:04 -0400
Subject: [PATCH 01/31] impl Default for collection iterators that don't
already have it
---
.../alloc/src/collections/binary_heap/mod.rs | 14 ++++++++++
library/alloc/src/collections/btree/map.rs | 28 +++++++++++++++++++
.../alloc/src/collections/vec_deque/iter.rs | 14 ++++++++++
.../src/collections/vec_deque/iter_mut.rs | 14 ++++++++++
4 files changed, 70 insertions(+)
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index fe1ff24139554..a4a172b86e54a 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -1433,6 +1433,20 @@ pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
}
+#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Iter<'_, T> {
+ /// Creates an empty `binary_heap::Iter`.
+ ///
+ /// ```
+ /// # use std::collections::binary_heap;
+ /// let iter: binary_heap::Iter<'_, u8> = Default::default();
+ /// assert_eq!(iter.len(), 0);
+ /// ```
+ fn default() -> Self {
+ Iter { iter: Default::default() }
+ }
+}
+
#[stable(feature = "collection_debug", since = "1.17.0")]
impl fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 3875f61efafdf..a2e97bcee829e 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -2016,6 +2016,20 @@ impl Default for Range<'_, K, V> {
}
}
+#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+impl Default for RangeMut<'_, K, V> {
+ /// Creates an empty `btree_map::RangeMut`.
+ ///
+ /// ```
+ /// # use std::collections::btree_map;
+ /// let iter: btree_map::RangeMut<'_, u8, u8> = Default::default();
+ /// assert_eq!(iter.count(), 0);
+ /// ```
+ fn default() -> Self {
+ RangeMut { inner: Default::default(), _marker: PhantomData }
+ }
+}
+
#[stable(feature = "map_values_mut", since = "1.10.0")]
impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
type Item = &'a mut V;
@@ -2050,6 +2064,20 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> {
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ValuesMut<'_, K, V> {}
+#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+impl Default for ValuesMut<'_, K, V> {
+ /// Creates an empty `btree_map::ValuesMut`.
+ ///
+ /// ```
+ /// # use std::collections::btree_map;
+ /// let iter: btree_map::ValuesMut<'_, u8, u8> = Default::default();
+ /// assert_eq!(iter.count(), 0);
+ /// ```
+ fn default() -> Self {
+ ValuesMut { inner: Default::default() }
+ }
+}
+
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
impl Iterator for IntoKeys {
type Item = K;
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index 5a5e7f70854d8..10adc547da666 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -28,6 +28,20 @@ impl fmt::Debug for Iter<'_, T> {
}
}
+#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Iter<'_, T> {
+ /// Creates an empty `vec_deque::Iter`.
+ ///
+ /// ```
+ /// # use std::collections::vec_deque;
+ /// let iter: vec_deque::Iter<'_, u8> = Default::default();
+ /// assert_eq!(iter.len(), 0);
+ /// ```
+ fn default() -> Self {
+ Iter { i1: Default::default(), i2: Default::default() }
+ }
+}
+
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for Iter<'_, T> {
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 5061931afb7b7..18f11096eeb93 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -28,6 +28,20 @@ impl fmt::Debug for IterMut<'_, T> {
}
}
+#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+impl Default for IterMut<'_, T> {
+ /// Creates an empty `vec_deque::IterMut`.
+ ///
+ /// ```
+ /// # use std::collections::vec_deque;
+ /// let iter: vec_deque::IterMut<'_, u8> = Default::default();
+ /// assert_eq!(iter.len(), 0);
+ /// ```
+ fn default() -> Self {
+ IterMut { i1: Default::default(), i2: Default::default() }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
From 0b9972049727f08610c038bce7177571b7111df5 Mon Sep 17 00:00:00 2001
From: ltdk
Date: Sat, 27 Jul 2024 02:48:55 -0400
Subject: [PATCH 02/31] Okay, I guess I have to give these a different feature
name
---
library/alloc/src/collections/binary_heap/mod.rs | 2 +-
library/alloc/src/collections/btree/map.rs | 4 ++--
library/alloc/src/collections/vec_deque/iter.rs | 2 +-
library/alloc/src/collections/vec_deque/iter_mut.rs | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index a4a172b86e54a..72e466f4dcdc4 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -1433,7 +1433,7 @@ pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
}
-#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl Default for Iter<'_, T> {
/// Creates an empty `binary_heap::Iter`.
///
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index a2e97bcee829e..2c28e893f3696 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -2016,7 +2016,7 @@ impl Default for Range<'_, K, V> {
}
}
-#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl Default for RangeMut<'_, K, V> {
/// Creates an empty `btree_map::RangeMut`.
///
@@ -2064,7 +2064,7 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> {
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ValuesMut<'_, K, V> {}
-#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl Default for ValuesMut<'_, K, V> {
/// Creates an empty `btree_map::ValuesMut`.
///
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index 10adc547da666..67b5b91c4d4b0 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -28,7 +28,7 @@ impl fmt::Debug for Iter<'_, T> {
}
}
-#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl Default for Iter<'_, T> {
/// Creates an empty `vec_deque::Iter`.
///
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 18f11096eeb93..2726e3e425290 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -28,7 +28,7 @@ impl fmt::Debug for IterMut<'_, T> {
}
}
-#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl Default for IterMut<'_, T> {
/// Creates an empty `vec_deque::IterMut`.
///
From ba0d6c973994915faef00e0e15e2957ff2b286b7 Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Thu, 4 Jul 2024 18:34:35 +0100
Subject: [PATCH 03/31] Update generate-copyright
This tool now scans for cargo dependencies and includes any important looking license files.
We do this because cargo package metadata is not sufficient - the Apache-2.0 license says you have to include any NOTICE file, for example. And authors != copyright holders (cargo has the former, we must include the latter).
---
Cargo.lock | 2 +
src/bootstrap/src/core/build_steps/run.rs | 2 +
src/tools/collect-license-metadata/Cargo.toml | 2 +
.../collect-license-metadata/src/main.rs | 5 +
src/tools/generate-copyright/Cargo.toml | 3 +
.../generate-copyright/src/cargo_metadata.rs | 196 ++++++++++++++++++
src/tools/generate-copyright/src/main.rs | 122 +++++++++--
7 files changed, 320 insertions(+), 12 deletions(-)
create mode 100644 src/tools/generate-copyright/src/cargo_metadata.rs
diff --git a/Cargo.lock b/Cargo.lock
index a4b4e49f82c2e..0f3a106512d20 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1408,6 +1408,8 @@ dependencies = [
"anyhow",
"serde",
"serde_json",
+ "tempfile",
+ "thiserror",
]
[[package]]
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index fde1693646a8b..29d7bcc425bea 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -217,6 +217,8 @@ impl Step for GenerateCopyright {
let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
cmd.env("LICENSE_METADATA", &license_metadata);
cmd.env("DEST", &dest);
+ cmd.env("OUT_DIR", &builder.out);
+ cmd.env("CARGO", &builder.initial_cargo);
cmd.run(builder);
dest
diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml
index d0820cfc2a0e4..edf9e5c5393ea 100644
--- a/src/tools/collect-license-metadata/Cargo.toml
+++ b/src/tools/collect-license-metadata/Cargo.toml
@@ -2,6 +2,8 @@
name = "collect-license-metadata"
version = "0.1.0"
edition = "2021"
+description = "Runs the reuse tool and caches the output, so rust toolchain devs don't need to have reuse installed"
+license = "MIT OR Apache-2.0"
[dependencies]
anyhow = "1.0.65"
diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs
index ca6aa01d78c04..dce36bb17b600 100644
--- a/src/tools/collect-license-metadata/src/main.rs
+++ b/src/tools/collect-license-metadata/src/main.rs
@@ -8,6 +8,11 @@ use anyhow::Error;
use crate::licenses::LicensesInterner;
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run collect-license-metadata`
fn main() -> Result<(), Error> {
let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index 899ef0f8a6c26..bf643876a042b 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -2,6 +2,7 @@
name = "generate-copyright"
version = "0.1.0"
edition = "2021"
+description = "Produces a manifest of all the copyrighted materials in the Rust Toolchain"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -9,3 +10,5 @@ edition = "2021"
anyhow = "1.0.65"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
+thiserror = "1"
+tempfile = "3"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
new file mode 100644
index 0000000000000..721a6b1c6e627
--- /dev/null
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -0,0 +1,196 @@
+//! Gets metadata about a workspace from Cargo
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::ffi::{OsStr, OsString};
+use std::path::Path;
+
+/// Describes how this module can fail
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error("Failed to run cargo metadata: {0:?}")]
+ LaunchingMetadata(#[from] std::io::Error),
+ #[error("Failed get output from cargo metadata: {0:?}")]
+ GettingMetadata(String),
+ #[error("Failed parse JSON output from cargo metadata: {0:?}")]
+ ParsingJson(#[from] serde_json::Error),
+ #[error("Failed find expected JSON element {0} in output from cargo metadata")]
+ MissingJsonElement(&'static str),
+ #[error("Failed find expected JSON element {0} in output from cargo metadata for package {1}")]
+ MissingJsonElementForPackage(String, String),
+ #[error("Failed to run cargo vendor: {0:?}")]
+ LaunchingVendor(std::io::Error),
+ #[error("Failed to complete cargo vendor")]
+ RunningVendor,
+}
+
+/// Describes one of our dependencies
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Dependency {
+ /// The name of the package
+ pub name: String,
+ /// The version number
+ pub version: String,
+ /// The license it is under
+ pub license: String,
+ /// The list of authors from the package metadata
+ pub authors: Vec,
+ /// A list of important files from the package, with their contents.
+ ///
+ /// This includes *COPYRIGHT*, *NOTICE*, *AUTHOR*, *LICENSE*, and *LICENCE* files, case-insensitive.
+ pub notices: BTreeMap,
+}
+
+/// Use `cargo` to get a list of dependencies and their license data.
+///
+/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can
+/// grab the license files.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get(
+ cargo: &Path,
+ dest: &Path,
+ root_path: &Path,
+ manifest_paths: &[&Path],
+) -> Result, Error> {
+ let mut temp_set = BTreeSet::new();
+ // Look at the metadata for each manifest
+ for manifest_path in manifest_paths {
+ if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) {
+ panic!("cargo_manifest::get requires a path to a Cargo.toml file");
+ }
+ let metadata_json = get_metadata_json(cargo, manifest_path)?;
+ let packages = metadata_json["packages"]
+ .as_array()
+ .ok_or_else(|| Error::MissingJsonElement("packages array"))?;
+ for package in packages {
+ let package =
+ package.as_object().ok_or_else(|| Error::MissingJsonElement("package object"))?;
+ let manifest_path = package
+ .get("manifest_path")
+ .and_then(|v| v.as_str())
+ .map(Path::new)
+ .ok_or_else(|| Error::MissingJsonElement("package.manifest_path"))?;
+ if manifest_path.starts_with(&root_path) {
+ // it's an in-tree dependency and reuse covers it
+ continue;
+ }
+ // otherwise it's an out-of-tree dependency
+ let get_string = |field_name: &str, package_name: &str| {
+ package.get(field_name).and_then(|v| v.as_str()).ok_or_else(|| {
+ Error::MissingJsonElementForPackage(
+ format!("package.{field_name}"),
+ package_name.to_owned(),
+ )
+ })
+ };
+ let name = get_string("name", "unknown")?;
+ let license = get_string("license", name)?;
+ let version = get_string("version", name)?;
+ let authors_list = package
+ .get("authors")
+ .and_then(|v| v.as_array())
+ .ok_or_else(|| Error::MissingJsonElement("package.authors"))?;
+ let authors: Vec =
+ authors_list.iter().filter_map(|v| v.as_str()).map(|s| s.to_owned()).collect();
+ temp_set.insert(Dependency {
+ name: name.to_owned(),
+ version: version.to_owned(),
+ license: license.to_owned(),
+ authors,
+ notices: BTreeMap::new(),
+ });
+ }
+ }
+
+ // Now do a cargo-vendor and grab everything
+ let vendor_path = dest.join("vendor");
+ println!("Vendoring deps into {}...", vendor_path.display());
+ run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
+
+ // Now for each dependency we found, go and grab any important looking files
+ let mut output = BTreeSet::new();
+ for mut dep in temp_set {
+ load_important_files(&mut dep, &vendor_path)?;
+ output.insert(dep);
+ }
+
+ Ok(output)
+}
+
+/// Get cargo-metdata for a package, as JSON
+fn get_metadata_json(cargo: &Path, manifest_path: &Path) -> Result {
+ let metadata_output = std::process::Command::new(cargo)
+ .arg("metadata")
+ .arg("--format-version=1")
+ .arg("--all-features")
+ .arg("--manifest-path")
+ .arg(manifest_path)
+ .env("RUSTC_BOOTSTRAP", "1")
+ .output()
+ .map_err(|e| Error::LaunchingMetadata(e))?;
+ if !metadata_output.status.success() {
+ return Err(Error::GettingMetadata(
+ String::from_utf8(metadata_output.stderr).expect("UTF-8 output from cargo"),
+ ));
+ }
+ let json = serde_json::from_slice(&metadata_output.stdout)?;
+ Ok(json)
+}
+
+/// Run cargo-vendor, fetching into the given dir
+fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> {
+ let mut vendor_command = std::process::Command::new(cargo);
+ vendor_command.env("RUSTC_BOOTSTRAP", "1");
+ vendor_command.arg("vendor");
+ vendor_command.arg("--quiet");
+ vendor_command.arg("--versioned-dirs");
+ for manifest_path in manifest_paths {
+ vendor_command.arg("-s");
+ vendor_command.arg(manifest_path);
+ }
+ vendor_command.arg(dest);
+
+ let vendor_status = vendor_command.status().map_err(|e| Error::LaunchingVendor(e))?;
+
+ if !vendor_status.success() {
+ return Err(Error::RunningVendor);
+ }
+
+ Ok(())
+}
+
+/// Add important files off disk into this dependency.
+///
+/// Maybe one-day Cargo.toml will contain enough information that we don't need
+/// to do this manual scraping.
+fn load_important_files(dep: &mut Dependency, vendor_root: &Path) -> Result<(), Error> {
+ let name_version = format!("{}-{}", dep.name, dep.version);
+ println!("Scraping notices for {}...", name_version);
+ let dep_vendor_path = vendor_root.join(name_version);
+ for entry in std::fs::read_dir(dep_vendor_path)? {
+ let entry = entry?;
+ let metadata = entry.metadata()?;
+ let path = entry.path();
+ if let Some(filename) = path.file_name() {
+ let lc_filename = filename.to_ascii_lowercase();
+ let lc_filename_str = lc_filename.to_string_lossy();
+ let mut keep = false;
+ for m in ["copyright", "licence", "license", "author", "notice"] {
+ if lc_filename_str.contains(m) {
+ keep = true;
+ break;
+ }
+ }
+ if keep {
+ if metadata.is_dir() {
+ // scoop up whole directory
+ } else if metadata.is_file() {
+ println!("Scraping {}", filename.to_string_lossy());
+ dep.notices.insert(filename.to_owned(), std::fs::read_to_string(path)?);
+ }
+ }
+ }
+ }
+ Ok(())
+}
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index dce1a558697e6..6191cd158bc9b 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,54 +1,114 @@
use std::io::Write;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use anyhow::Error;
+mod cargo_metadata;
+
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run generate-metadata`
fn main() -> Result<(), Error> {
- let dest = env_path("DEST")?;
+ let dest_file = env_path("DEST")?;
+ let out_dir = env_path("OUT_DIR")?;
+ let cargo = env_path("CARGO")?;
let license_metadata = env_path("LICENSE_METADATA")?;
- let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+ let collected_tree_metadata: Metadata =
+ serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+
+ let root_path = std::path::absolute(".")?;
+ let workspace_paths = [
+ Path::new("./Cargo.toml"),
+ Path::new("./src/tools/cargo/Cargo.toml"),
+ Path::new("./library/std/Cargo.toml"),
+ ];
+ let collected_cargo_metadata =
+ cargo_metadata::get(&cargo, &out_dir, &root_path, &workspace_paths)?;
let mut buffer = Vec::new();
- render_recursive(&metadata.files, &mut buffer, 0)?;
- std::fs::write(&dest, &buffer)?;
+ writeln!(buffer, "# COPYRIGHT for Rust")?;
+ writeln!(buffer)?;
+ writeln!(
+ buffer,
+ "This file describes the copyright and licensing information for the source code within The Rust Project git tree, and the third-party dependencies used when building the Rust toolchain (including the Rust Standard Library)"
+ )?;
+ writeln!(buffer)?;
+ writeln!(buffer, "## Table of Contents")?;
+ writeln!(buffer)?;
+ writeln!(buffer, "* [In-tree files](#in-tree-files)")?;
+ writeln!(buffer, "* [Out-of-tree files](#out-of-tree-files)")?;
+ // writeln!(buffer, "* [License Texts](#license-texts)")?;
+ writeln!(buffer)?;
+
+ writeln!(buffer, "## In-tree files")?;
+ writeln!(buffer)?;
+ writeln!(
+ buffer,
+ "The following licenses cover the in-tree source files that were used in this release:"
+ )?;
+ writeln!(buffer)?;
+ render_tree_recursive(&collected_tree_metadata.files, &mut buffer, 0)?;
+
+ writeln!(buffer)?;
+
+ writeln!(buffer, "## Out-of-tree files")?;
+ writeln!(buffer)?;
+ writeln!(
+ buffer,
+ "The following licenses cover the out-of-tree crates that were used in this release:"
+ )?;
+ writeln!(buffer)?;
+ render_deps(collected_cargo_metadata.iter(), &mut buffer)?;
+
+ std::fs::write(&dest_file, &buffer)?;
Ok(())
}
-fn render_recursive(node: &Node, buffer: &mut Vec, depth: usize) -> Result<(), Error> {
+/// Recursively draw the tree of files/folders we found on disk and their licenses, as
+/// markdown, into the given Vec.
+fn render_tree_recursive(node: &Node, buffer: &mut Vec, depth: usize) -> Result<(), Error> {
let prefix = std::iter::repeat("> ").take(depth + 1).collect::();
match node {
Node::Root { children } => {
for child in children {
- render_recursive(child, buffer, depth)?;
+ render_tree_recursive(child, buffer, depth)?;
}
}
Node::Directory { name, children, license } => {
- render_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
+ render_tree_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
if !children.is_empty() {
writeln!(buffer, "{prefix}")?;
writeln!(buffer, "{prefix}*Exceptions:*")?;
for child in children {
writeln!(buffer, "{prefix}")?;
- render_recursive(child, buffer, depth + 1)?;
+ render_tree_recursive(child, buffer, depth + 1)?;
}
}
}
Node::Group { files, directories, license } => {
- render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?;
+ render_tree_license(
+ &prefix,
+ directories.iter().chain(files.iter()),
+ Some(license),
+ buffer,
+ )?;
}
Node::File { name, license } => {
- render_license(&prefix, std::iter::once(name), Some(license), buffer)?;
+ render_tree_license(&prefix, std::iter::once(name), Some(license), buffer)?;
}
}
Ok(())
}
-fn render_license<'a>(
+/// Draw a series of sibling files/folders, as markdown, into the given Vec.
+fn render_tree_license<'a>(
prefix: &str,
names: impl Iterator- ,
license: Option<&License>,
@@ -67,11 +127,47 @@ fn render_license<'a>(
Ok(())
}
+/// Render a list of out-of-tree dependencies as markdown into the given Vec.
+fn render_deps<'a, 'b>(
+ deps: impl Iterator
- ,
+ buffer: &'b mut Vec
,
+) -> Result<(), Error> {
+ for dep in deps {
+ let authors_list = dep.authors.join(", ").replace("<", "\\<").replace(">", "\\>");
+ let url = format!("https://crates.io/crates/{}/{}", dep.name, dep.version);
+ writeln!(buffer)?;
+ writeln!(
+ buffer,
+ "### [{name} {version}]({url})",
+ name = dep.name,
+ version = dep.version,
+ url = url,
+ )?;
+ writeln!(buffer)?;
+ writeln!(buffer, "* Authors: {}", authors_list)?;
+ writeln!(buffer, "* License: {}", dep.license)?;
+ for (name, contents) in &dep.notices {
+ writeln!(buffer)?;
+ writeln!(buffer, "#### {}", name.to_string_lossy())?;
+ writeln!(buffer)?;
+ writeln!(buffer, "Click to expand ")?;
+ writeln!(buffer)?;
+ writeln!(buffer, "```")?;
+ writeln!(buffer, "{}", contents)?;
+ writeln!(buffer, "```")?;
+ writeln!(buffer)?;
+ writeln!(buffer, " ")?;
+ }
+ }
+ Ok(())
+}
+/// Describes a tree of metadata for our filesystem tree
#[derive(serde::Deserialize)]
struct Metadata {
files: Node,
}
+/// Describes one node in our metadata tree
#[derive(serde::Deserialize)]
#[serde(rename_all = "kebab-case", tag = "type")]
pub(crate) enum Node {
@@ -81,12 +177,14 @@ pub(crate) enum Node {
Group { files: Vec, directories: Vec, license: License },
}
+/// A License has an SPDX license name and a list of copyright holders.
#[derive(serde::Deserialize)]
struct License {
spdx: String,
copyright: Vec,
}
+/// Grab an environment variable as a PathBuf, or fail nicely.
fn env_path(var: &str) -> Result {
if let Some(var) = std::env::var_os(var) {
Ok(var.into())
From 204e3eadf1323ebd886ee159b193e231ec4906c9 Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Mon, 29 Jul 2024 11:41:02 +0100
Subject: [PATCH 04/31] generate-copyright: Produce HTML, not Markdown
This format works better with large amounts of structured data.
We also mark which deps are in the stdlib
---
src/bootstrap/src/core/build_steps/run.rs | 2 +-
.../generate-copyright/src/cargo_metadata.rs | 81 +++++----
src/tools/generate-copyright/src/main.rs | 172 ++++++++++--------
3 files changed, 152 insertions(+), 103 deletions(-)
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 29d7bcc425bea..65d635c0bd69f 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -212,7 +212,7 @@ impl Step for GenerateCopyright {
let license_metadata = builder.ensure(CollectLicenseMetadata);
// Temporary location, it will be moved to the proper one once it's accurate.
- let dest = builder.out.join("COPYRIGHT.md");
+ let dest = builder.out.join("COPYRIGHT.html");
let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
cmd.env("LICENSE_METADATA", &license_metadata);
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 721a6b1c6e627..eda53c73c0af6 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -1,6 +1,6 @@
//! Gets metadata about a workspace from Cargo
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeMap;
use std::ffi::{OsStr, OsString};
use std::path::Path;
@@ -23,13 +23,18 @@ pub enum Error {
RunningVendor,
}
-/// Describes one of our dependencies
+/// Uniquely describes a package on crates.io
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Dependency {
+pub struct Package {
/// The name of the package
pub name: String,
/// The version number
pub version: String,
+}
+
+/// Extra data about a package
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PackageMetadata {
/// The license it is under
pub license: String,
/// The list of authors from the package metadata
@@ -40,20 +45,44 @@ pub struct Dependency {
pub notices: BTreeMap,
}
-/// Use `cargo` to get a list of dependencies and their license data.
+/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
///
/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can
/// grab the license files.
///
/// Any dependency with a path beginning with `root_path` is ignored, as we
/// assume `reuse` has covered it already.
-pub fn get(
+pub fn get_metadata_and_notices(
cargo: &Path,
dest: &Path,
root_path: &Path,
manifest_paths: &[&Path],
-) -> Result, Error> {
- let mut temp_set = BTreeSet::new();
+) -> Result, Error> {
+ let mut output = get_metadata(cargo, root_path, manifest_paths)?;
+
+ // Now do a cargo-vendor and grab everything
+ let vendor_path = dest.join("vendor");
+ println!("Vendoring deps into {}...", vendor_path.display());
+ run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
+
+ // Now for each dependency we found, go and grab any important looking files
+ for (package, metadata) in output.iter_mut() {
+ load_important_files(package, metadata, &vendor_path)?;
+ }
+
+ Ok(output)
+}
+
+/// Use `cargo metadata` to get a list of dependencies and their license data.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get_metadata(
+ cargo: &Path,
+ root_path: &Path,
+ manifest_paths: &[&Path],
+) -> Result, Error> {
+ let mut output = BTreeMap::new();
// Look at the metadata for each manifest
for manifest_path in manifest_paths {
if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) {
@@ -71,7 +100,7 @@ pub fn get(
.and_then(|v| v.as_str())
.map(Path::new)
.ok_or_else(|| Error::MissingJsonElement("package.manifest_path"))?;
- if manifest_path.starts_with(&root_path) {
+ if manifest_path.starts_with(root_path) {
// it's an in-tree dependency and reuse covers it
continue;
}
@@ -93,28 +122,14 @@ pub fn get(
.ok_or_else(|| Error::MissingJsonElement("package.authors"))?;
let authors: Vec =
authors_list.iter().filter_map(|v| v.as_str()).map(|s| s.to_owned()).collect();
- temp_set.insert(Dependency {
- name: name.to_owned(),
- version: version.to_owned(),
- license: license.to_owned(),
- authors,
- notices: BTreeMap::new(),
- });
+ let package = Package { name: name.to_owned(), version: version.to_owned() };
+ output.insert(
+ package.clone(),
+ PackageMetadata { license: license.to_owned(), authors, notices: BTreeMap::new() },
+ );
}
}
- // Now do a cargo-vendor and grab everything
- let vendor_path = dest.join("vendor");
- println!("Vendoring deps into {}...", vendor_path.display());
- run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
-
- // Now for each dependency we found, go and grab any important looking files
- let mut output = BTreeSet::new();
- for mut dep in temp_set {
- load_important_files(&mut dep, &vendor_path)?;
- output.insert(dep);
- }
-
Ok(output)
}
@@ -128,7 +143,7 @@ fn get_metadata_json(cargo: &Path, manifest_path: &Path) -> Result Resu
}
vendor_command.arg(dest);
- let vendor_status = vendor_command.status().map_err(|e| Error::LaunchingVendor(e))?;
+ let vendor_status = vendor_command.status().map_err(Error::LaunchingVendor)?;
if !vendor_status.success() {
return Err(Error::RunningVendor);
@@ -164,8 +179,12 @@ fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Resu
///
/// Maybe one-day Cargo.toml will contain enough information that we don't need
/// to do this manual scraping.
-fn load_important_files(dep: &mut Dependency, vendor_root: &Path) -> Result<(), Error> {
- let name_version = format!("{}-{}", dep.name, dep.version);
+fn load_important_files(
+ package: &Package,
+ dep: &mut PackageMetadata,
+ vendor_root: &Path,
+) -> Result<(), Error> {
+ let name_version = format!("{}-{}", package.name, package.version);
println!("Scraping notices for {}...", name_version);
let dep_vendor_path = vendor_root.join(name_version);
for entry in std::fs::read_dir(dep_vendor_path)? {
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 6191cd158bc9b..efccba0651e4d 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeMap;
use std::io::Write;
use std::path::{Path, PathBuf};
@@ -5,6 +6,33 @@ use anyhow::Error;
mod cargo_metadata;
+static TOP_BOILERPLATE: &str = r##"
+
+
+
+
+ Copyright notices for The Rust Toolchain
+
+
+
+Copyright notices for The Rust Toolchain
+
+This file describes the copyright and licensing information for the source
+code within The Rust Project git tree, and the third-party dependencies used
+when building the Rust toolchain (including the Rust Standard Library).
+
+Table of Contents
+
+"##;
+
+static BOTTOM_BOILERPLATE: &str = r#"
+
+
+"#;
+
/// The entry point to the binary.
///
/// You should probably let `bootstrap` execute this program instead of running it directly.
@@ -26,43 +54,28 @@ fn main() -> Result<(), Error> {
Path::new("./library/std/Cargo.toml"),
];
let collected_cargo_metadata =
- cargo_metadata::get(&cargo, &out_dir, &root_path, &workspace_paths)?;
+ cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
+
+ let stdlib_set =
+ cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
let mut buffer = Vec::new();
- writeln!(buffer, "# COPYRIGHT for Rust")?;
- writeln!(buffer)?;
- writeln!(
- buffer,
- "This file describes the copyright and licensing information for the source code within The Rust Project git tree, and the third-party dependencies used when building the Rust toolchain (including the Rust Standard Library)"
- )?;
- writeln!(buffer)?;
- writeln!(buffer, "## Table of Contents")?;
- writeln!(buffer)?;
- writeln!(buffer, "* [In-tree files](#in-tree-files)")?;
- writeln!(buffer, "* [Out-of-tree files](#out-of-tree-files)")?;
- // writeln!(buffer, "* [License Texts](#license-texts)")?;
- writeln!(buffer)?;
-
- writeln!(buffer, "## In-tree files")?;
- writeln!(buffer)?;
+ writeln!(buffer, "{}", TOP_BOILERPLATE)?;
+
writeln!(
buffer,
- "The following licenses cover the in-tree source files that were used in this release:"
+ r#"In-tree files The following licenses cover the in-tree source files that were used in this release:
"#
)?;
- writeln!(buffer)?;
- render_tree_recursive(&collected_tree_metadata.files, &mut buffer, 0)?;
-
- writeln!(buffer)?;
+ render_tree_recursive(&collected_tree_metadata.files, &mut buffer)?;
- writeln!(buffer, "## Out-of-tree files")?;
- writeln!(buffer)?;
writeln!(
buffer,
- "The following licenses cover the out-of-tree crates that were used in this release:"
+ r#"Out-of-tree dependencies The following licenses cover the out-of-tree crates that were used in this release:
"#
)?;
- writeln!(buffer)?;
- render_deps(collected_cargo_metadata.iter(), &mut buffer)?;
+ render_deps(&collected_cargo_metadata, &stdlib_set, &mut buffer)?;
+
+ writeln!(buffer, "{}", BOTTOM_BOILERPLATE)?;
std::fs::write(&dest_file, &buffer)?;
@@ -71,56 +84,51 @@ fn main() -> Result<(), Error> {
/// Recursively draw the tree of files/folders we found on disk and their licenses, as
/// markdown, into the given Vec.
-fn render_tree_recursive(node: &Node, buffer: &mut Vec, depth: usize) -> Result<(), Error> {
- let prefix = std::iter::repeat("> ").take(depth + 1).collect::();
-
+fn render_tree_recursive(node: &Node, buffer: &mut Vec) -> Result<(), Error> {
+ writeln!(buffer, r#""#)?;
match node {
Node::Root { children } => {
for child in children {
- render_tree_recursive(child, buffer, depth)?;
+ render_tree_recursive(child, buffer)?;
}
}
Node::Directory { name, children, license } => {
- render_tree_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
+ render_tree_license(std::iter::once(name), license.as_ref(), buffer)?;
if !children.is_empty() {
- writeln!(buffer, "{prefix}")?;
- writeln!(buffer, "{prefix}*Exceptions:*")?;
+ writeln!(buffer, "
Exceptions:
")?;
for child in children {
- writeln!(buffer, "{prefix}")?;
- render_tree_recursive(child, buffer, depth + 1)?;
+ render_tree_recursive(child, buffer)?;
}
}
}
Node::Group { files, directories, license } => {
- render_tree_license(
- &prefix,
- directories.iter().chain(files.iter()),
- Some(license),
- buffer,
- )?;
+ render_tree_license(directories.iter().chain(files.iter()), Some(license), buffer)?;
}
Node::File { name, license } => {
- render_tree_license(&prefix, std::iter::once(name), Some(license), buffer)?;
+ render_tree_license(std::iter::once(name), Some(license), buffer)?;
}
}
+ writeln!(buffer, "
")?;
Ok(())
}
/// Draw a series of sibling files/folders, as markdown, into the given Vec.
fn render_tree_license<'a>(
- prefix: &str,
names: impl Iterator- ,
license: Option<&License>,
buffer: &mut Vec
,
) -> Result<(), Error> {
+ writeln!(buffer, "File/Directory: ")?;
for name in names {
- writeln!(buffer, "{prefix}**`{name}`** ")?;
+ writeln!(buffer, "{name}
")?;
}
+ writeln!(buffer, "
")?;
+
if let Some(license) = license {
- writeln!(buffer, "{prefix}License: `{}`", license.spdx)?;
+ writeln!(buffer, "License: {}
", license.spdx)?;
for copyright in license.copyright.iter() {
- writeln!(buffer, "{prefix}Copyright: {copyright}")?;
+ writeln!(buffer, "Copyright: {copyright}
")?;
}
}
@@ -128,36 +136,48 @@ fn render_tree_license<'a>(
}
/// Render a list of out-of-tree dependencies as markdown into the given Vec.
-fn render_deps<'a, 'b>(
- deps: impl Iterator- ,
- buffer: &'b mut Vec
,
+fn render_deps(
+ all_deps: &BTreeMap,
+ stdlib_set: &BTreeMap,
+ buffer: &mut Vec,
) -> Result<(), Error> {
- for dep in deps {
- let authors_list = dep.authors.join(", ").replace("<", "\\<").replace(">", "\\>");
- let url = format!("https://crates.io/crates/{}/{}", dep.name, dep.version);
+ for (package, metadata) in all_deps {
+ let authors_list = if metadata.authors.is_empty() {
+ "None Specified".to_owned()
+ } else {
+ metadata.authors.join(", ")
+ };
+ let url = format!("https://crates.io/crates/{}/{}", package.name, package.version);
writeln!(buffer)?;
writeln!(
buffer,
- "### [{name} {version}]({url})",
- name = dep.name,
- version = dep.version,
- url = url,
+ r#"📦 {name}-{version} "#,
+ name = package.name,
+ version = package.version,
)?;
- writeln!(buffer)?;
- writeln!(buffer, "* Authors: {}", authors_list)?;
- writeln!(buffer, "* License: {}", dep.license)?;
- for (name, contents) in &dep.notices {
- writeln!(buffer)?;
- writeln!(buffer, "#### {}", name.to_string_lossy())?;
- writeln!(buffer)?;
- writeln!(buffer, "Click to expand ")?;
- writeln!(buffer)?;
- writeln!(buffer, "```")?;
- writeln!(buffer, "{}", contents)?;
- writeln!(buffer, "```")?;
- writeln!(buffer)?;
- writeln!(buffer, " ")?;
+ writeln!(buffer, r#"URL: {url}
"#,)?;
+ writeln!(
+ buffer,
+ "In libstd: {}
",
+ if stdlib_set.contains_key(package) { "Yes" } else { "No" }
+ )?;
+ writeln!(buffer, "Authors: {}
", escape_html(&authors_list))?;
+ writeln!(buffer, "License: {}
", escape_html(&metadata.license))?;
+ writeln!(buffer, "Notices: ")?;
+ if metadata.notices.is_empty() {
+ writeln!(buffer, "None")?;
+ } else {
+ for (name, contents) in &metadata.notices {
+ writeln!(
+ buffer,
+ "{}
",
+ name.to_string_lossy()
+ )?;
+ writeln!(buffer, "\n{}\n ", contents)?;
+ writeln!(buffer, " ")?;
+ }
}
+ writeln!(buffer, "
")?;
}
Ok(())
}
@@ -192,3 +212,13 @@ fn env_path(var: &str) -> Result {
anyhow::bail!("missing environment variable {var}")
}
}
+
+/// Escapes any invalid HTML characters
+fn escape_html(input: &str) -> String {
+ static MAPPING: [(char, &str); 3] = [('&', "&"), ('<', "<"), ('>', ">")];
+ let mut output = input.to_owned();
+ for (ch, s) in &MAPPING {
+ output = output.replace(*ch, s);
+ }
+ output
+}
From 56f84796a4e819be108721f723d8c1b229e5dbdd Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 30 Jul 2024 13:54:48 +0100
Subject: [PATCH 05/31] generate-copyright: Fix typo
---
src/tools/generate-copyright/src/main.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index efccba0651e4d..af69ab8c8bf36 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -37,7 +37,7 @@ static BOTTOM_BOILERPLATE: &str = r#"
///
/// You should probably let `bootstrap` execute this program instead of running it directly.
///
-/// Run `x.py run generate-metadata`
+/// Run `x.py run generate-copyright`
fn main() -> Result<(), Error> {
let dest_file = env_path("DEST")?;
let out_dir = env_path("OUT_DIR")?;
From dbab595d78f12c0514cfe2ac4c7c9d083445c14f Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 30 Jul 2024 13:56:17 +0100
Subject: [PATCH 06/31] generate-copyright: use cargo-metadata
---
Cargo.lock | 1 +
src/tools/generate-copyright/Cargo.toml | 1 +
.../generate-copyright/src/cargo_metadata.rs | 80 +++++--------------
3 files changed, 20 insertions(+), 62 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0f3a106512d20..eeaeff79ebb25 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1406,6 +1406,7 @@ name = "generate-copyright"
version = "0.1.0"
dependencies = [
"anyhow",
+ "cargo_metadata 0.18.1",
"serde",
"serde_json",
"tempfile",
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index bf643876a042b..c94cc35fb5036 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -12,3 +12,4 @@ serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
thiserror = "1"
tempfile = "3"
+cargo_metadata = "0.18.1"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index eda53c73c0af6..655d73715e036 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -7,16 +7,10 @@ use std::path::Path;
/// Describes how this module can fail
#[derive(Debug, thiserror::Error)]
pub enum Error {
- #[error("Failed to run cargo metadata: {0:?}")]
- LaunchingMetadata(#[from] std::io::Error),
- #[error("Failed get output from cargo metadata: {0:?}")]
- GettingMetadata(String),
- #[error("Failed parse JSON output from cargo metadata: {0:?}")]
- ParsingJson(#[from] serde_json::Error),
- #[error("Failed find expected JSON element {0} in output from cargo metadata")]
- MissingJsonElement(&'static str),
- #[error("Failed find expected JSON element {0} in output from cargo metadata for package {1}")]
- MissingJsonElementForPackage(String, String),
+ #[error("I/O Error: {0:?}")]
+ Io(#[from] std::io::Error),
+ #[error("Failed get output from cargo-metadata: {0:?}")]
+ GettingMetadata(#[from] cargo_metadata::Error),
#[error("Failed to run cargo vendor: {0:?}")]
LaunchingVendor(std::io::Error),
#[error("Failed to complete cargo vendor")]
@@ -88,44 +82,26 @@ pub fn get_metadata(
if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) {
panic!("cargo_manifest::get requires a path to a Cargo.toml file");
}
- let metadata_json = get_metadata_json(cargo, manifest_path)?;
- let packages = metadata_json["packages"]
- .as_array()
- .ok_or_else(|| Error::MissingJsonElement("packages array"))?;
- for package in packages {
- let package =
- package.as_object().ok_or_else(|| Error::MissingJsonElement("package object"))?;
- let manifest_path = package
- .get("manifest_path")
- .and_then(|v| v.as_str())
- .map(Path::new)
- .ok_or_else(|| Error::MissingJsonElement("package.manifest_path"))?;
+ let metadata = cargo_metadata::MetadataCommand::new()
+ .cargo_path(cargo)
+ .env("RUSTC_BOOTSTRAP", "1")
+ .manifest_path(manifest_path)
+ .exec()?;
+ for package in metadata.packages {
+ let manifest_path = package.manifest_path.as_path();
if manifest_path.starts_with(root_path) {
// it's an in-tree dependency and reuse covers it
continue;
}
// otherwise it's an out-of-tree dependency
- let get_string = |field_name: &str, package_name: &str| {
- package.get(field_name).and_then(|v| v.as_str()).ok_or_else(|| {
- Error::MissingJsonElementForPackage(
- format!("package.{field_name}"),
- package_name.to_owned(),
- )
- })
- };
- let name = get_string("name", "unknown")?;
- let license = get_string("license", name)?;
- let version = get_string("version", name)?;
- let authors_list = package
- .get("authors")
- .and_then(|v| v.as_array())
- .ok_or_else(|| Error::MissingJsonElement("package.authors"))?;
- let authors: Vec =
- authors_list.iter().filter_map(|v| v.as_str()).map(|s| s.to_owned()).collect();
- let package = Package { name: name.to_owned(), version: version.to_owned() };
+ let package_id = Package { name: package.name, version: package.version.to_string() };
output.insert(
- package.clone(),
- PackageMetadata { license: license.to_owned(), authors, notices: BTreeMap::new() },
+ package_id,
+ PackageMetadata {
+ license: package.license.unwrap_or_else(|| String::from("Unspecified")),
+ authors: package.authors,
+ notices: BTreeMap::new(),
+ },
);
}
}
@@ -133,26 +109,6 @@ pub fn get_metadata(
Ok(output)
}
-/// Get cargo-metdata for a package, as JSON
-fn get_metadata_json(cargo: &Path, manifest_path: &Path) -> Result {
- let metadata_output = std::process::Command::new(cargo)
- .arg("metadata")
- .arg("--format-version=1")
- .arg("--all-features")
- .arg("--manifest-path")
- .arg(manifest_path)
- .env("RUSTC_BOOTSTRAP", "1")
- .output()
- .map_err(Error::LaunchingMetadata)?;
- if !metadata_output.status.success() {
- return Err(Error::GettingMetadata(
- String::from_utf8(metadata_output.stderr).expect("UTF-8 output from cargo"),
- ));
- }
- let json = serde_json::from_slice(&metadata_output.stdout)?;
- Ok(json)
-}
-
/// Run cargo-vendor, fetching into the given dir
fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> {
let mut vendor_command = std::process::Command::new(cargo);
From f7e6bf61a9c3492115d19dc112071adea90a7038 Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 30 Jul 2024 19:39:06 +0100
Subject: [PATCH 07/31] generate-copyright: use rinja to format the output
I can't find a way to derive rinja::Template for Node - I think because it is a recursive type. So I rendered it manually using html_escape.
---
src/tools/generate-copyright/Cargo.toml | 6 +-
.../generate-copyright/src/cargo_metadata.rs | 12 +-
src/tools/generate-copyright/src/main.rs | 226 +++++++-----------
.../templates/COPYRIGHT.html | 54 +++++
4 files changed, 146 insertions(+), 152 deletions(-)
create mode 100644 src/tools/generate-copyright/templates/COPYRIGHT.html
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index c94cc35fb5036..c00292cf33108 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -8,8 +8,10 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
[dependencies]
anyhow = "1.0.65"
+cargo_metadata = "0.18.1"
+html-escape = "0.2.13"
+rinja = "0.2.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
-thiserror = "1"
tempfile = "3"
-cargo_metadata = "0.18.1"
+thiserror = "1"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 655d73715e036..d02b9eeb6f922 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -1,7 +1,7 @@
//! Gets metadata about a workspace from Cargo
use std::collections::BTreeMap;
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsStr;
use std::path::Path;
/// Describes how this module can fail
@@ -36,7 +36,9 @@ pub struct PackageMetadata {
/// A list of important files from the package, with their contents.
///
/// This includes *COPYRIGHT*, *NOTICE*, *AUTHOR*, *LICENSE*, and *LICENCE* files, case-insensitive.
- pub notices: BTreeMap,
+ pub notices: BTreeMap,
+ /// If this is true, this dep is in the Rust Standard Library
+ pub is_in_libstd: Option,
}
/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
@@ -101,6 +103,7 @@ pub fn get_metadata(
license: package.license.unwrap_or_else(|| String::from("Unspecified")),
authors: package.authors,
notices: BTreeMap::new(),
+ is_in_libstd: None,
},
);
}
@@ -161,8 +164,9 @@ fn load_important_files(
if metadata.is_dir() {
// scoop up whole directory
} else if metadata.is_file() {
- println!("Scraping {}", filename.to_string_lossy());
- dep.notices.insert(filename.to_owned(), std::fs::read_to_string(path)?);
+ let filename = filename.to_string_lossy();
+ println!("Scraping {}", filename);
+ dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?);
}
}
}
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index af69ab8c8bf36..03b789b739298 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,37 +1,17 @@
use std::collections::BTreeMap;
-use std::io::Write;
use std::path::{Path, PathBuf};
use anyhow::Error;
+use rinja::Template;
mod cargo_metadata;
-static TOP_BOILERPLATE: &str = r##"
-
-
-
-
- Copyright notices for The Rust Toolchain
-
-
-
-Copyright notices for The Rust Toolchain
-
-This file describes the copyright and licensing information for the source
-code within The Rust Project git tree, and the third-party dependencies used
-when building the Rust toolchain (including the Rust Standard Library).
-
-Table of Contents
-
-"##;
-
-static BOTTOM_BOILERPLATE: &str = r#"
-
-
-"#;
+#[derive(Template)]
+#[template(path = "COPYRIGHT.html")]
+struct CopyrightTemplate {
+ in_tree: Node,
+ dependencies: BTreeMap,
+}
/// The entry point to the binary.
///
@@ -53,150 +33,114 @@ fn main() -> Result<(), Error> {
Path::new("./src/tools/cargo/Cargo.toml"),
Path::new("./library/std/Cargo.toml"),
];
- let collected_cargo_metadata =
+ let mut collected_cargo_metadata =
cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
let stdlib_set =
cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
- let mut buffer = Vec::new();
+ for (key, value) in collected_cargo_metadata.iter_mut() {
+ value.is_in_libstd = Some(stdlib_set.contains_key(key));
+ }
- writeln!(buffer, "{}", TOP_BOILERPLATE)?;
+ let template = CopyrightTemplate {
+ in_tree: collected_tree_metadata.files,
+ dependencies: collected_cargo_metadata,
+ };
- writeln!(
- buffer,
- r#"In-tree files The following licenses cover the in-tree source files that were used in this release:
"#
- )?;
- render_tree_recursive(&collected_tree_metadata.files, &mut buffer)?;
+ let output = template.render()?;
- writeln!(
- buffer,
- r#"Out-of-tree dependencies The following licenses cover the out-of-tree crates that were used in this release:
"#
- )?;
- render_deps(&collected_cargo_metadata, &stdlib_set, &mut buffer)?;
+ std::fs::write(&dest_file, output)?;
- writeln!(buffer, "{}", BOTTOM_BOILERPLATE)?;
+ Ok(())
+}
- std::fs::write(&dest_file, &buffer)?;
+/// Describes a tree of metadata for our filesystem tree
+#[derive(serde::Deserialize)]
+struct Metadata {
+ files: Node,
+}
+/// Describes one node in our metadata tree
+#[derive(serde::Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+pub(crate) enum Node {
+ Root { children: Vec },
+ Directory { name: String, children: Vec, license: Option },
+ File { name: String, license: License },
+ Group { files: Vec, directories: Vec, license: License },
+}
+
+fn with_box(fmt: &mut std::fmt::Formatter<'_>, inner: F) -> std::fmt::Result
+where
+ F: FnOnce(&mut std::fmt::Formatter<'_>) -> std::fmt::Result,
+{
+ writeln!(fmt, r#""#)?;
+ inner(fmt)?;
+ writeln!(fmt, "
")?;
Ok(())
}
-/// Recursively draw the tree of files/folders we found on disk and their licenses, as
-/// markdown, into the given Vec.
-fn render_tree_recursive(node: &Node, buffer: &mut Vec) -> Result<(), Error> {
- writeln!(buffer, r#""#)?;
- match node {
- Node::Root { children } => {
- for child in children {
- render_tree_recursive(child, buffer)?;
+impl std::fmt::Display for Node {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Node::Root { children } => {
+ if children.len() > 1 {
+ with_box(fmt, |f| {
+ for child in children {
+ writeln!(f, "{child}")?;
+ }
+ Ok(())
+ })
+ } else {
+ for child in children {
+ writeln!(fmt, "{child}")?;
+ }
+ Ok(())
+ }
}
- }
- Node::Directory { name, children, license } => {
- render_tree_license(std::iter::once(name), license.as_ref(), buffer)?;
- if !children.is_empty() {
- writeln!(buffer, "
Exceptions:
")?;
- for child in children {
- render_tree_recursive(child, buffer)?;
+ Node::Directory { name, children, license } => with_box(fmt, |f| {
+ render_tree_license(std::iter::once(name), license.as_ref(), f)?;
+ if !children.is_empty() {
+ writeln!(f, "
Exceptions:
")?;
+ for child in children {
+ writeln!(f, "{child}")?;
+ }
}
+ Ok(())
+ }),
+ Node::Group { files, directories, license } => with_box(fmt, |f| {
+ render_tree_license(directories.iter().chain(files.iter()), Some(license), f)
+ }),
+ Node::File { name, license } => {
+ with_box(fmt, |f| render_tree_license(std::iter::once(name), Some(license), f))
}
}
- Node::Group { files, directories, license } => {
- render_tree_license(directories.iter().chain(files.iter()), Some(license), buffer)?;
- }
- Node::File { name, license } => {
- render_tree_license(std::iter::once(name), Some(license), buffer)?;
- }
}
- writeln!(buffer, "
")?;
-
- Ok(())
}
-/// Draw a series of sibling files/folders, as markdown, into the given Vec.
+/// Draw a series of sibling files/folders, as HTML, into the given formatter.
fn render_tree_license<'a>(
names: impl Iterator- ,
license: Option<&License>,
- buffer: &mut Vec
,
-) -> Result<(), Error> {
- writeln!(buffer, "File/Directory: ")?;
+ f: &mut std::fmt::Formatter<'_>,
+) -> std::fmt::Result {
+ writeln!(f, "
File/Directory: ")?;
for name in names {
- writeln!(buffer, "{name}
")?;
+ writeln!(f, "{}
", html_escape::encode_text(&name))?;
}
- writeln!(buffer, "
")?;
+ writeln!(f, "
")?;
if let Some(license) = license {
- writeln!(buffer, "License: {}
", license.spdx)?;
+ writeln!(f, "License: {}
", html_escape::encode_text(&license.spdx))?;
for copyright in license.copyright.iter() {
- writeln!(buffer, "Copyright: {copyright}
")?;
+ writeln!(f, "Copyright: {}
", html_escape::encode_text(©right))?;
}
}
Ok(())
}
-/// Render a list of out-of-tree dependencies as markdown into the given Vec.
-fn render_deps(
- all_deps: &BTreeMap,
- stdlib_set: &BTreeMap,
- buffer: &mut Vec,
-) -> Result<(), Error> {
- for (package, metadata) in all_deps {
- let authors_list = if metadata.authors.is_empty() {
- "None Specified".to_owned()
- } else {
- metadata.authors.join(", ")
- };
- let url = format!("https://crates.io/crates/{}/{}", package.name, package.version);
- writeln!(buffer)?;
- writeln!(
- buffer,
- r#"📦 {name}-{version} "#,
- name = package.name,
- version = package.version,
- )?;
- writeln!(buffer, r#"URL: {url}
"#,)?;
- writeln!(
- buffer,
- "In libstd: {}
",
- if stdlib_set.contains_key(package) { "Yes" } else { "No" }
- )?;
- writeln!(buffer, "Authors: {}
", escape_html(&authors_list))?;
- writeln!(buffer, "License: {}
", escape_html(&metadata.license))?;
- writeln!(buffer, "Notices: ")?;
- if metadata.notices.is_empty() {
- writeln!(buffer, "None")?;
- } else {
- for (name, contents) in &metadata.notices {
- writeln!(
- buffer,
- "{}
",
- name.to_string_lossy()
- )?;
- writeln!(buffer, "\n{}\n ", contents)?;
- writeln!(buffer, " ")?;
- }
- }
- writeln!(buffer, "
")?;
- }
- Ok(())
-}
-/// Describes a tree of metadata for our filesystem tree
-#[derive(serde::Deserialize)]
-struct Metadata {
- files: Node,
-}
-
-/// Describes one node in our metadata tree
-#[derive(serde::Deserialize)]
-#[serde(rename_all = "kebab-case", tag = "type")]
-pub(crate) enum Node {
- Root { children: Vec },
- Directory { name: String, children: Vec, license: Option },
- File { name: String, license: License },
- Group { files: Vec, directories: Vec, license: License },
-}
-
/// A License has an SPDX license name and a list of copyright holders.
#[derive(serde::Deserialize)]
struct License {
@@ -212,13 +156,3 @@ fn env_path(var: &str) -> Result {
anyhow::bail!("missing environment variable {var}")
}
}
-
-/// Escapes any invalid HTML characters
-fn escape_html(input: &str) -> String {
- static MAPPING: [(char, &str); 3] = [('&', "&"), ('<', "<"), ('>', ">")];
- let mut output = input.to_owned();
- for (ch, s) in &MAPPING {
- output = output.replace(*ch, s);
- }
- output
-}
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT.html b/src/tools/generate-copyright/templates/COPYRIGHT.html
new file mode 100644
index 0000000000000..ccb177a54d419
--- /dev/null
+++ b/src/tools/generate-copyright/templates/COPYRIGHT.html
@@ -0,0 +1,54 @@
+
+
+
+
+ Copyright notices for The Rust Toolchain
+
+
+
+Copyright notices for The Rust Toolchain
+
+This file describes the copyright and licensing information for the source
+code within The Rust Project git tree, and the third-party dependencies used
+when building the Rust toolchain (including the Rust Standard Library).
+
+Table of Contents
+
+
+In-tree files
+
+The following licenses cover the in-tree source files that were used in this
+release:
+
+{{ in_tree|safe }}
+
+Out-of-tree dependencies
+
+The following licenses cover the out-of-tree crates that were used in this
+release:
+
+{% for (key, value) in dependencies %}
+ 📦 {{key.name}}-{{key.version}}
+ URL: https://crates.io/crates/{{ key.name }}/{{ key.version }}
+ In libstd: {% if value.is_in_libstd.unwrap() %} Yes {% else %} No {% endif %}
+ Authors: {{ value.authors|join(", ") }}
+ License: {{ value.license }}
+ {% let len = value.notices.len() %}
+ {% if len > 0 %}
+ Notices:
+ {% for (notice_name, notice_text) in value.notices %}
+
+ {{ notice_name }}
+
+{{ notice_text }}
+
+
+ {% endfor %}
+
+ {% endif %}
+{% endfor %}
+
+
\ No newline at end of file
From 37ab09010cb627df6b3ffb2d4e95c2cacaf93efb Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 30 Jul 2024 19:39:38 +0100
Subject: [PATCH 08/31] REUSE.toml: Copyright text isn't parsed as Markdown.
---
REUSE.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/REUSE.toml b/REUSE.toml
index 1a30d8016c9ea..efd705552478d 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -163,7 +163,7 @@ SPDX-License-Identifier = "MIT OR Apache-2.0"
path = "src/llvm-project/**"
precedence = "override"
SPDX-FileCopyrightText = [
- "2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)",
+ "2003-2019 by the contributors listed in CREDITS.TXT (https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)",
"2010 Apple Inc",
"2003-2019 University of Illinois at Urbana-Champaign.",
]
From 30ac7c9a817793a86d870eeab5a8238acb29b186 Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Wed, 31 Jul 2024 19:26:44 +0100
Subject: [PATCH 09/31] generate-copyright: Render Node with rinja too.
---
Cargo.lock | 46 +++++++++++-
src/tools/generate-copyright/Cargo.toml | 2 -
src/tools/generate-copyright/src/main.rs | 73 +------------------
.../generate-copyright/templates/Node.html | 71 ++++++++++++++++++
4 files changed, 115 insertions(+), 77 deletions(-)
create mode 100644 src/tools/generate-copyright/templates/Node.html
diff --git a/Cargo.lock b/Cargo.lock
index eeaeff79ebb25..54454e84b5a97 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1407,9 +1407,9 @@ version = "0.1.0"
dependencies = [
"anyhow",
"cargo_metadata 0.18.1",
+ "rinja 0.2.0",
"serde",
"serde_json",
- "tempfile",
"thiserror",
]
@@ -3100,6 +3100,18 @@ dependencies = [
"walkdir",
]
+[[package]]
+name = "rinja"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d47a46d7729e891c8accf260e9daa02ae6d570aa2a94fb1fb27eb5364a2323"
+dependencies = [
+ "humansize",
+ "num-traits",
+ "percent-encoding",
+ "rinja_derive 0.2.0",
+]
+
[[package]]
name = "rinja"
version = "0.3.0"
@@ -3107,7 +3119,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd"
dependencies = [
"itoa",
- "rinja_derive",
+ "rinja_derive 0.3.0",
+]
+
+[[package]]
+name = "rinja_derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44dae9afe59d58ed8d988d67d1945f3638125d2fd2104058399382e11bd3ea2a"
+dependencies = [
+ "basic-toml",
+ "mime",
+ "mime_guess",
+ "once_map",
+ "proc-macro2",
+ "quote",
+ "rinja_parser 0.2.0",
+ "serde",
+ "syn 2.0.67",
]
[[package]]
@@ -3123,11 +3152,20 @@ dependencies = [
"once_map",
"proc-macro2",
"quote",
- "rinja_parser",
+ "rinja_parser 0.3.0",
"serde",
"syn 2.0.67",
]
+[[package]]
+name = "rinja_parser"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1771c78cd5d3b1646ef8d8f2ed100db936e8b291d3cc06e92a339ff346858c"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "rinja_parser"
version = "0.3.0"
@@ -4606,7 +4644,7 @@ dependencies = [
"minifier",
"pulldown-cmark 0.9.6",
"regex",
- "rinja",
+ "rinja 0.3.0",
"rustdoc-json-types",
"serde",
"serde_json",
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index c00292cf33108..d200e2ec9f1e1 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -9,9 +9,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
[dependencies]
anyhow = "1.0.65"
cargo_metadata = "0.18.1"
-html-escape = "0.2.13"
rinja = "0.2.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
-tempfile = "3"
thiserror = "1"
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 03b789b739298..37de24648d56d 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -62,8 +62,9 @@ struct Metadata {
}
/// Describes one node in our metadata tree
-#[derive(serde::Deserialize)]
+#[derive(serde::Deserialize, rinja::Template)]
#[serde(rename_all = "kebab-case", tag = "type")]
+#[template(path = "Node.html")]
pub(crate) enum Node {
Root { children: Vec },
Directory { name: String, children: Vec, license: Option },
@@ -71,76 +72,6 @@ pub(crate) enum Node {
Group { files: Vec, directories: Vec, license: License },
}
-fn with_box(fmt: &mut std::fmt::Formatter<'_>, inner: F) -> std::fmt::Result
-where
- F: FnOnce(&mut std::fmt::Formatter<'_>) -> std::fmt::Result,
-{
- writeln!(fmt, r#""#)?;
- inner(fmt)?;
- writeln!(fmt, "
")?;
- Ok(())
-}
-
-impl std::fmt::Display for Node {
- fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Node::Root { children } => {
- if children.len() > 1 {
- with_box(fmt, |f| {
- for child in children {
- writeln!(f, "{child}")?;
- }
- Ok(())
- })
- } else {
- for child in children {
- writeln!(fmt, "{child}")?;
- }
- Ok(())
- }
- }
- Node::Directory { name, children, license } => with_box(fmt, |f| {
- render_tree_license(std::iter::once(name), license.as_ref(), f)?;
- if !children.is_empty() {
- writeln!(f, "Exceptions:
")?;
- for child in children {
- writeln!(f, "{child}")?;
- }
- }
- Ok(())
- }),
- Node::Group { files, directories, license } => with_box(fmt, |f| {
- render_tree_license(directories.iter().chain(files.iter()), Some(license), f)
- }),
- Node::File { name, license } => {
- with_box(fmt, |f| render_tree_license(std::iter::once(name), Some(license), f))
- }
- }
- }
-}
-
-/// Draw a series of sibling files/folders, as HTML, into the given formatter.
-fn render_tree_license<'a>(
- names: impl Iterator- ,
- license: Option<&License>,
- f: &mut std::fmt::Formatter<'_>,
-) -> std::fmt::Result {
- writeln!(f, "
File/Directory: ")?;
- for name in names {
- writeln!(f, "{}
", html_escape::encode_text(&name))?;
- }
- writeln!(f, "
")?;
-
- if let Some(license) = license {
- writeln!(f, "License: {}
", html_escape::encode_text(&license.spdx))?;
- for copyright in license.copyright.iter() {
- writeln!(f, "Copyright: {}
", html_escape::encode_text(©right))?;
- }
- }
-
- Ok(())
-}
-
/// A License has an SPDX license name and a list of copyright holders.
#[derive(serde::Deserialize)]
struct License {
diff --git a/src/tools/generate-copyright/templates/Node.html b/src/tools/generate-copyright/templates/Node.html
new file mode 100644
index 0000000000000..a71a1bf3b73d7
--- /dev/null
+++ b/src/tools/generate-copyright/templates/Node.html
@@ -0,0 +1,71 @@
+{% match self %}
+
+{% when Node::Root { children } %}
+
+{% for child in children %}
+{{ child|safe }}
+{% endfor %}
+
+{% when Node::Directory { name, children, license } %}
+
+
+
+
+ File/Directory: {{ name }}
+
+
+ {% if let Some(license) = license %}
+
+
License: {{ license.spdx }}
+ {% for copyright in license.copyright.iter() %}
+
Copyright: {{ copyright }}
+ {% endfor %}
+
+ {% endif %}
+
+ {% if !children.is_empty() %}
+
+
Exceptions:
+ {% for child in children %}
+ {{ child|safe }}
+ {% endfor %}
+
+ {% endif %}
+
+
+
+{% when Node::File { name, license } %}
+
+
+
+ File/Directory: {{ name }}
+
+
+
License: {{ license.spdx }}
+ {% for copyright in license.copyright.iter() %}
+
Copyright: {{ copyright }}
+ {% endfor %}
+
+
+{% when Node::Group { files, directories, license } %}
+
+
+
+
+ File/Directory:
+ {% for name in files %}
+ {{ name }}
+ {% endfor %}
+ {% for name in directories %}
+ {{ name }}
+ {% endfor %}
+
+
+
License: {{ license.spdx }}
+ {% for copyright in license.copyright.iter() %}
+
Copyright: {{ copyright }}
+ {% endfor %}
+
+
+
+{% endmatch %}
From 5277b67b6977e3fcef64b0ce21cecd3a5dc9c22a Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 6 Aug 2024 11:02:11 +0100
Subject: [PATCH 10/31] generate-copyright: gather files inside interesting
folders
---
.../generate-copyright/src/cargo_metadata.rs | 50 ++++++++++++-------
1 file changed, 33 insertions(+), 17 deletions(-)
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index d02b9eeb6f922..c85e4aa371a2a 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -2,7 +2,7 @@
use std::collections::BTreeMap;
use std::ffi::OsStr;
-use std::path::Path;
+use std::path::{Path, PathBuf};
/// Describes how this module can fail
#[derive(Debug, thiserror::Error)]
@@ -15,6 +15,8 @@ pub enum Error {
LaunchingVendor(std::io::Error),
#[error("Failed to complete cargo vendor")]
RunningVendor,
+ #[error("Bad path {0:?} whilst scraping files")]
+ Scraping(PathBuf),
}
/// Uniquely describes a package on crates.io
@@ -150,24 +152,38 @@ fn load_important_files(
let entry = entry?;
let metadata = entry.metadata()?;
let path = entry.path();
- if let Some(filename) = path.file_name() {
- let lc_filename = filename.to_ascii_lowercase();
- let lc_filename_str = lc_filename.to_string_lossy();
- let mut keep = false;
- for m in ["copyright", "licence", "license", "author", "notice"] {
- if lc_filename_str.contains(m) {
- keep = true;
- break;
- }
+ let Some(filename) = path.file_name() else {
+ return Err(Error::Scraping(path));
+ };
+ let lc_filename = filename.to_ascii_lowercase();
+ let lc_filename_str = lc_filename.to_string_lossy();
+ let mut keep = false;
+ for m in ["copyright", "licence", "license", "author", "notice"] {
+ if lc_filename_str.contains(m) {
+ keep = true;
+ break;
}
- if keep {
- if metadata.is_dir() {
- // scoop up whole directory
- } else if metadata.is_file() {
- let filename = filename.to_string_lossy();
- println!("Scraping {}", filename);
- dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?);
+ }
+ if keep {
+ if metadata.is_dir() {
+ for inner_entry in std::fs::read_dir(entry.path())? {
+ let inner_entry = inner_entry?;
+ if inner_entry.metadata()?.is_file() {
+ let inner_filename = inner_entry.file_name();
+ let inner_filename_str = inner_filename.to_string_lossy();
+ let qualified_filename =
+ format!("{}/{}", lc_filename_str, inner_filename_str);
+ println!("Scraping {}", qualified_filename);
+ dep.notices.insert(
+ qualified_filename.to_string(),
+ std::fs::read_to_string(inner_entry.path())?,
+ );
+ }
}
+ } else if metadata.is_file() {
+ let filename = filename.to_string_lossy();
+ println!("Scraping {}", filename);
+ dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?);
}
}
}
From 4e24e9b1adb8ffd57d7315028407922c44069f26 Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 6 Aug 2024 12:03:37 +0100
Subject: [PATCH 11/31] Update to rinja 0.3
---
Cargo.lock | 49 ++++---------------------
src/tools/generate-copyright/Cargo.toml | 2 +-
2 files changed, 8 insertions(+), 43 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 54454e84b5a97..67fee5b3f059f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1407,7 +1407,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"cargo_metadata 0.18.1",
- "rinja 0.2.0",
+ "rinja",
"serde",
"serde_json",
"thiserror",
@@ -3100,43 +3100,17 @@ dependencies = [
"walkdir",
]
-[[package]]
-name = "rinja"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2d47a46d7729e891c8accf260e9daa02ae6d570aa2a94fb1fb27eb5364a2323"
-dependencies = [
- "humansize",
- "num-traits",
- "percent-encoding",
- "rinja_derive 0.2.0",
-]
-
[[package]]
name = "rinja"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd"
dependencies = [
+ "humansize",
"itoa",
- "rinja_derive 0.3.0",
-]
-
-[[package]]
-name = "rinja_derive"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44dae9afe59d58ed8d988d67d1945f3638125d2fd2104058399382e11bd3ea2a"
-dependencies = [
- "basic-toml",
- "mime",
- "mime_guess",
- "once_map",
- "proc-macro2",
- "quote",
- "rinja_parser 0.2.0",
- "serde",
- "syn 2.0.67",
+ "num-traits",
+ "percent-encoding",
+ "rinja_derive",
]
[[package]]
@@ -3152,20 +3126,11 @@ dependencies = [
"once_map",
"proc-macro2",
"quote",
- "rinja_parser 0.3.0",
+ "rinja_parser",
"serde",
"syn 2.0.67",
]
-[[package]]
-name = "rinja_parser"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1771c78cd5d3b1646ef8d8f2ed100db936e8b291d3cc06e92a339ff346858c"
-dependencies = [
- "nom",
-]
-
[[package]]
name = "rinja_parser"
version = "0.3.0"
@@ -4644,7 +4609,7 @@ dependencies = [
"minifier",
"pulldown-cmark 0.9.6",
"regex",
- "rinja 0.3.0",
+ "rinja",
"rustdoc-json-types",
"serde",
"serde_json",
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index d200e2ec9f1e1..404101abd41bf 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -9,7 +9,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
[dependencies]
anyhow = "1.0.65"
cargo_metadata = "0.18.1"
-rinja = "0.2.0"
+rinja = "0.3.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
thiserror = "1"
From 99579f3ec1ee070d3d8203df1168f948b05b48dc Mon Sep 17 00:00:00 2001
From: Jonathan Pallant
Date: Tue, 6 Aug 2024 12:12:57 +0100
Subject: [PATCH 12/31] Apparently library/std is now part of a workspace at
library/
---
src/tools/generate-copyright/src/main.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 37de24648d56d..afa75d0d67140 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -31,7 +31,7 @@ fn main() -> Result<(), Error> {
let workspace_paths = [
Path::new("./Cargo.toml"),
Path::new("./src/tools/cargo/Cargo.toml"),
- Path::new("./library/std/Cargo.toml"),
+ Path::new("./library/Cargo.toml"),
];
let mut collected_cargo_metadata =
cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
From b174cf827bc020f45ca603723eb8d3c4c5ae339e Mon Sep 17 00:00:00 2001
From: Jane Losare-Lusby
Date: Tue, 6 Aug 2024 13:18:46 -0700
Subject: [PATCH 13/31] Integrate crlf directly into related test file instead
via of .gitattributes
---
tests/rustdoc-ui/intra-doc/.gitattributes | 2 +-
tests/rustdoc-ui/intra-doc/warning-crlf.rs | 52 +++++++++++-----------
2 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/tests/rustdoc-ui/intra-doc/.gitattributes b/tests/rustdoc-ui/intra-doc/.gitattributes
index 6c125fac52f5e..0ac2e3c27f431 100644
--- a/tests/rustdoc-ui/intra-doc/.gitattributes
+++ b/tests/rustdoc-ui/intra-doc/.gitattributes
@@ -1 +1 @@
-warning-crlf.rs eol=crlf
+warning-crlf.rs -text
diff --git a/tests/rustdoc-ui/intra-doc/warning-crlf.rs b/tests/rustdoc-ui/intra-doc/warning-crlf.rs
index ab096b860f819..9d3a4673c9d01 100644
--- a/tests/rustdoc-ui/intra-doc/warning-crlf.rs
+++ b/tests/rustdoc-ui/intra-doc/warning-crlf.rs
@@ -1,26 +1,26 @@
-// ignore-tidy-cr
-//@ check-pass
-
-// This file checks the spans of intra-link warnings in a file with CRLF line endings. The
-// .gitattributes file in this directory should enforce it.
-
-/// [error]
-pub struct A;
-//~^^ WARNING `error`
-
-///
-/// docs [error1]
-//~^ WARNING `error1`
-
-/// docs [error2]
-///
-pub struct B;
-//~^^^ WARNING `error2`
-
-/**
- * This is a multi-line comment.
- *
- * It also has an [error].
- */
-pub struct C;
-//~^^^ WARNING `error`
+// ignore-tidy-cr
+//@ check-pass
+
+// This file checks the spans of intra-link warnings in a file with CRLF line endings. The
+// .gitattributes file in this directory should enforce it.
+
+/// [error]
+pub struct A;
+//~^^ WARNING `error`
+
+///
+/// docs [error1]
+//~^ WARNING `error1`
+
+/// docs [error2]
+///
+pub struct B;
+//~^^^ WARNING `error2`
+
+/**
+ * This is a multi-line comment.
+ *
+ * It also has an [error].
+ */
+pub struct C;
+//~^^^ WARNING `error`
From 74653b61a67ae7db9f77ea1e09e65e40686c9058 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Fri, 26 Jul 2024 00:05:20 -0400
Subject: [PATCH 14/31] Add implied target features to target_feature attribute
---
compiler/rustc_codegen_llvm/src/llvm_util.rs | 16 -----
.../rustc_codegen_ssa/src/target_features.rs | 40 ++++++++++---
compiler/rustc_middle/src/query/mod.rs | 6 ++
compiler/rustc_target/src/target_features.rs | 58 +++++++++++++++++--
tests/ui/target-feature/implied-features.rs | 24 ++++++++
5 files changed, 113 insertions(+), 31 deletions(-)
create mode 100644 tests/ui/target-feature/implied-features.rs
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index af8a9be1ccbfd..dc21b92a95f76 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -646,22 +646,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec, which didn't make
- // it into a released version of LLVM yet.
- //
- // This doesn't use the "implicit target feature" system because it is only
- // used for function attributes in other targets, which fixes this bug as
- // well on the function attribute level.
- if sess.target.families.contains(&"wasm".into()) {
- if features.iter().any(|f| f == "+relaxed-simd")
- && !features.iter().any(|f| f == "+simd128")
- {
- features.push("+simd128".into());
- }
- }
-
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
features: f,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 127244a34f8f0..1bf842b53a3c5 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,7 +1,7 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::unord::UnordMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
@@ -30,6 +30,7 @@ pub fn from_target_feature(
.emit();
};
let rust_features = tcx.features();
+ let mut added_target_features = Vec::new();
for item in list {
// Only `enable = ...` is accepted in the meta-item list.
if !item.has_name(sym::enable) {
@@ -44,7 +45,7 @@ pub fn from_target_feature(
};
// We allow comma separation to enable multiple features.
- target_features.extend(value.as_str().split(',').filter_map(|feature| {
+ added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
let Some(feature_gate) = supported_target_features.get(feature) else {
let msg = format!("the feature named `{feature}` is not valid for this target");
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
@@ -98,13 +99,12 @@ pub fn from_target_feature(
}));
}
- for (feature, requires) in tcx.sess.target.implicit_target_features() {
- if target_features.iter().any(|f| f.as_str() == *feature)
- && !target_features.iter().any(|f| f.as_str() == *requires)
- {
- target_features.push(Symbol::intern(requires));
- }
+ // Add implied features
+ for feature in added_target_features.iter() {
+ target_features
+ .extend(tcx.implied_target_features(*feature).clone().into_sorted_stable_ord());
}
+ target_features.extend(added_target_features)
}
/// Computes the set of target features used in a function for the purposes of
@@ -162,6 +162,28 @@ pub(crate) fn provide(providers: &mut Providers) {
.collect()
}
},
+ implied_target_features: |tcx, feature| {
+ let implied_features = tcx
+ .sess
+ .target
+ .implied_target_features()
+ .iter()
+ .map(|(f, i)| (Symbol::intern(f), i))
+ .collect::>();
+
+ // implied target features have their own implied target features, so we traverse the
+ // map until there are no more features to add
+ let mut features = UnordSet::new();
+ let mut new_features = vec![feature];
+ while let Some(new_feature) = new_features.pop() {
+ if features.insert(new_feature) {
+ if let Some(implied_features) = implied_features.get(&new_feature) {
+ new_features.extend(implied_features.iter().copied().map(Symbol::intern))
+ }
+ }
+ }
+ features
+ },
asm_target_features,
..*providers
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c22c2e985abba..b6a2943265034 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2183,6 +2183,12 @@ rustc_queries! {
desc { "looking up supported target features" }
}
+ query implied_target_features(feature: Symbol) -> &'tcx UnordSet {
+ arena_cache
+ eval_always
+ desc { "looking up implied target features" }
+ }
+
query features_query(_: ()) -> &'tcx rustc_feature::Features {
feedable
desc { "looking up enabled feature gates" }
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 4e2617c467949..5b79495831a34 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -339,8 +339,6 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
// tidy-alphabetical-end
];
-const WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")];
-
const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
@@ -411,6 +409,54 @@ const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
// tidy-alphabetical-end
];
+const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+ // tidy-alphabetical-start
+ ("aes", &["sse2"]),
+ ("avx", &["sse4.2"]),
+ ("avx2", &["avx"]),
+ ("f16c", &["avx"]),
+ ("fma", &["avx"]),
+ ("pclmulqdq", &["sse2"]),
+ ("sha", &["sse2"]),
+ ("sse2", &["sse"]),
+ ("sse3", &["sse2"]),
+ ("sse4.1", &["ssse3"]),
+ ("sse4.2", &["sse4.1"]),
+ ("ssse3", &["sse3"]),
+ // tidy-alphabetical-end
+];
+
+const AARCH64_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+ // tidy-alphabetical-start
+ ("aes", &["neon"]),
+ ("f32mm", &["sve"]),
+ ("f64mm", &["sve"]),
+ ("fcma", &["neon"]),
+ ("fhm", &["fp16"]),
+ ("fp16", &["neon"]),
+ ("jsconv", &["neon"]),
+ ("rcpc2", &["rcpc"]),
+ ("sha2", &["neon"]),
+ ("sha3", &["sha2"]),
+ ("sm4", &["neon"]),
+ ("sve", &["fp16"]),
+ ("sve2", &["sve"]),
+ ("sve2-aes", &["sve2", "aes"]),
+ ("sve2-bitperm", &["sve2"]),
+ ("sve2-sha3", &["sve2", "sha3"]),
+ ("sve2-sm4", &["sve2", "sm4"]),
+ // tidy-alphabetical-end
+];
+
+const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+ // tidy-alphabetical-start
+ ("zb", &["zba", "zbc", "zbs"]),
+ ("zk", &["zkn", "zkr", "zks", "zkt", "zbkb", "zbkc", "zkbx"]),
+ ("zkn", &["zknd", "zkne", "zknh", "zbkb", "zbkc", "zkbx"]),
+ ("zks", &["zksed", "zksh", "zbkb", "zbkc", "zkbx"]),
+ // tidy-alphabetical-end
+];
+
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
@@ -458,11 +504,11 @@ impl super::spec::Target {
}
}
- /// Returns a list of target features. Each items first target feature
- /// implicitly enables the second one.
- pub fn implicit_target_features(&self) -> &'static [(&'static str, &'static str)] {
+ pub fn implied_target_features(&self) -> &'static [(&'static str, &'static [&'static str])] {
match &*self.arch {
- "wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES,
+ "aarch4" => AARCH64_IMPLIED_FEATURES,
+ "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES,
+ "x86" | "x86_64" => X86_IMPLIED_FEATURES,
_ => &[],
}
}
diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs
new file mode 100644
index 0000000000000..c6d9ba78c21e6
--- /dev/null
+++ b/tests/ui/target-feature/implied-features.rs
@@ -0,0 +1,24 @@
+//@ only-x86_64
+//@ run-pass
+#![feature(target_feature_11)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "ssse3")]
+fn call_ssse3() {}
+
+#[target_feature(enable = "avx")]
+fn call_avx() {}
+
+#[target_feature(enable = "avx2")]
+fn test_avx2() {
+ call_ssse3();
+ call_avx();
+}
+
+#[target_feature(enable = "fma")]
+fn test_fma() {
+ call_ssse3();
+ call_avx();
+}
+
+fn main() {}
From 22c59529441da1cca8eb2cc50d4162e3adf95355 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Fri, 26 Jul 2024 10:04:27 -0400
Subject: [PATCH 15/31] Add test to ensure implied target features work with
asm, and fix failing tests
---
.../rustc_codegen_ssa/src/target_features.rs | 12 ++--
.../const-eval/const_fn_target_feature.stderr | 2 +-
.../rfc-2396-target_feature-11/safe-calls.rs | 7 +--
.../safe-calls.stderr | 60 +++++++------------
.../asm-implied-features-issue-128125.rs | 10 ++++
tests/ui/target-feature/implied-features.rs | 2 +-
6 files changed, 44 insertions(+), 49 deletions(-)
create mode 100644 tests/ui/target-feature/asm-implied-features-issue-128125.rs
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 1bf842b53a3c5..24b2c9c51c6e1 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,7 +1,7 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_data_structures::unord::{UnordMap, UnordSet};
+use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
@@ -99,12 +99,14 @@ pub fn from_target_feature(
}));
}
- // Add implied features
+ // Add both explicit and implied target features, using a set to deduplicate
+ let mut target_features_set = UnordSet::new();
for feature in added_target_features.iter() {
- target_features
- .extend(tcx.implied_target_features(*feature).clone().into_sorted_stable_ord());
+ target_features_set
+ .extend_unord(tcx.implied_target_features(*feature).clone().into_items());
}
- target_features.extend(added_target_features)
+ target_features_set.extend(added_target_features);
+ target_features.extend(target_features_set.into_sorted_stable_ord())
}
/// Computes the set of target features used in a function for the purposes of
diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
index d3a00b57ebb50..ad40d733546af 100644
--- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr
+++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/const_fn_target_feature.rs:11:24
|
LL | const B: () = unsafe { avx2_fn() };
- | ^^^^^^^^^ calling a function that requires unavailable target features: avx2
+ | ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2
error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
index de002ef71d7d3..fec4e75290fc8 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
@@ -34,6 +34,7 @@ fn foo() {
#[target_feature(enable = "sse2")]
fn bar() {
+ sse2();
avx_bmi2();
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
Quux.avx_bmi2();
@@ -43,7 +44,6 @@ fn bar() {
#[target_feature(enable = "avx")]
fn baz() {
sse2();
- //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
avx_bmi2();
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
Quux.avx_bmi2();
@@ -54,7 +54,8 @@ fn baz() {
#[target_feature(enable = "bmi2")]
fn qux() {
sse2();
- //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+ avx_bmi2();
+ Quux.avx_bmi2();
}
const _: () = sse2();
@@ -64,8 +65,6 @@ const _: () = sse2_and_fxsr();
//~^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe
#[deny(unsafe_op_in_unsafe_fn)]
-#[target_feature(enable = "avx")]
-#[target_feature(enable = "bmi2")]
unsafe fn needs_unsafe_block() {
sse2();
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
index 537819ab8595c..c2227f8e84783 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
@@ -4,8 +4,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target feature: sse2
- = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
+ = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:29:5
@@ -13,7 +13,8 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
+ = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
+ = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:31:5
@@ -21,32 +22,24 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
+ = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
+ = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:37:5
+ --> $DIR/safe-calls.rs:38:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
+ = help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:39:5
+ --> $DIR/safe-calls.rs:40:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:45:5
- |
-LL | sse2();
- | ^^^^^^ call to function with `#[target_feature]`
- |
- = help: in order for the call to be safe, the context requires the following additional target feature: sse2
- = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:47:5
@@ -65,52 +58,43 @@ LL | Quux.avx_bmi2();
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:56:5
- |
-LL | sse2();
- | ^^^^^^ call to function with `#[target_feature]`
- |
- = help: in order for the call to be safe, the context requires the following additional target feature: sse2
- = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:60:15
+ --> $DIR/safe-calls.rs:61:15
|
LL | const _: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target feature: sse2
- = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
+ = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
- --> $DIR/safe-calls.rs:63:15
+ --> $DIR/safe-calls.rs:64:15
|
LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
- = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr
+ = note: the fxsr, sse, and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
- --> $DIR/safe-calls.rs:70:5
+ --> $DIR/safe-calls.rs:69:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: for more information, see issue #71668
- = help: in order for the call to be safe, the context requires the following additional target feature: sse2
- = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
+ = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
note: an unsafe function restricts its caller, but its body is safe by default
- --> $DIR/safe-calls.rs:69:1
+ --> $DIR/safe-calls.rs:68:1
|
LL | unsafe fn needs_unsafe_block() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
- --> $DIR/safe-calls.rs:66:8
+ --> $DIR/safe-calls.rs:67:8
|
LL | #[deny(unsafe_op_in_unsafe_fn)]
| ^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/target-feature/asm-implied-features-issue-128125.rs b/tests/ui/target-feature/asm-implied-features-issue-128125.rs
new file mode 100644
index 0000000000000..2b4f1d7df8563
--- /dev/null
+++ b/tests/ui/target-feature/asm-implied-features-issue-128125.rs
@@ -0,0 +1,10 @@
+//@ only-x86_64
+//@ build-pass
+#![allow(dead_code)]
+
+#[target_feature(enable = "avx2")]
+unsafe fn demo(v: std::arch::x86_64::__m256i) {
+ std::arch::asm!("/* {v} */", v = in(ymm_reg) v);
+}
+
+fn main() {}
diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs
index c6d9ba78c21e6..4fdd843e6c289 100644
--- a/tests/ui/target-feature/implied-features.rs
+++ b/tests/ui/target-feature/implied-features.rs
@@ -1,5 +1,5 @@
//@ only-x86_64
-//@ run-pass
+//@ build-pass
#![feature(target_feature_11)]
#![allow(dead_code)]
From 520a5a535f4a1432d7f9742171a11d21f518f652 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Fri, 26 Jul 2024 11:27:21 -0400
Subject: [PATCH 16/31] Fix codegen tests
---
tests/codegen/sse42-implies-crc32.rs | 2 +-
tests/codegen/target-feature-overrides.rs | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/tests/codegen/sse42-implies-crc32.rs b/tests/codegen/sse42-implies-crc32.rs
index 94fcd77bc8842..8a9c496a3a541 100644
--- a/tests/codegen/sse42-implies-crc32.rs
+++ b/tests/codegen/sse42-implies-crc32.rs
@@ -12,4 +12,4 @@ pub unsafe fn crc32sse(v: u8) -> u32 {
_mm_crc32_u8(out, v)
}
-// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32"}}
+// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}}
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index 1e2c364dbbc9a..87783706d9535 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -1,7 +1,7 @@
//@ revisions: COMPAT INCOMPAT
//@ needs-llvm-components: x86
//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
-//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
+//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx,+sse4.2,+sse4.1,+ssse3,+sse3
//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
// See also tests/assembly/target-feature-multiple.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
}
// CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
+// COMPAT-SAME: "target-features"="+avx2,+avx,{{.*}}"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
// CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx"
+// COMPAT-SAME: "target-features"="+avx2,+avx,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx"
From c866e1f812b7436abce2b03ec56d62c77d6684a2 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Mon, 29 Jul 2024 00:09:47 -0400
Subject: [PATCH 17/31] Add missing features
---
compiler/rustc_target/src/target_features.rs | 26 ++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 5b79495831a34..64f966d7a305e 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -414,8 +414,22 @@ const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
("aes", &["sse2"]),
("avx", &["sse4.2"]),
("avx2", &["avx"]),
+ ("avx512bf16", &["avx512bw"]),
+ ("avx512bitalg", &["avx512bw"]),
+ ("avx512bw", &["avx512f"]),
+ ("avx512cd", &["avx512f"]),
+ ("avx512dq", &["avx512f"]),
+ ("avx512f", &["avx2"]),
+ ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]),
+ ("avx512vbmi", &["avx512bw"]),
+ ("avx512vbmi2", &["avx512bw"]),
+ ("avx512vl", &["avx512f"]),
+ ("avx512vnni", &["avx512f"]),
+ ("avx512vp2intersect", &["avx512f"]),
+ ("avx512vpopcntdq", &["avx512f"]),
("f16c", &["avx"]),
("fma", &["avx"]),
+ ("gfni", &["sse2"]),
("pclmulqdq", &["sse2"]),
("sha", &["sse2"]),
("sse2", &["sse"]),
@@ -423,6 +437,11 @@ const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
("sse4.1", &["ssse3"]),
("sse4.2", &["sse4.1"]),
("ssse3", &["sse3"]),
+ ("vaes", &["avx", "aes"]),
+ ("vpclmulqdq", &["avx", "pclmulqdq"]),
+ ("xsavec", &["xsave"]),
+ ("xsaveopt", &["xsave"]),
+ ("xsaves", &["xsave"]),
// tidy-alphabetical-end
];
@@ -457,6 +476,12 @@ const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
// tidy-alphabetical-end
];
+const WASM_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+ // tidy-alphabetical-start
+ ("relaxed-simd", &["simd128"]),
+ // tidy-alphabetical-end
+];
+
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
@@ -509,6 +534,7 @@ impl super::spec::Target {
"aarch4" => AARCH64_IMPLIED_FEATURES,
"riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES,
"x86" | "x86_64" => X86_IMPLIED_FEATURES,
+ "wasm32" | "wasm64" => WASM_IMPLIED_FEATURES,
_ => &[],
}
}
From 34f29a24bbd471cf60f0517457ae024f90ec2263 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Tue, 30 Jul 2024 23:58:51 -0400
Subject: [PATCH 18/31] Add +sse4.2 due to #128426
---
src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 +-
src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs | 2 +-
src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs | 2 +-
src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
index 7363c75361779..13ebe56146381 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+aes,+vaes,+avx512f
+//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2
#![feature(avx512_target_feature, stdarch_x86_avx512)]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
index 728f57d48f17e..18693a2a97d11 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx
+//@compile-flags: -C target-feature=+avx,+sse4.2
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
index 80d125bb85650..f42ff6dfb51b2 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx2
+//@compile-flags: -C target-feature=+avx2,+sse4.2
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
index 66bfcb20f1c99..7d25854ccc075 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
+//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2
#![feature(avx512_target_feature)]
#![feature(stdarch_x86_avx512)]
From 3c48f6548bce89b459952f8d7ca077cfa99159aa Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Wed, 31 Jul 2024 01:50:02 -0400
Subject: [PATCH 19/31] Bless tests
---
.../fail/function_calls/simd_feature_flag_difference.stderr | 4 ++--
src/tools/miri/tests/fail/function_calls/target_feature.rs | 2 +-
.../miri/tests/fail/function_calls/target_feature.stderr | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
index 2544421c7e8c7..8ebd5d2726ffd 100644
--- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
+++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: avx
+error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
--> $DIR/simd_feature_flag_difference.rs:LL:CC
|
LL | unsafe { foo(0.0, x) }
- | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx
+ | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs
index 84e01eb4803fe..713d7c16f4c25 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.rs
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs
@@ -4,7 +4,7 @@
fn main() {
assert!(!is_x86_feature_detected!("ssse3"));
unsafe {
- ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
+ ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3
}
}
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
index 4d3cf6e9d3bc0..74a862c7b681c 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
+error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3
--> $DIR/target_feature.rs:LL:CC
|
LL | ssse3_fn();
- | ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
+ | ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
From fbd618d4aa8f3a6c998b81aa83a543d4c09d9bb3 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Fri, 2 Aug 2024 00:20:49 -0400
Subject: [PATCH 20/31] Refactor and fill out target feature lists
---
compiler/rustc_codegen_gcc/src/gcc_util.rs | 4 +-
compiler/rustc_codegen_gcc/src/lib.rs | 2 +-
compiler/rustc_codegen_llvm/src/llvm_util.rs | 28 +-
.../rustc_codegen_ssa/src/target_features.rs | 6 +-
compiler/rustc_target/src/target_features.rs | 613 ++++++++----------
5 files changed, 293 insertions(+), 360 deletions(-)
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 8bb90efe6fb7c..5308ccdb61469 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec {
sess.target
.supported_target_features()
.iter()
- .filter_map(|&(feature, gate)| {
+ .filter_map(|&(feature, gate, _)| {
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
Some(feature)
} else {
@@ -386,7 +386,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
.target
.supported_target_features()
.iter()
- .map(|(feature, _gate)| {
+ .map(|(feature, _gate, _implied)| {
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
let desc =
@@ -571,17 +571,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Vec>();
// implied target features have their own implied target features, so we traverse the
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 64f966d7a305e..f408db1dcbad2 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -53,136 +53,146 @@ impl Stability {
//
// Stabilizing a target feature requires t-lang approval.
-const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+type ImpliedFeatures = &'static [&'static str];
+
+const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("aclass", Unstable(sym::arm_target_feature)),
- ("aes", Unstable(sym::arm_target_feature)),
- ("crc", Unstable(sym::arm_target_feature)),
- ("d32", Unstable(sym::arm_target_feature)),
- ("dotprod", Unstable(sym::arm_target_feature)),
- ("dsp", Unstable(sym::arm_target_feature)),
- ("fp-armv8", Unstable(sym::arm_target_feature)),
- ("i8mm", Unstable(sym::arm_target_feature)),
- ("mclass", Unstable(sym::arm_target_feature)),
- ("neon", Unstable(sym::arm_target_feature)),
- ("rclass", Unstable(sym::arm_target_feature)),
- ("sha2", Unstable(sym::arm_target_feature)),
+ ("aclass", Unstable(sym::arm_target_feature), &[]),
+ ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+ ("crc", Unstable(sym::arm_target_feature), &[]),
+ ("d32", Unstable(sym::arm_target_feature), &[]),
+ ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
+ ("dsp", Unstable(sym::arm_target_feature), &[]),
+ ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
+ ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
+ ("mclass", Unstable(sym::arm_target_feature), &[]),
+ ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
+ ("rclass", Unstable(sym::arm_target_feature), &[]),
+ ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
// This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled per-function using #[instruction_set], not
// #[target_feature].
- ("thumb-mode", Unstable(sym::arm_target_feature)),
- ("thumb2", Unstable(sym::arm_target_feature)),
- ("trustzone", Unstable(sym::arm_target_feature)),
- ("v5te", Unstable(sym::arm_target_feature)),
- ("v6", Unstable(sym::arm_target_feature)),
- ("v6k", Unstable(sym::arm_target_feature)),
- ("v6t2", Unstable(sym::arm_target_feature)),
- ("v7", Unstable(sym::arm_target_feature)),
- ("v8", Unstable(sym::arm_target_feature)),
- ("vfp2", Unstable(sym::arm_target_feature)),
- ("vfp3", Unstable(sym::arm_target_feature)),
- ("vfp4", Unstable(sym::arm_target_feature)),
- ("virtualization", Unstable(sym::arm_target_feature)),
+ ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
+ ("thumb2", Unstable(sym::arm_target_feature), &[]),
+ ("trustzone", Unstable(sym::arm_target_feature), &[]),
+ ("v5te", Unstable(sym::arm_target_feature), &[]),
+ ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
+ ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
+ ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
+ ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
+ ("v8", Unstable(sym::arm_target_feature), &["v7"]),
+ ("vfp2", Unstable(sym::arm_target_feature), &[]),
+ ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
+ ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
+ ("virtualization", Unstable(sym::arm_target_feature), &[]),
// tidy-alphabetical-end
];
-const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
// FEAT_AES & FEAT_PMULL
- ("aes", Stable),
+ ("aes", Stable, &["neon"]),
// FEAT_BF16
- ("bf16", Stable),
+ ("bf16", Stable, &[]),
// FEAT_BTI
- ("bti", Stable),
+ ("bti", Stable, &[]),
// FEAT_CRC
- ("crc", Stable),
+ ("crc", Stable, &[]),
// FEAT_DIT
- ("dit", Stable),
+ ("dit", Stable, &[]),
// FEAT_DotProd
- ("dotprod", Stable),
+ ("dotprod", Stable, &["neon"]),
// FEAT_DPB
- ("dpb", Stable),
+ ("dpb", Stable, &[]),
// FEAT_DPB2
- ("dpb2", Stable),
+ ("dpb2", Stable, &["dpb"]),
// FEAT_F32MM
- ("f32mm", Stable),
+ ("f32mm", Stable, &["sve"]),
// FEAT_F64MM
- ("f64mm", Stable),
+ ("f64mm", Stable, &["sve"]),
// FEAT_FCMA
- ("fcma", Stable),
+ ("fcma", Stable, &["neon"]),
// FEAT_FHM
- ("fhm", Stable),
+ ("fhm", Stable, &["fp16"]),
// FEAT_FLAGM
- ("flagm", Stable),
+ ("flagm", Stable, &[]),
// FEAT_FP16
- ("fp16", Stable),
+ ("fp16", Stable, &[]),
// FEAT_FRINTTS
- ("frintts", Stable),
+ ("frintts", Stable, &[]),
// FEAT_I8MM
- ("i8mm", Stable),
+ ("i8mm", Stable, &[]),
// FEAT_JSCVT
- ("jsconv", Stable),
+ ("jsconv", Stable, &[]),
// FEAT_LOR
- ("lor", Stable),
+ ("lor", Stable, &[]),
// FEAT_LSE
- ("lse", Stable),
+ ("lse", Stable, &[]),
// FEAT_MTE & FEAT_MTE2
- ("mte", Stable),
+ ("mte", Stable, &[]),
// FEAT_AdvSimd & FEAT_FP
- ("neon", Stable),
+ ("neon", Stable, &[]),
// FEAT_PAUTH (address authentication)
- ("paca", Stable),
+ ("paca", Stable, &[]),
// FEAT_PAUTH (generic authentication)
- ("pacg", Stable),
+ ("pacg", Stable, &[]),
// FEAT_PAN
- ("pan", Stable),
+ ("pan", Stable, &[]),
// FEAT_PMUv3
- ("pmuv3", Stable),
+ ("pmuv3", Stable, &[]),
// FEAT_RAND
- ("rand", Stable),
+ ("rand", Stable, &[]),
// FEAT_RAS & FEAT_RASv1p1
- ("ras", Stable),
+ ("ras", Stable, &[]),
// FEAT_RCPC
- ("rcpc", Stable),
+ ("rcpc", Stable, &[]),
// FEAT_RCPC2
- ("rcpc2", Stable),
+ ("rcpc2", Stable, &["rcpc"]),
// FEAT_RDM
- ("rdm", Stable),
+ ("rdm", Stable, &["neon"]),
// FEAT_SB
- ("sb", Stable),
+ ("sb", Stable, &[]),
// FEAT_SHA1 & FEAT_SHA256
- ("sha2", Stable),
+ ("sha2", Stable, &["neon"]),
// FEAT_SHA512 & FEAT_SHA3
- ("sha3", Stable),
+ ("sha3", Stable, &["sha2"]),
// FEAT_SM3 & FEAT_SM4
- ("sm4", Stable),
+ ("sm4", Stable, &["neon"]),
// FEAT_SPE
- ("spe", Stable),
+ ("spe", Stable, &[]),
// FEAT_SSBS & FEAT_SSBS2
- ("ssbs", Stable),
+ ("ssbs", Stable, &[]),
// FEAT_SVE
- ("sve", Stable),
+ ("sve", Stable, &[]),
// FEAT_SVE2
- ("sve2", Stable),
+ ("sve2", Stable, &["sve"]),
// FEAT_SVE2_AES
- ("sve2-aes", Stable),
+ ("sve2-aes", Stable, &["sve2", "aes"]),
// FEAT_SVE2_BitPerm
- ("sve2-bitperm", Stable),
+ ("sve2-bitperm", Stable, &["sve2"]),
// FEAT_SVE2_SHA3
- ("sve2-sha3", Stable),
+ ("sve2-sha3", Stable, &["sve2", "sha3"]),
// FEAT_SVE2_SM4
- ("sve2-sm4", Stable),
+ ("sve2-sm4", Stable, &["sve2", "sm4"]),
// FEAT_TME
- ("tme", Stable),
- ("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
- ("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
+ ("tme", Stable, &[]),
+ (
+ "v8.1a",
+ Unstable(sym::aarch64_ver_target_feature),
+ &["crc", "lse", "rdm", "pan", "lor", "vh"],
+ ),
+ ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
+ (
+ "v8.3a",
+ Unstable(sym::aarch64_ver_target_feature),
+ &["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
+ ),
+ ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
+ ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
+ ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
+ ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &[]),
// FEAT_VHE
- ("vh", Stable),
+ ("vh", Stable, &[]),
// tidy-alphabetical-end
];
@@ -190,295 +200,223 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
&["paca", "pacg"], // Together these represent `pauth` in LLVM
];
-const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("adx", Stable),
- ("aes", Stable),
- ("amx-bf16", Unstable(sym::x86_amx_intrinsics)),
- ("amx-complex", Unstable(sym::x86_amx_intrinsics)),
- ("amx-fp16", Unstable(sym::x86_amx_intrinsics)),
- ("amx-int8", Unstable(sym::x86_amx_intrinsics)),
- ("amx-tile", Unstable(sym::x86_amx_intrinsics)),
- ("avx", Stable),
- ("avx2", Stable),
- ("avx512bf16", Unstable(sym::avx512_target_feature)),
- ("avx512bitalg", Unstable(sym::avx512_target_feature)),
- ("avx512bw", Unstable(sym::avx512_target_feature)),
- ("avx512cd", Unstable(sym::avx512_target_feature)),
- ("avx512dq", Unstable(sym::avx512_target_feature)),
- ("avx512f", Unstable(sym::avx512_target_feature)),
- ("avx512fp16", Unstable(sym::avx512_target_feature)),
- ("avx512ifma", Unstable(sym::avx512_target_feature)),
- ("avx512vbmi", Unstable(sym::avx512_target_feature)),
- ("avx512vbmi2", Unstable(sym::avx512_target_feature)),
- ("avx512vl", Unstable(sym::avx512_target_feature)),
- ("avx512vnni", Unstable(sym::avx512_target_feature)),
- ("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
- ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
- ("avxifma", Unstable(sym::avx512_target_feature)),
- ("avxneconvert", Unstable(sym::avx512_target_feature)),
- ("avxvnni", Unstable(sym::avx512_target_feature)),
- ("avxvnniint16", Unstable(sym::avx512_target_feature)),
- ("avxvnniint8", Unstable(sym::avx512_target_feature)),
- ("bmi1", Stable),
- ("bmi2", Stable),
- ("cmpxchg16b", Stable),
- ("ermsb", Unstable(sym::ermsb_target_feature)),
- ("f16c", Stable),
- ("fma", Stable),
- ("fxsr", Stable),
- ("gfni", Unstable(sym::avx512_target_feature)),
- ("lahfsahf", Unstable(sym::lahfsahf_target_feature)),
- ("lzcnt", Stable),
- ("movbe", Stable),
- ("pclmulqdq", Stable),
- ("popcnt", Stable),
- ("prfchw", Unstable(sym::prfchw_target_feature)),
- ("rdrand", Stable),
- ("rdseed", Stable),
- ("rtm", Unstable(sym::rtm_target_feature)),
- ("sha", Stable),
- ("sha512", Unstable(sym::sha512_sm_x86)),
- ("sm3", Unstable(sym::sha512_sm_x86)),
- ("sm4", Unstable(sym::sha512_sm_x86)),
- ("sse", Stable),
- ("sse2", Stable),
- ("sse3", Stable),
- ("sse4.1", Stable),
- ("sse4.2", Stable),
- ("sse4a", Unstable(sym::sse4a_target_feature)),
- ("ssse3", Stable),
- ("tbm", Unstable(sym::tbm_target_feature)),
- ("vaes", Unstable(sym::avx512_target_feature)),
- ("vpclmulqdq", Unstable(sym::avx512_target_feature)),
- ("xop", Unstable(sym::xop_target_feature)),
- ("xsave", Stable),
- ("xsavec", Stable),
- ("xsaveopt", Stable),
- ("xsaves", Stable),
+ ("adx", Stable, &[]),
+ ("aes", Stable, &["sse2"]),
+ ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+ ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+ ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+ ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+ ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
+ ("avx", Stable, &["sse4.2"]),
+ ("avx2", Stable, &["avx"]),
+ ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+ ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+ ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
+ ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
+ ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+ ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+ ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+ ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
+ ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
+ ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
+ ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
+ ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
+ ("bmi1", Stable, &[]),
+ ("bmi2", Stable, &[]),
+ ("cmpxchg16b", Stable, &[]),
+ ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
+ ("f16c", Stable, &["avx"]),
+ ("fma", Stable, &["avx"]),
+ ("fxsr", Stable, &[]),
+ ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
+ ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
+ ("lzcnt", Stable, &[]),
+ ("movbe", Stable, &[]),
+ ("pclmulqdq", Stable, &[]),
+ ("popcnt", Stable, &[]),
+ ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
+ ("rdrand", Stable, &[]),
+ ("rdseed", Stable, &[]),
+ ("rtm", Unstable(sym::rtm_target_feature), &[]),
+ ("sha", Stable, &["sse2"]),
+ ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
+ ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
+ ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
+ ("sse", Stable, &[]),
+ ("sse2", Stable, &["sse"]),
+ ("sse3", Stable, &["sse2"]),
+ ("sse4.1", Stable, &["ssse3"]),
+ ("sse4.2", Stable, &["sse4.1"]),
+ ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
+ ("ssse3", Stable, &["sse3"]),
+ ("tbm", Unstable(sym::tbm_target_feature), &[]),
+ ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
+ ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
+ ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
+ ("xsave", Stable, &[]),
+ ("xsavec", Stable, &["xsave"]),
+ ("xsaveopt", Stable, &["xsave"]),
+ ("xsaves", Stable, &["xsave"]),
// tidy-alphabetical-end
];
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("hvx", Unstable(sym::hexagon_target_feature)),
- ("hvx-length128b", Unstable(sym::hexagon_target_feature)),
+ ("hvx", Unstable(sym::hexagon_target_feature), &[]),
+ ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
// tidy-alphabetical-end
];
-const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("altivec", Unstable(sym::powerpc_target_feature)),
- ("power10-vector", Unstable(sym::powerpc_target_feature)),
- ("power8-altivec", Unstable(sym::powerpc_target_feature)),
- ("power8-vector", Unstable(sym::powerpc_target_feature)),
- ("power9-altivec", Unstable(sym::powerpc_target_feature)),
- ("power9-vector", Unstable(sym::powerpc_target_feature)),
- ("vsx", Unstable(sym::powerpc_target_feature)),
+ ("altivec", Unstable(sym::powerpc_target_feature), &[]),
+ ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
+ ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
+ ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
+ ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
+ ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
+ ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
// tidy-alphabetical-end
];
-const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("fp64", Unstable(sym::mips_target_feature)),
- ("msa", Unstable(sym::mips_target_feature)),
- ("virt", Unstable(sym::mips_target_feature)),
+ ("fp64", Unstable(sym::mips_target_feature), &[]),
+ ("msa", Unstable(sym::mips_target_feature), &[]),
+ ("virt", Unstable(sym::mips_target_feature), &[]),
// tidy-alphabetical-end
];
-const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("a", Stable),
- ("c", Stable),
- ("d", Unstable(sym::riscv_target_feature)),
- ("e", Unstable(sym::riscv_target_feature)),
- ("f", Unstable(sym::riscv_target_feature)),
- ("m", Stable),
- ("relax", Unstable(sym::riscv_target_feature)),
- ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
- ("v", Unstable(sym::riscv_target_feature)),
- ("zba", Stable),
- ("zbb", Stable),
- ("zbc", Stable),
- ("zbkb", Stable),
- ("zbkc", Stable),
- ("zbkx", Stable),
- ("zbs", Stable),
- ("zdinx", Unstable(sym::riscv_target_feature)),
- ("zfh", Unstable(sym::riscv_target_feature)),
- ("zfhmin", Unstable(sym::riscv_target_feature)),
- ("zfinx", Unstable(sym::riscv_target_feature)),
- ("zhinx", Unstable(sym::riscv_target_feature)),
- ("zhinxmin", Unstable(sym::riscv_target_feature)),
- ("zk", Stable),
- ("zkn", Stable),
- ("zknd", Stable),
- ("zkne", Stable),
- ("zknh", Stable),
- ("zkr", Stable),
- ("zks", Stable),
- ("zksed", Stable),
- ("zksh", Stable),
- ("zkt", Stable),
+ ("a", Stable, &[]),
+ ("c", Stable, &[]),
+ ("d", Unstable(sym::riscv_target_feature), &["f"]),
+ ("e", Unstable(sym::riscv_target_feature), &[]),
+ ("f", Unstable(sym::riscv_target_feature), &[]),
+ ("m", Stable, &[]),
+ ("relax", Unstable(sym::riscv_target_feature), &[]),
+ ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
+ ("v", Unstable(sym::riscv_target_feature), &[]),
+ ("zba", Stable, &[]),
+ ("zbb", Stable, &[]),
+ ("zbc", Stable, &[]),
+ ("zbkb", Stable, &[]),
+ ("zbkc", Stable, &[]),
+ ("zbkx", Stable, &[]),
+ ("zbs", Stable, &[]),
+ ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
+ ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
+ ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
+ ("zfinx", Unstable(sym::riscv_target_feature), &[]),
+ ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
+ ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
+ ("zk", Stable, &["zkn", "zkr", "zkt"]),
+ ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
+ ("zknd", Stable, &[]),
+ ("zkne", Stable, &[]),
+ ("zknh", Stable, &[]),
+ ("zkr", Stable, &[]),
+ ("zks", Stable, &["zbkb", "bzkc", "zbkx", "zksed", "zksh"]),
+ ("zksed", Stable, &[]),
+ ("zksh", Stable, &[]),
+ ("zkt", Stable, &[]),
// tidy-alphabetical-end
];
-const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("atomics", Unstable(sym::wasm_target_feature)),
- ("bulk-memory", Stable),
- ("exception-handling", Unstable(sym::wasm_target_feature)),
- ("extended-const", Stable),
- ("multivalue", Unstable(sym::wasm_target_feature)),
- ("mutable-globals", Stable),
- ("nontrapping-fptoint", Stable),
- ("reference-types", Unstable(sym::wasm_target_feature)),
- ("relaxed-simd", Stable),
- ("sign-ext", Stable),
- ("simd128", Stable),
+ ("atomics", Unstable(sym::wasm_target_feature), &[]),
+ ("bulk-memory", Stable, &[]),
+ ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
+ ("extended-const", Stable, &[]),
+ ("multivalue", Unstable(sym::wasm_target_feature), &[]),
+ ("mutable-globals", Stable, &[]),
+ ("nontrapping-fptoint", Stable, &[]),
+ ("reference-types", Unstable(sym::wasm_target_feature), &[]),
+ ("relaxed-simd", Stable, &["simd128"]),
+ ("sign-ext", Stable, &[]),
+ ("simd128", Stable, &[]),
// tidy-alphabetical-end
];
-const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
+const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
+ &[("alu32", Unstable(sym::bpf_target_feature), &[])];
-const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("10e60", Unstable(sym::csky_target_feature)),
- ("2e3", Unstable(sym::csky_target_feature)),
- ("3e3r1", Unstable(sym::csky_target_feature)),
- ("3e3r2", Unstable(sym::csky_target_feature)),
- ("3e3r3", Unstable(sym::csky_target_feature)),
- ("3e7", Unstable(sym::csky_target_feature)),
- ("7e10", Unstable(sym::csky_target_feature)),
- ("cache", Unstable(sym::csky_target_feature)),
- ("doloop", Unstable(sym::csky_target_feature)),
- ("dsp1e2", Unstable(sym::csky_target_feature)),
- ("dspe60", Unstable(sym::csky_target_feature)),
- ("e1", Unstable(sym::csky_target_feature)),
- ("e2", Unstable(sym::csky_target_feature)),
- ("edsp", Unstable(sym::csky_target_feature)),
- ("elrw", Unstable(sym::csky_target_feature)),
- ("float1e2", Unstable(sym::csky_target_feature)),
- ("float1e3", Unstable(sym::csky_target_feature)),
- ("float3e4", Unstable(sym::csky_target_feature)),
- ("float7e60", Unstable(sym::csky_target_feature)),
- ("floate1", Unstable(sym::csky_target_feature)),
- ("hard-tp", Unstable(sym::csky_target_feature)),
- ("high-registers", Unstable(sym::csky_target_feature)),
- ("hwdiv", Unstable(sym::csky_target_feature)),
- ("mp", Unstable(sym::csky_target_feature)),
- ("mp1e2", Unstable(sym::csky_target_feature)),
- ("nvic", Unstable(sym::csky_target_feature)),
- ("trust", Unstable(sym::csky_target_feature)),
- ("vdsp2e60f", Unstable(sym::csky_target_feature)),
- ("vdspv1", Unstable(sym::csky_target_feature)),
- ("vdspv2", Unstable(sym::csky_target_feature)),
+ ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
+ ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
+ ("3e3r1", Unstable(sym::csky_target_feature), &[]),
+ ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
+ ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
+ ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
+ ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
+ ("cache", Unstable(sym::csky_target_feature), &[]),
+ ("doloop", Unstable(sym::csky_target_feature), &[]),
+ ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
+ ("dspe60", Unstable(sym::csky_target_feature), &[]),
+ ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
+ ("e2", Unstable(sym::csky_target_feature), &["e2"]),
+ ("edsp", Unstable(sym::csky_target_feature), &[]),
+ ("elrw", Unstable(sym::csky_target_feature), &[]),
+ ("float1e2", Unstable(sym::csky_target_feature), &[]),
+ ("float1e3", Unstable(sym::csky_target_feature), &[]),
+ ("float3e4", Unstable(sym::csky_target_feature), &[]),
+ ("float7e60", Unstable(sym::csky_target_feature), &[]),
+ ("floate1", Unstable(sym::csky_target_feature), &[]),
+ ("hard-tp", Unstable(sym::csky_target_feature), &[]),
+ ("high-registers", Unstable(sym::csky_target_feature), &[]),
+ ("hwdiv", Unstable(sym::csky_target_feature), &[]),
+ ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
+ ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
+ ("nvic", Unstable(sym::csky_target_feature), &[]),
+ ("trust", Unstable(sym::csky_target_feature), &[]),
+ ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
+ ("vdspv1", Unstable(sym::csky_target_feature), &[]),
+ ("vdspv2", Unstable(sym::csky_target_feature), &[]),
// tidy-alphabetical-end
//fpu
// tidy-alphabetical-start
- ("fdivdu", Unstable(sym::csky_target_feature)),
- ("fpuv2_df", Unstable(sym::csky_target_feature)),
- ("fpuv2_sf", Unstable(sym::csky_target_feature)),
- ("fpuv3_df", Unstable(sym::csky_target_feature)),
- ("fpuv3_hf", Unstable(sym::csky_target_feature)),
- ("fpuv3_hi", Unstable(sym::csky_target_feature)),
- ("fpuv3_sf", Unstable(sym::csky_target_feature)),
- ("hard-float", Unstable(sym::csky_target_feature)),
- ("hard-float-abi", Unstable(sym::csky_target_feature)),
- // tidy-alphabetical-end
-];
-
-const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
- // tidy-alphabetical-start
- ("d", Unstable(sym::loongarch_target_feature)),
- ("f", Unstable(sym::loongarch_target_feature)),
- ("frecipe", Unstable(sym::loongarch_target_feature)),
- ("lasx", Unstable(sym::loongarch_target_feature)),
- ("lbt", Unstable(sym::loongarch_target_feature)),
- ("lsx", Unstable(sym::loongarch_target_feature)),
- ("lvz", Unstable(sym::loongarch_target_feature)),
- ("relax", Unstable(sym::loongarch_target_feature)),
- ("ual", Unstable(sym::loongarch_target_feature)),
- // tidy-alphabetical-end
-];
-
-const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
- // tidy-alphabetical-start
- ("backchain", Unstable(sym::s390x_target_feature)),
- ("vector", Unstable(sym::s390x_target_feature)),
- // tidy-alphabetical-end
-];
-
-const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
- // tidy-alphabetical-start
- ("aes", &["sse2"]),
- ("avx", &["sse4.2"]),
- ("avx2", &["avx"]),
- ("avx512bf16", &["avx512bw"]),
- ("avx512bitalg", &["avx512bw"]),
- ("avx512bw", &["avx512f"]),
- ("avx512cd", &["avx512f"]),
- ("avx512dq", &["avx512f"]),
- ("avx512f", &["avx2"]),
- ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]),
- ("avx512vbmi", &["avx512bw"]),
- ("avx512vbmi2", &["avx512bw"]),
- ("avx512vl", &["avx512f"]),
- ("avx512vnni", &["avx512f"]),
- ("avx512vp2intersect", &["avx512f"]),
- ("avx512vpopcntdq", &["avx512f"]),
- ("f16c", &["avx"]),
- ("fma", &["avx"]),
- ("gfni", &["sse2"]),
- ("pclmulqdq", &["sse2"]),
- ("sha", &["sse2"]),
- ("sse2", &["sse"]),
- ("sse3", &["sse2"]),
- ("sse4.1", &["ssse3"]),
- ("sse4.2", &["sse4.1"]),
- ("ssse3", &["sse3"]),
- ("vaes", &["avx", "aes"]),
- ("vpclmulqdq", &["avx", "pclmulqdq"]),
- ("xsavec", &["xsave"]),
- ("xsaveopt", &["xsave"]),
- ("xsaves", &["xsave"]),
- // tidy-alphabetical-end
-];
-
-const AARCH64_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
- // tidy-alphabetical-start
- ("aes", &["neon"]),
- ("f32mm", &["sve"]),
- ("f64mm", &["sve"]),
- ("fcma", &["neon"]),
- ("fhm", &["fp16"]),
- ("fp16", &["neon"]),
- ("jsconv", &["neon"]),
- ("rcpc2", &["rcpc"]),
- ("sha2", &["neon"]),
- ("sha3", &["sha2"]),
- ("sm4", &["neon"]),
- ("sve", &["fp16"]),
- ("sve2", &["sve"]),
- ("sve2-aes", &["sve2", "aes"]),
- ("sve2-bitperm", &["sve2"]),
- ("sve2-sha3", &["sve2", "sha3"]),
- ("sve2-sm4", &["sve2", "sm4"]),
+ ("fdivdu", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
+ ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
+ ("hard-float", Unstable(sym::csky_target_feature), &[]),
+ ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
// tidy-alphabetical-end
];
-const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("zb", &["zba", "zbc", "zbs"]),
- ("zk", &["zkn", "zkr", "zks", "zkt", "zbkb", "zbkc", "zkbx"]),
- ("zkn", &["zknd", "zkne", "zknh", "zbkb", "zbkc", "zkbx"]),
- ("zks", &["zksed", "zksh", "zbkb", "zbkc", "zkbx"]),
+ ("d", Unstable(sym::loongarch_target_feature), &["f"]),
+ ("f", Unstable(sym::loongarch_target_feature), &[]),
+ ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
+ ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
+ ("lbt", Unstable(sym::loongarch_target_feature), &[]),
+ ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
+ ("lvz", Unstable(sym::loongarch_target_feature), &[]),
+ ("relax", Unstable(sym::loongarch_target_feature), &[]),
+ ("ual", Unstable(sym::loongarch_target_feature), &[]),
// tidy-alphabetical-end
];
-const WASM_IMPLIED_FEATURES: &[(&str, &[&str])] = &[
+const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
- ("relaxed-simd", &["simd128"]),
+ ("backchain", Unstable(sym::s390x_target_feature), &[]),
+ ("vector", Unstable(sym::s390x_target_feature), &[]),
// tidy-alphabetical-end
];
@@ -501,10 +439,13 @@ pub fn all_known_features() -> impl Iterator- {
.chain(LOONGARCH_ALLOWED_FEATURES)
.chain(IBMZ_ALLOWED_FEATURES)
.cloned()
+ .map(|(f, s, _)| (f, s))
}
impl super::spec::Target {
- pub fn supported_target_features(&self) -> &'static [(&'static str, Stability)] {
+ pub fn supported_target_features(
+ &self,
+ ) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
match &*self.arch {
"arm" => ARM_ALLOWED_FEATURES,
"aarch64" | "arm64ec" => AARCH64_ALLOWED_FEATURES,
@@ -528,14 +469,4 @@ impl super::spec::Target {
_ => &[],
}
}
-
- pub fn implied_target_features(&self) -> &'static [(&'static str, &'static [&'static str])] {
- match &*self.arch {
- "aarch4" => AARCH64_IMPLIED_FEATURES,
- "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES,
- "x86" | "x86_64" => X86_IMPLIED_FEATURES,
- "wasm32" | "wasm64" => WASM_IMPLIED_FEATURES,
- _ => &[],
- }
- }
}
From 484aca885765739d5fa1f3d77e082552d8c4bc58 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Sat, 3 Aug 2024 04:45:48 -0400
Subject: [PATCH 21/31] Don't use LLVM's target features
---
compiler/rustc_codegen_llvm/src/back/write.rs | 8 ++-
compiler/rustc_codegen_llvm/src/context.rs | 2 +-
compiler/rustc_codegen_llvm/src/lib.rs | 2 +-
compiler/rustc_codegen_llvm/src/llvm_util.rs | 63 ++++++++++++++-----
.../rustc_codegen_ssa/src/target_features.rs | 23 +------
compiler/rustc_target/src/target_features.rs | 25 ++++++++
6 files changed, 84 insertions(+), 39 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 5a7909d151139..890fcf508a8bd 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -95,11 +95,15 @@ pub fn write_output_file<'ll>(
}
}
-pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
+pub fn create_informational_target_machine(
+ sess: &Session,
+ extra_features: bool,
+) -> OwnedTargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
- let features = llvm_util::global_llvm_features(sess, false);
+ let features =
+ if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() };
target_machine_factory(sess, config::OptLevel::No, &features)(config)
.unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ea930421b5869..1dc3fbfc7b303 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults.
{
- let tm = crate::back::write::create_informational_target_machine(tcx.sess);
+ let tm = crate::back::write::create_informational_target_machine(tcx.sess, true);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 41e9cfd1066b9..333f1fdf6e03a 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -434,7 +434,7 @@ impl ModuleLlvm {
ModuleLlvm {
llmod_raw,
llcx,
- tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
+ tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, true)),
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c70f6dd8180bf..e85974b7cc1ec 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -308,7 +308,53 @@ pub fn check_tied_features(
/// Used to generate cfg variables and apply features
/// Must express features in the way Rust understands them
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
- let target_machine = create_informational_target_machine(sess);
+ let rust_features = sess
+ .target
+ .supported_target_features()
+ .iter()
+ .map(|(feature, _, _)| {
+ (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature))
+ })
+ .collect::>();
+
+ let mut features = FxHashSet::default();
+
+ // Add base features for the target
+ let target_machine = create_informational_target_machine(sess, false);
+ features.extend(
+ sess.target
+ .supported_target_features()
+ .iter()
+ .filter(|(feature, _, _)| {
+ // skip checking special features, as LLVM may not understands them
+ if RUSTC_SPECIAL_FEATURES.contains(feature) {
+ return true;
+ }
+ // check that all features in a given smallvec are enabled
+ for llvm_feature in to_llvm_features(sess, feature) {
+ let cstr = SmallCStr::new(llvm_feature);
+ if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
+ return false;
+ }
+ }
+ true
+ })
+ .map(|(feature, _, _)| Symbol::intern(feature)),
+ );
+
+ // Add enabled features
+ for llvm_feature in global_llvm_features(sess, false) {
+ let (add, llvm_feature) = llvm_feature.split_at(1);
+ let feature =
+ rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature));
+ if add == "+" {
+ features.extend(sess.target.implied_target_features(std::iter::once(feature)));
+ } else if add == "-" {
+ features.remove(&feature);
+ }
+ }
+
+ // Filter enabled features based on feature gates
sess.target
.supported_target_features()
.iter()
@@ -320,18 +366,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
}
})
.filter(|feature| {
- // skip checking special features, as LLVM may not understands them
- if RUSTC_SPECIAL_FEATURES.contains(feature) {
- return true;
- }
- // check that all features in a given smallvec are enabled
- for llvm_feature in to_llvm_features(sess, feature) {
- let cstr = SmallCStr::new(llvm_feature);
- if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
- return false;
- }
- }
- true
+ RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature))
})
.map(|feature| Symbol::intern(feature))
.collect()
@@ -440,7 +475,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
require_inited();
- let tm = create_informational_target_machine(sess);
+ let tm = create_informational_target_machine(sess, true);
match req.kind {
PrintKind::TargetCPUs => {
// SAFETY generate a C compatible string from a byte slice to pass
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 536f39375bb90..c84b844cd0401 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,6 +1,6 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
@@ -165,26 +165,7 @@ pub(crate) fn provide(providers: &mut Providers) {
}
},
implied_target_features: |tcx, feature| {
- let implied_features = tcx
- .sess
- .target
- .supported_target_features()
- .iter()
- .map(|(f, _, i)| (Symbol::intern(f), i))
- .collect::>();
-
- // implied target features have their own implied target features, so we traverse the
- // map until there are no more features to add
- let mut features = UnordSet::new();
- let mut new_features = vec![feature];
- while let Some(new_feature) = new_features.pop() {
- if features.insert(new_feature) {
- if let Some(implied_features) = implied_features.get(&new_feature) {
- new_features.extend(implied_features.iter().copied().map(Symbol::intern))
- }
- }
- }
- features
+ tcx.sess.target.implied_target_features(std::iter::once(feature)).into()
},
asm_target_features,
..*providers
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index f408db1dcbad2..0e9979e1bb7f6 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_span::symbol::{sym, Symbol};
/// Features that control behaviour of rustc, rather than the codegen.
@@ -469,4 +470,28 @@ impl super::spec::Target {
_ => &[],
}
}
+
+ pub fn implied_target_features(
+ &self,
+ base_features: impl Iterator- ,
+ ) -> FxHashSet
{
+ let implied_features = self
+ .supported_target_features()
+ .iter()
+ .map(|(f, _, i)| (Symbol::intern(f), i))
+ .collect::>();
+
+ // implied target features have their own implied target features, so we traverse the
+ // map until there are no more features to add
+ let mut features = FxHashSet::default();
+ let mut new_features = base_features.collect::>();
+ while let Some(new_feature) = new_features.pop() {
+ if features.insert(new_feature) {
+ if let Some(implied_features) = implied_features.get(&new_feature) {
+ new_features.extend(implied_features.iter().copied().map(Symbol::intern))
+ }
+ }
+ }
+ features
+ }
}
From a25da077cf7606f42ffad17ee1562f932aa19b12 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Sat, 3 Aug 2024 23:51:37 -0400
Subject: [PATCH 22/31] Don't use LLVM to compute -Ctarget-feature
---
compiler/rustc_codegen_llvm/src/back/write.rs | 5 +-
compiler/rustc_codegen_llvm/src/context.rs | 2 +-
compiler/rustc_codegen_llvm/src/lib.rs | 4 +-
compiler/rustc_codegen_llvm/src/llvm_util.rs | 211 +++++++++---------
compiler/rustc_target/src/target_features.rs | 8 +-
tests/codegen/target-feature-overrides.rs | 2 +-
6 files changed, 120 insertions(+), 112 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 890fcf508a8bd..a1f2433ab6f3b 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -97,13 +97,12 @@ pub fn write_output_file<'ll>(
pub fn create_informational_target_machine(
sess: &Session,
- extra_features: bool,
+ only_base_features: bool,
) -> OwnedTargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
- let features =
- if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() };
+ let features = llvm_util::global_llvm_features(sess, false, only_base_features);
target_machine_factory(sess, config::OptLevel::No, &features)(config)
.unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1dc3fbfc7b303..173b8a479efc5 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults.
{
- let tm = crate::back::write::create_informational_target_machine(tcx.sess, true);
+ let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 333f1fdf6e03a..518a86e0cb06d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend {
fn provide(&self, providers: &mut Providers) {
providers.global_backend_features =
- |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
+ |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false)
}
fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
@@ -434,7 +434,7 @@ impl ModuleLlvm {
ModuleLlvm {
llmod_raw,
llcx,
- tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, true)),
+ tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e85974b7cc1ec..3190853a84c90 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -308,19 +308,10 @@ pub fn check_tied_features(
/// Used to generate cfg variables and apply features
/// Must express features in the way Rust understands them
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
- let rust_features = sess
- .target
- .supported_target_features()
- .iter()
- .map(|(feature, _, _)| {
- (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature))
- })
- .collect::>();
-
let mut features = FxHashSet::default();
// Add base features for the target
- let target_machine = create_informational_target_machine(sess, false);
+ let target_machine = create_informational_target_machine(sess, true);
features.extend(
sess.target
.supported_target_features()
@@ -343,13 +334,16 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
);
// Add enabled features
- for llvm_feature in global_llvm_features(sess, false) {
- let (add, llvm_feature) = llvm_feature.split_at(1);
- let feature =
- rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature));
- if add == "+" {
+ for (enabled, feature) in
+ sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
+ Some('+') => Some((true, Symbol::intern(&s[1..]))),
+ Some('-') => Some((false, Symbol::intern(&s[1..]))),
+ _ => None,
+ })
+ {
+ if enabled {
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
- } else if add == "-" {
+ } else {
features.remove(&feature);
}
}
@@ -475,7 +469,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
require_inited();
- let tm = create_informational_target_machine(sess, true);
+ let tm = create_informational_target_machine(sess, false);
match req.kind {
PrintKind::TargetCPUs => {
// SAFETY generate a C compatible string from a byte slice to pass
@@ -523,7 +517,11 @@ pub fn target_cpu(sess: &Session) -> &str {
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
-pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec {
+pub(crate) fn global_llvm_features(
+ sess: &Session,
+ diagnostics: bool,
+ only_base_features: bool,
+) -> Vec {
// Features that come earlier are overridden by conflicting features later in the string.
// Typically we'll want more explicit settings to override the implicit ones, so:
//
@@ -583,96 +581,109 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec return None,
- Some(c @ ('+' | '-')) => c,
- Some(_) => {
- if diagnostics {
- sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+ if !only_base_features {
+ let supported_features = sess.target.supported_target_features();
+ let (llvm_major, _, _) = get_version();
+ let mut featsmap = FxHashMap::default();
+ let feats = sess
+ .opts
+ .cg
+ .target_feature
+ .split(',')
+ .filter_map(|s| {
+ let enable_disable = match s.chars().next() {
+ None => return None,
+ Some(c @ ('+' | '-')) => c,
+ Some(_) => {
+ if diagnostics {
+ sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+ }
+ return None;
}
- return None;
- }
- };
+ };
- let feature = backend_feature_name(sess, s)?;
- // Warn against use of LLVM specific feature names and unstable features on the CLI.
- if diagnostics {
- let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
- if feature_state.is_none() {
- let rust_feature =
- supported_features.iter().find_map(|&(rust_feature, _, _)| {
- let llvm_features = to_llvm_features(sess, rust_feature);
- if llvm_features.contains(feature)
- && !llvm_features.contains(rust_feature)
- {
- Some(rust_feature)
- } else {
- None
+ let feature = backend_feature_name(sess, s)?;
+ // Warn against use of LLVM specific feature names and unstable features on the CLI.
+ if diagnostics {
+ let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
+ if feature_state.is_none() {
+ let rust_feature =
+ supported_features.iter().find_map(|&(rust_feature, _, _)| {
+ let llvm_features = to_llvm_features(sess, rust_feature);
+ if llvm_features.contains(feature)
+ && !llvm_features.contains(rust_feature)
+ {
+ Some(rust_feature)
+ } else {
+ None
+ }
+ });
+ let unknown_feature = if let Some(rust_feature) = rust_feature {
+ UnknownCTargetFeature {
+ feature,
+ rust_feature: PossibleFeature::Some { rust_feature },
}
- });
- let unknown_feature = if let Some(rust_feature) = rust_feature {
- UnknownCTargetFeature {
- feature,
- rust_feature: PossibleFeature::Some { rust_feature },
- }
- } else {
- UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
- };
- sess.dcx().emit_warn(unknown_feature);
- } else if feature_state
- .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
- {
- // An unstable feature. Warn about using it.
- sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+ } else {
+ UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+ };
+ sess.dcx().emit_warn(unknown_feature);
+ } else if feature_state
+ .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
+ {
+ // An unstable feature. Warn about using it.
+ sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+ }
}
- }
- if diagnostics {
- // FIXME(nagisa): figure out how to not allocate a full hashset here.
- featsmap.insert(feature, enable_disable == '+');
- }
+ if diagnostics {
+ // FIXME(nagisa): figure out how to not allocate a full hashset here.
+ featsmap.insert(feature, enable_disable == '+');
+ }
- // rustc-specific features do not get passed down to LLVM…
- if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
- return None;
- }
+ // rustc-specific features do not get passed down to LLVM…
+ if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+ return None;
+ }
- // if the target-feature is "backchain" and LLVM version is greater than 18
- // then we also need to add "+backchain" to the target-features attribute.
- // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
- if feature == "backchain" && llvm_major < 18 {
- return None;
- }
- // ... otherwise though we run through `to_llvm_features` when
- // passing requests down to LLVM. This means that all in-language
- // features also work on the command line instead of having two
- // different names when the LLVM name and the Rust name differ.
- let llvm_feature = to_llvm_features(sess, feature);
-
- Some(
- std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
- .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
- match (enable_disable, feat) {
+ // if the target-feature is "backchain" and LLVM version is greater than 18
+ // then we also need to add "+backchain" to the target-features attribute.
+ // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
+ if feature == "backchain" && llvm_major < 18 {
+ return None;
+ }
+ // ... otherwise though we run through `to_llvm_features` when
+ // passing requests down to LLVM. This means that all in-language
+ // features also work on the command line instead of having two
+ // different names when the LLVM name and the Rust name differ.
+ let llvm_feature = to_llvm_features(sess, feature);
+
+ Some(
+ std::iter::once(format!(
+ "{}{}",
+ enable_disable, llvm_feature.llvm_feature_name
+ ))
+ .chain(llvm_feature.dependency.into_iter().filter_map(
+ move |feat| match (enable_disable, feat) {
('-' | '+', TargetFeatureFoldStrength::Both(f))
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
Some(format!("{enable_disable}{f}"))
}
_ => None,
- }
- })),
- )
- })
- .flatten();
- features.extend(feats);
+ },
+ )),
+ )
+ })
+ .flatten();
+ features.extend(feats);
+
+ if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+ sess.dcx().emit_err(TargetFeatureDisableOrEnable {
+ features: f,
+ span: None,
+ missing_features: None,
+ });
+ }
+ }
// -Zfixed-x18
if sess.opts.unstable_opts.fixed_x18 {
@@ -683,14 +694,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec
Date: Sun, 4 Aug 2024 01:02:53 -0400
Subject: [PATCH 23/31] Remove redundant implied features
---
compiler/rustc_codegen_llvm/src/llvm_util.rs | 36 ++------------------
compiler/rustc_target/src/target_features.rs | 6 ++--
2 files changed, 6 insertions(+), 36 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 3190853a84c90..10cba179c7564 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -239,40 +239,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
}
// In LLVM neon implicitly enables fp, but we manually enable
// neon when a feature only implicitly enables fp
- ("aarch64", "f32mm") => {
- LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "f64mm") => {
- LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "fhm") => {
- LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "fp16") => {
- LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "jsconv") => {
- LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve") => {
- LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve2") => {
- LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve2-aes") => {
- LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve2-sm4") => {
- LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve2-sha3") => {
- LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
- }
- ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
- "sve2-bitperm",
- TargetFeatureFoldStrength::EnableOnly("neon"),
- ),
+ ("aarch64", "fhm") => LLVMFeature::new("fp16fml"),
+ ("aarch64", "fp16") => LLVMFeature::new("fullfp16"),
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
// `fast-unaligned-access`. In LLVM 19, it was split back out.
("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 63bdcfddfc5f7..746926308b6b4 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -118,13 +118,15 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// FEAT_FLAGM
("flagm", Stable, &[]),
// FEAT_FP16
- ("fp16", Stable, &[]),
+ // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+ ("fp16", Stable, &["neon"]),
// FEAT_FRINTTS
("frintts", Stable, &[]),
// FEAT_I8MM
("i8mm", Stable, &[]),
// FEAT_JSCVT
- ("jsconv", Stable, &[]),
+ // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+ ("jsconv", Stable, &["neon"]),
// FEAT_LOR
("lor", Stable, &[]),
// FEAT_LSE
From 6b96a60611c5edaa107b109b5a50e58a64a33fc2 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Sun, 4 Aug 2024 15:32:17 -0400
Subject: [PATCH 24/31] Add implied features to non-target-feature functions
---
compiler/rustc_codegen_llvm/src/llvm_util.rs | 26 ++++++++++++++++----
tests/codegen/target-feature-overrides.rs | 6 ++---
tests/codegen/tied-features-strength.rs | 2 +-
3 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 10cba179c7564..1a80824a3b70d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -8,6 +8,7 @@ use libc::c_int;
use rustc_codegen_ssa::base::wants_wasm_eh;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::unord::UnordSet;
use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::config::{PrintKind, PrintRequest};
@@ -553,11 +554,26 @@ pub(crate) fn global_llvm_features(
let supported_features = sess.target.supported_target_features();
let (llvm_major, _, _) = get_version();
let mut featsmap = FxHashMap::default();
- let feats = sess
- .opts
- .cg
- .target_feature
- .split(',')
+
+ // insert implied features
+ let mut all_rust_features = vec![];
+ for feature in sess.opts.cg.target_feature.split(',') {
+ match feature.strip_prefix('+') {
+ Some(feature) => all_rust_features.extend(
+ UnordSet::from(
+ sess.target
+ .implied_target_features(std::iter::once(Symbol::intern(feature))),
+ )
+ .to_sorted_stable_ord()
+ .iter()
+ .map(|s| format!("+{}", s.as_str())),
+ ),
+ _ => all_rust_features.push(feature.to_string()),
+ }
+ }
+
+ let feats = all_rust_features
+ .iter()
.filter_map(|s| {
let enable_disable = match s.chars().next() {
None => return None,
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index 5b7489c96cf97..f38a1ae72de5d 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -1,7 +1,7 @@
//@ revisions: COMPAT INCOMPAT
//@ needs-llvm-components: x86
//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
-//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
+//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2
//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
// See also tests/assembly/target-feature-multiple.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
}
// CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx,{{.*}}"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
// CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx,{{.*}}"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 7f0805bc1b435..1b4596ae2cb57 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -8,7 +8,7 @@
// is LLVM-14 we can remove the optional regex matching for this feature.
//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
-// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?))*}}" }
+// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" }
From 83276f568032f14b1af7e5cd9f7d928734af8d09 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Sun, 4 Aug 2024 23:51:59 -0400
Subject: [PATCH 25/31] Hide implicit target features from diagnostics when
possible
---
compiler/rustc_codegen_gcc/src/attributes.rs | 2 +-
compiler/rustc_codegen_llvm/src/attributes.rs | 2 +-
.../rustc_codegen_ssa/src/target_features.rs | 28 ++++++++++++++-----
.../rustc_const_eval/src/interpret/call.rs | 13 +++++++--
.../src/middle/codegen_fn_attrs.rs | 11 +++++++-
.../rustc_mir_build/src/check_unsafety.rs | 26 +++++++++++++----
compiler/rustc_mir_transform/src/inline.rs | 4 ++-
.../simd_feature_flag_difference.stderr | 4 +--
.../fail/function_calls/target_feature.rs | 2 +-
.../fail/function_calls/target_feature.stderr | 4 +--
.../pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 +-
.../pass/shims/x86/intrinsics-x86-avx.rs | 2 +-
.../pass/shims/x86/intrinsics-x86-avx2.rs | 2 +-
.../pass/shims/x86/intrinsics-x86-avx512.rs | 2 +-
.../const-eval/const_fn_target_feature.stderr | 2 +-
.../safe-calls.stderr | 26 ++++++++---------
16 files changed, 89 insertions(+), 43 deletions(-)
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index e521551304ef8..5fdf2680aac88 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
let function_features = codegen_fn_attrs
.target_features
.iter()
- .map(|features| features.as_str())
+ .map(|features| features.name.as_str())
.collect::>();
if let Some(features) = check_tied_features(
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index ad38814a68b6d..876f05c6277c1 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -496,7 +496,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
to_add.extend(tune_cpu_attr(cx));
let function_features =
- codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::>();
+ codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::>();
if let Some(f) = llvm_util::check_tied_features(
cx.tcx.sess,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index c84b844cd0401..145b1ece23007 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -6,6 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
@@ -18,7 +19,7 @@ pub fn from_target_feature(
tcx: TyCtxt<'_>,
attr: &ast::Attribute,
supported_target_features: &UnordMap>,
- target_features: &mut Vec,
+ target_features: &mut Vec,
) {
let Some(list) = attr.meta_item_list() else { return };
let bad_item = |span| {
@@ -99,14 +100,27 @@ pub fn from_target_feature(
}));
}
- // Add both explicit and implied target features, using a set to deduplicate
- let mut target_features_set = UnordSet::new();
+ // Add explicit features
+ target_features.extend(
+ added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
+ );
+
+ // Add implied features
+ let mut implied_target_features = UnordSet::new();
for feature in added_target_features.iter() {
- target_features_set
+ implied_target_features
.extend_unord(tcx.implied_target_features(*feature).clone().into_items());
}
- target_features_set.extend(added_target_features);
- target_features.extend(target_features_set.into_sorted_stable_ord())
+ for feature in added_target_features.iter() {
+ implied_target_features.remove(feature);
+ }
+ target_features.extend(
+ implied_target_features
+ .into_sorted_stable_ord()
+ .iter()
+ .copied()
+ .map(|name| TargetFeature { name, implied: true }),
+ )
}
/// Computes the set of target features used in a function for the purposes of
@@ -115,7 +129,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet {
let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did);
- target_features.extend(&attrs.target_features);
+ target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
match attrs.instruction_set {
None => {}
Some(InstructionSetAttr::ArmA32) => {
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 2c5147678e8cb..e5c195f08d71b 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -317,19 +317,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&& attrs
.target_features
.iter()
- .any(|feature| !self.tcx.sess.target_features.contains(feature))
+ .any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
{
+ // Don't include implicit features in the error, unless only implicit features are
+ // missing. This should be rare, because it can only happen when an implicit feature
+ // is disabled, e.g. `+avx2,-avx`
+ let missing_explicit_features = attrs.target_features.iter().any(|feature| {
+ !feature.implied && !self.tcx.sess.target_features.contains(&feature.name)
+ });
throw_ub_custom!(
fluent::const_eval_unavailable_target_features_for_fn,
unavailable_feats = attrs
.target_features
.iter()
- .filter(|&feature| !self.tcx.sess.target_features.contains(feature))
+ .filter(|&feature| !(missing_explicit_features && feature.implied)
+ && !self.tcx.sess.target_features.contains(&feature.name))
.fold(String::new(), |mut s, feature| {
if !s.is_empty() {
s.push_str(", ");
}
- s.push_str(feature.as_str());
+ s.push_str(feature.name.as_str());
s
}),
);
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index ff6a3a9c12d36..b7d290e58d22b 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
pub link_ordinal: Option,
/// The `#[target_feature(enable = "...")]` attribute and the enabled
/// features (only enabled features are supported right now).
- pub target_features: Vec,
+ pub target_features: Vec,
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
pub linkage: Option,
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -51,6 +51,15 @@ pub struct CodegenFnAttrs {
pub patchable_function_entry: Option,
}
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct TargetFeature {
+ /// The name of the target feature (e.g. "avx")
+ pub name: Symbol,
+ /// The feature is implied by another feature, rather than explicitly added by the
+ /// `#[target_feature]` attribute
+ pub implied: bool,
+}
+
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct PatchableFunctionEntry {
/// Nops to prepend to the function
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 48018fcaa36df..0b4f0632f2b36 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,6 +5,7 @@ use std::ops::Bound;
use rustc_errors::DiagArgValue;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
use rustc_middle::mir::BorrowKind;
use rustc_middle::span_bug;
use rustc_middle::thir::visit::Visitor;
@@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
safety_context: SafetyContext,
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
- body_target_features: &'tcx [Symbol],
+ body_target_features: &'tcx [TargetFeature],
/// When inside the LHS of an assignment to a field, this is the type
/// of the LHS and the span of the assignment expression.
assignment_info: Option>,
@@ -442,14 +443,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
// is_like_wasm check in hir_analysis/src/collect.rs
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
if !self.tcx.sess.target.options.is_like_wasm
- && !callee_features
- .iter()
- .all(|feature| self.body_target_features.contains(feature))
+ && !callee_features.iter().all(|feature| {
+ self.body_target_features.iter().any(|f| f.name == feature.name)
+ })
{
+ // Don't include implicit features in the error, unless only implicit
+ // features are missing.
+ let missing_explicit_features = callee_features.iter().any(|feature| {
+ !feature.implied
+ && !self.body_target_features.iter().any(|body_feature| {
+ !feature.implied && body_feature.name == feature.name
+ })
+ });
let missing: Vec<_> = callee_features
.iter()
.copied()
- .filter(|feature| !self.body_target_features.contains(feature))
+ .filter(|feature| {
+ !(missing_explicit_features && feature.implied)
+ && !self
+ .body_target_features
+ .iter()
+ .any(|body_feature| body_feature.name == feature.name)
+ })
+ .map(|feature| feature.name)
.collect();
let build_enabled = self
.tcx
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f30732e6aaf3b..0f012242c3738 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
return Err("incompatible instruction set");
}
- if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
+ let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
+ let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
+ if callee_feature_names.ne(this_feature_names) {
// In general it is not correct to inline a callee with target features that are a
// subset of the caller. This is because the callee might contain calls, and the ABI of
// those calls depends on the target features of the surrounding function. By moving a
diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
index 8ebd5d2726ffd..2544421c7e8c7 100644
--- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
+++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
+error: Undefined Behavior: calling a function that requires unavailable target features: avx
--> $DIR/simd_feature_flag_difference.rs:LL:CC
|
LL | unsafe { foo(0.0, x) }
- | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
+ | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs
index 713d7c16f4c25..84e01eb4803fe 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.rs
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs
@@ -4,7 +4,7 @@
fn main() {
assert!(!is_x86_feature_detected!("ssse3"));
unsafe {
- ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3
+ ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
}
}
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
index 74a862c7b681c..4d3cf6e9d3bc0 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3
+error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
--> $DIR/target_feature.rs:LL:CC
|
LL | ssse3_fn();
- | ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3
+ | ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
index 13ebe56146381..7363c75361779 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2
+//@compile-flags: -C target-feature=+aes,+vaes,+avx512f
#![feature(avx512_target_feature, stdarch_x86_avx512)]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
index 18693a2a97d11..728f57d48f17e 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx,+sse4.2
+//@compile-flags: -C target-feature=+avx
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
index f42ff6dfb51b2..80d125bb85650 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx2,+sse4.2
+//@compile-flags: -C target-feature=+avx2
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
index 7d25854ccc075..66bfcb20f1c99 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
@@ -7,7 +7,7 @@
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2
+//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
#![feature(avx512_target_feature)]
#![feature(stdarch_x86_avx512)]
diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
index ad40d733546af..d3a00b57ebb50 100644
--- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr
+++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/const_fn_target_feature.rs:11:24
|
LL | const B: () = unsafe { avx2_fn() };
- | ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2
+ | ^^^^^^^^^ calling a function that requires unavailable target features: avx2
error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
index c2227f8e84783..1ddf05b40a606 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
@@ -4,8 +4,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
- = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+ = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:29:5
@@ -13,8 +13,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
- = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:31:5
@@ -22,8 +21,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
- = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:38:5
@@ -31,7 +29,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
+ = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:40:5
@@ -39,7 +37,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
+ = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:47:5
@@ -63,8 +61,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
LL | const _: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
- = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+ = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:64:15
@@ -72,8 +70,8 @@ error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsaf
LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
- = help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr
- = note: the fxsr, sse, and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
+ = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
--> $DIR/safe-calls.rs:69:5
@@ -82,8 +80,8 @@ LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: for more information, see issue #71668
- = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
- = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+ = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+ = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/safe-calls.rs:68:1
|
From 0b98a0c72769c2549827ec2320beb5478ca3c335 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Mon, 5 Aug 2024 10:31:03 -0400
Subject: [PATCH 26/31] Fix typo
Co-authored-by: Amanieu d'Antras
---
compiler/rustc_target/src/target_features.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 746926308b6b4..da66ba270b33c 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -335,7 +335,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("zkne", Stable, &[]),
("zknh", Stable, &[]),
("zkr", Stable, &[]),
- ("zks", Stable, &["zbkb", "bzkc", "zbkx", "zksed", "zksh"]),
+ ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
("zksed", Stable, &[]),
("zksh", Stable, &[]),
("zkt", Stable, &[]),
From 8818c9552821721e4be5c19832b4e3ac64090feb Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Tue, 6 Aug 2024 00:35:32 -0400
Subject: [PATCH 27/31] Disallow enabling features without their implied
features
---
compiler/rustc_codegen_llvm/src/llvm_util.rs | 6 ++++--
compiler/rustc_codegen_ssa/src/target_features.rs | 8 ++++----
compiler/rustc_const_eval/src/interpret/call.rs | 8 +-------
compiler/rustc_middle/src/query/mod.rs | 2 +-
compiler/rustc_mir_build/src/check_unsafety.rs | 10 +---------
5 files changed, 11 insertions(+), 23 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 1a80824a3b70d..9fd8ca43789dd 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -277,7 +277,7 @@ pub fn check_tied_features(
/// Used to generate cfg variables and apply features
/// Must express features in the way Rust understands them
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
- let mut features = FxHashSet::default();
+ let mut features = vec![];
// Add base features for the target
let target_machine = create_informational_target_machine(sess, true);
@@ -313,7 +313,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec {
if enabled {
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
} else {
- features.remove(&feature);
+ features.retain(|f| {
+ !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
+ });
}
}
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 145b1ece23007..cf8f7fa25d856 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,7 +1,7 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
@@ -108,8 +108,7 @@ pub fn from_target_feature(
// Add implied features
let mut implied_target_features = UnordSet::new();
for feature in added_target_features.iter() {
- implied_target_features
- .extend_unord(tcx.implied_target_features(*feature).clone().into_items());
+ implied_target_features.extend(tcx.implied_target_features(*feature).clone());
}
for feature in added_target_features.iter() {
implied_target_features.remove(feature);
@@ -179,7 +178,8 @@ pub(crate) fn provide(providers: &mut Providers) {
}
},
implied_target_features: |tcx, feature| {
- tcx.sess.target.implied_target_features(std::iter::once(feature)).into()
+ UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
+ .into_sorted_stable_ord()
},
asm_target_features,
..*providers
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index e5c195f08d71b..b5f3d07d90b35 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -319,18 +319,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.iter()
.any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
{
- // Don't include implicit features in the error, unless only implicit features are
- // missing. This should be rare, because it can only happen when an implicit feature
- // is disabled, e.g. `+avx2,-avx`
- let missing_explicit_features = attrs.target_features.iter().any(|feature| {
- !feature.implied && !self.tcx.sess.target_features.contains(&feature.name)
- });
throw_ub_custom!(
fluent::const_eval_unavailable_target_features_for_fn,
unavailable_feats = attrs
.target_features
.iter()
- .filter(|&feature| !(missing_explicit_features && feature.implied)
+ .filter(|&feature| !feature.implied
&& !self.tcx.sess.target_features.contains(&feature.name))
.fold(String::new(), |mut s, feature| {
if !s.is_empty() {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b6a2943265034..5b114c9515c19 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2183,7 +2183,7 @@ rustc_queries! {
desc { "looking up supported target features" }
}
- query implied_target_features(feature: Symbol) -> &'tcx UnordSet {
+ query implied_target_features(feature: Symbol) -> &'tcx Vec {
arena_cache
eval_always
desc { "looking up implied target features" }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 0b4f0632f2b36..54a4204da71e8 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -447,19 +447,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
self.body_target_features.iter().any(|f| f.name == feature.name)
})
{
- // Don't include implicit features in the error, unless only implicit
- // features are missing.
- let missing_explicit_features = callee_features.iter().any(|feature| {
- !feature.implied
- && !self.body_target_features.iter().any(|body_feature| {
- !feature.implied && body_feature.name == feature.name
- })
- });
let missing: Vec<_> = callee_features
.iter()
.copied()
.filter(|feature| {
- !(missing_explicit_features && feature.implied)
+ !feature.implied
&& !self
.body_target_features
.iter()
From d1d21ede82614f2b575cb16bcbabe75183721740 Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz
Date: Wed, 7 Aug 2024 09:56:28 +0200
Subject: [PATCH 28/31] rustc_codegen_ssa: Set architecture for object crate
for 32-bit SPARC
The object crate was recently updated to recognize the 32-bit SPARC
ELF targets EM_SPARC and EM_SPARC32PLUS, so the proper architecture
for 32-bit SPARC can now be set in rustc_codegen_ssa.
---
compiler/rustc_codegen_ssa/src/back/metadata.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 19394029c949a..9b5a797ad5106 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -208,6 +208,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option (Architecture::PowerPc64, None),
"riscv32" => (Architecture::Riscv32, None),
"riscv64" => (Architecture::Riscv64, None),
+ "sparc" => (Architecture::Sparc32Plus, None),
"sparc64" => (Architecture::Sparc64, None),
"avr" => (Architecture::Avr, None),
"msp430" => (Architecture::Msp430, None),
From c1897960c016d7296b945175b0fef9546f6326a6 Mon Sep 17 00:00:00 2001
From: Ralf Jung
Date: Wed, 7 Aug 2024 15:29:00 +0200
Subject: [PATCH 29/31] unused_parens: do not lint against parens around &raw
---
compiler/rustc_lint/src/unused.rs | 7 ++
tests/ui/lint/lint-unnecessary-parens.fixed | 8 ++
tests/ui/lint/lint-unnecessary-parens.rs | 8 ++
tests/ui/lint/lint-unnecessary-parens.stderr | 88 +++++++++++++-------
4 files changed, 79 insertions(+), 32 deletions(-)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 795333224ba00..e2c05129ee238 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -675,6 +675,13 @@ trait UnusedDelimLint {
return true;
}
+ // Do not lint against parentheses around `&raw [const|mut] expr`.
+ // These parentheses will have to be added e.g. when calling a method on the result of this
+ // expression, and we want to avoid churn wrt adding and removing parentheses.
+ if matches!(inner.kind, ast::ExprKind::AddrOf(ast::BorrowKind::Raw, ..)) {
+ return true;
+ }
+
// Check if LHS needs parens to prevent false-positives in cases like
// `fn x() -> u8 { ({ 0 } + 1) }`.
//
diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed
index 760897c5143f1..089aa1b7ab7de 100644
--- a/tests/ui/lint/lint-unnecessary-parens.fixed
+++ b/tests/ui/lint/lint-unnecessary-parens.fixed
@@ -1,6 +1,7 @@
//@ run-rustfix
#![deny(unused_parens)]
+#![feature(raw_ref_op)]
#![allow(while_true)] // for rustfix
#[derive(Eq, PartialEq)]
@@ -125,4 +126,11 @@ fn main() {
// FIXME: false positive. This parenthesis is required.
unit! {} - One //~ ERROR unnecessary parentheses around block return value
};
+
+ // Do *not* lint around `&raw` (but do lint when `&` creates a reference).
+ let mut x = 0;
+ let _r = &x; //~ ERROR unnecessary parentheses
+ let _r = &mut x; //~ ERROR unnecessary parentheses
+ let _r = (&raw const x);
+ let _r = (&raw mut x);
}
diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs
index 7cbaac8ae5403..dc77ee003523e 100644
--- a/tests/ui/lint/lint-unnecessary-parens.rs
+++ b/tests/ui/lint/lint-unnecessary-parens.rs
@@ -1,6 +1,7 @@
//@ run-rustfix
#![deny(unused_parens)]
+#![feature(raw_ref_op)]
#![allow(while_true)] // for rustfix
#[derive(Eq, PartialEq)]
@@ -125,4 +126,11 @@ fn main() {
// FIXME: false positive. This parenthesis is required.
(unit! {} - One) //~ ERROR unnecessary parentheses around block return value
};
+
+ // Do *not* lint around `&raw` (but do lint when `&` creates a reference).
+ let mut x = 0;
+ let _r = (&x); //~ ERROR unnecessary parentheses
+ let _r = (&mut x); //~ ERROR unnecessary parentheses
+ let _r = (&raw const x);
+ let _r = (&raw mut x);
}
diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr
index 755dd5fc3094b..c9422437a9fcd 100644
--- a/tests/ui/lint/lint-unnecessary-parens.stderr
+++ b/tests/ui/lint/lint-unnecessary-parens.stderr
@@ -1,5 +1,5 @@
error: unnecessary parentheses around `return` value
- --> $DIR/lint-unnecessary-parens.rs:13:12
+ --> $DIR/lint-unnecessary-parens.rs:14:12
|
LL | return (1);
| ^ ^
@@ -16,7 +16,7 @@ LL + return 1;
|
error: unnecessary parentheses around `return` value
- --> $DIR/lint-unnecessary-parens.rs:16:12
+ --> $DIR/lint-unnecessary-parens.rs:17:12
|
LL | return (X { y });
| ^ ^
@@ -28,7 +28,7 @@ LL + return X { y };
|
error: unnecessary parentheses around type
- --> $DIR/lint-unnecessary-parens.rs:19:46
+ --> $DIR/lint-unnecessary-parens.rs:20:46
|
LL | pub fn unused_parens_around_return_type() -> (u32) {
| ^ ^
@@ -40,7 +40,7 @@ LL + pub fn unused_parens_around_return_type() -> u32 {
|
error: unnecessary parentheses around block return value
- --> $DIR/lint-unnecessary-parens.rs:25:9
+ --> $DIR/lint-unnecessary-parens.rs:26:9
|
LL | (5)
| ^ ^
@@ -52,7 +52,7 @@ LL + 5
|
error: unnecessary parentheses around block return value
- --> $DIR/lint-unnecessary-parens.rs:27:5
+ --> $DIR/lint-unnecessary-parens.rs:28:5
|
LL | (5)
| ^ ^
@@ -64,7 +64,7 @@ LL + 5
|
error: unnecessary parentheses around `if` condition
- --> $DIR/lint-unnecessary-parens.rs:39:7
+ --> $DIR/lint-unnecessary-parens.rs:40:7
|
LL | if(true) {}
| ^ ^
@@ -76,7 +76,7 @@ LL + if true {}
|
error: unnecessary parentheses around `while` condition
- --> $DIR/lint-unnecessary-parens.rs:40:10
+ --> $DIR/lint-unnecessary-parens.rs:41:10
|
LL | while(true) {}
| ^ ^
@@ -88,7 +88,7 @@ LL + while true {}
|
error: unnecessary parentheses around `for` iterator expression
- --> $DIR/lint-unnecessary-parens.rs:41:13
+ --> $DIR/lint-unnecessary-parens.rs:42:13
|
LL | for _ in(e) {}
| ^ ^
@@ -100,7 +100,7 @@ LL + for _ in e {}
|
error: unnecessary parentheses around `match` scrutinee expression
- --> $DIR/lint-unnecessary-parens.rs:42:10
+ --> $DIR/lint-unnecessary-parens.rs:43:10
|
LL | match(1) { _ => ()}
| ^ ^
@@ -112,7 +112,7 @@ LL + match 1 { _ => ()}
|
error: unnecessary parentheses around `return` value
- --> $DIR/lint-unnecessary-parens.rs:43:11
+ --> $DIR/lint-unnecessary-parens.rs:44:11
|
LL | return(1);
| ^ ^
@@ -124,7 +124,7 @@ LL + return 1;
|
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:74:31
+ --> $DIR/lint-unnecessary-parens.rs:75:31
|
LL | pub const CONST_ITEM: usize = (10);
| ^ ^
@@ -136,7 +136,7 @@ LL + pub const CONST_ITEM: usize = 10;
|
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:75:33
+ --> $DIR/lint-unnecessary-parens.rs:76:33
|
LL | pub static STATIC_ITEM: usize = (10);
| ^ ^
@@ -148,7 +148,7 @@ LL + pub static STATIC_ITEM: usize = 10;
|
error: unnecessary parentheses around function argument
- --> $DIR/lint-unnecessary-parens.rs:79:9
+ --> $DIR/lint-unnecessary-parens.rs:80:9
|
LL | bar((true));
| ^ ^
@@ -160,7 +160,7 @@ LL + bar(true);
|
error: unnecessary parentheses around `if` condition
- --> $DIR/lint-unnecessary-parens.rs:81:8
+ --> $DIR/lint-unnecessary-parens.rs:82:8
|
LL | if (true) {}
| ^ ^
@@ -172,7 +172,7 @@ LL + if true {}
|
error: unnecessary parentheses around `while` condition
- --> $DIR/lint-unnecessary-parens.rs:82:11
+ --> $DIR/lint-unnecessary-parens.rs:83:11
|
LL | while (true) {}
| ^ ^
@@ -184,7 +184,7 @@ LL + while true {}
|
error: unnecessary parentheses around `match` scrutinee expression
- --> $DIR/lint-unnecessary-parens.rs:83:11
+ --> $DIR/lint-unnecessary-parens.rs:84:11
|
LL | match (true) {
| ^ ^
@@ -196,7 +196,7 @@ LL + match true {
|
error: unnecessary parentheses around `let` scrutinee expression
- --> $DIR/lint-unnecessary-parens.rs:86:16
+ --> $DIR/lint-unnecessary-parens.rs:87:16
|
LL | if let 1 = (1) {}
| ^ ^
@@ -208,7 +208,7 @@ LL + if let 1 = 1 {}
|
error: unnecessary parentheses around `let` scrutinee expression
- --> $DIR/lint-unnecessary-parens.rs:87:19
+ --> $DIR/lint-unnecessary-parens.rs:88:19
|
LL | while let 1 = (2) {}
| ^ ^
@@ -220,7 +220,7 @@ LL + while let 1 = 2 {}
|
error: unnecessary parentheses around method argument
- --> $DIR/lint-unnecessary-parens.rs:103:24
+ --> $DIR/lint-unnecessary-parens.rs:104:24
|
LL | X { y: false }.foo((true));
| ^ ^
@@ -232,7 +232,7 @@ LL + X { y: false }.foo(true);
|
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:105:18
+ --> $DIR/lint-unnecessary-parens.rs:106:18
|
LL | let mut _a = (0);
| ^ ^
@@ -244,7 +244,7 @@ LL + let mut _a = 0;
|
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:106:10
+ --> $DIR/lint-unnecessary-parens.rs:107:10
|
LL | _a = (0);
| ^ ^
@@ -256,7 +256,7 @@ LL + _a = 0;
|
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:107:11
+ --> $DIR/lint-unnecessary-parens.rs:108:11
|
LL | _a += (1);
| ^ ^
@@ -268,7 +268,7 @@ LL + _a += 1;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:109:8
+ --> $DIR/lint-unnecessary-parens.rs:110:8
|
LL | let(mut _a) = 3;
| ^ ^
@@ -280,7 +280,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:110:9
+ --> $DIR/lint-unnecessary-parens.rs:111:9
|
LL | let (mut _a) = 3;
| ^ ^
@@ -292,7 +292,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:111:8
+ --> $DIR/lint-unnecessary-parens.rs:112:8
|
LL | let( mut _a) = 3;
| ^^ ^
@@ -304,7 +304,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:113:8
+ --> $DIR/lint-unnecessary-parens.rs:114:8
|
LL | let(_a) = 3;
| ^ ^
@@ -316,7 +316,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:114:9
+ --> $DIR/lint-unnecessary-parens.rs:115:9
|
LL | let (_a) = 3;
| ^ ^
@@ -328,7 +328,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around pattern
- --> $DIR/lint-unnecessary-parens.rs:115:8
+ --> $DIR/lint-unnecessary-parens.rs:116:8
|
LL | let( _a) = 3;
| ^^ ^
@@ -340,7 +340,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around block return value
- --> $DIR/lint-unnecessary-parens.rs:121:9
+ --> $DIR/lint-unnecessary-parens.rs:122:9
|
LL | (unit!() - One)
| ^ ^
@@ -352,7 +352,7 @@ LL + unit!() - One
|
error: unnecessary parentheses around block return value
- --> $DIR/lint-unnecessary-parens.rs:123:9
+ --> $DIR/lint-unnecessary-parens.rs:124:9
|
LL | (unit![] - One)
| ^ ^
@@ -364,7 +364,7 @@ LL + unit![] - One
|
error: unnecessary parentheses around block return value
- --> $DIR/lint-unnecessary-parens.rs:126:9
+ --> $DIR/lint-unnecessary-parens.rs:127:9
|
LL | (unit! {} - One)
| ^ ^
@@ -375,5 +375,29 @@ LL - (unit! {} - One)
LL + unit! {} - One
|
-error: aborting due to 31 previous errors
+error: unnecessary parentheses around assigned value
+ --> $DIR/lint-unnecessary-parens.rs:132:14
+ |
+LL | let _r = (&x);
+ | ^ ^
+ |
+help: remove these parentheses
+ |
+LL - let _r = (&x);
+LL + let _r = &x;
+ |
+
+error: unnecessary parentheses around assigned value
+ --> $DIR/lint-unnecessary-parens.rs:133:14
+ |
+LL | let _r = (&mut x);
+ | ^ ^
+ |
+help: remove these parentheses
+ |
+LL - let _r = (&mut x);
+LL + let _r = &mut x;
+ |
+
+error: aborting due to 33 previous errors
From 8c06dc4dda857ce988c35f6207e53edd1502f74b Mon Sep 17 00:00:00 2001
From: bohan
Date: Tue, 6 Aug 2024 19:27:15 +0800
Subject: [PATCH 30/31] make `import.vis` is not mutable
---
.../rustc_resolve/src/build_reduced_graph.rs | 10 +--
compiler/rustc_resolve/src/check_unused.rs | 2 +-
compiler/rustc_resolve/src/diagnostics.rs | 23 +++---
compiler/rustc_resolve/src/ident.rs | 70 +++++++++++++++----
compiler/rustc_resolve/src/imports.rs | 53 +++++++-------
compiler/rustc_resolve/src/late.rs | 3 +-
.../rustc_resolve/src/late/diagnostics.rs | 1 +
compiler/rustc_resolve/src/lib.rs | 3 +-
compiler/rustc_resolve/src/macros.rs | 27 +++++--
9 files changed, 129 insertions(+), 63 deletions(-)
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2fa3692bb289f..307625bcfb17c 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -283,6 +283,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
parent_scope,
finalize.then(|| Finalize::new(id, path.span)),
None,
+ None,
) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
let res = module.res().expect("visibility resolved to unnamed block");
@@ -372,7 +373,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
has_attributes: !item.attrs.is_empty(),
root_span,
root_id,
- vis: Cell::new(Some(vis)),
+ vis,
used: Default::default(),
});
@@ -888,7 +889,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
root_span: item.span,
span: item.span,
module_path: Vec::new(),
- vis: Cell::new(Some(vis)),
+ vis,
used: Cell::new(used.then_some(Used::Other)),
});
self.r.potentially_unused_imports.push(import);
@@ -1089,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
root_span: span,
span,
module_path: Vec::new(),
- vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
+ vis: ty::Visibility::Restricted(CRATE_DEF_ID),
used: Default::default(),
})
};
@@ -1125,6 +1126,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ident,
MacroNS,
&self.parent_scope,
+ None,
);
if let Ok(binding) = result {
let import = macro_use_import(self, ident.span, false);
@@ -1253,7 +1255,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
root_span: span,
span,
module_path: Vec::new(),
- vis: Cell::new(Some(vis)),
+ vis,
used: Cell::new(Some(Used::Other)),
});
let import_binding = self.r.import(binding, import);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index a819997156105..75b8ecebdd914 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -382,7 +382,7 @@ impl Resolver<'_, '_> {
for import in self.potentially_unused_imports.iter() {
match import.kind {
_ if import.used.get().is_some()
- || import.expect_vis().is_public()
+ || import.vis.is_public()
|| import.span.is_dummy() =>
{
if let ImportKind::MacroUse { .. } = import.kind {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 8080bb60e415e..942026ef01223 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1052,6 +1052,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
false,
false,
+ None,
) {
suggestions.extend(
ext.helper_attrs
@@ -1506,6 +1507,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
false,
None,
+ None,
) {
let desc = match binding.res() {
Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
@@ -1983,6 +1985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
ribs: Option<&PerNS>>>,
ignore_binding: Option>,
+ ignore_import: Option>,
module: Option>,
failed_segment_idx: usize,
ident: Ident,
@@ -2066,11 +2069,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
None,
ignore_binding,
+ ignore_import,
)
.ok()
} else if let Some(ribs) = ribs
&& let Some(TypeNS | ValueNS) = opt_ns
{
+ assert!(ignore_import.is_none());
match self.resolve_ident_in_lexical_scope(
ident,
ns_to_try,
@@ -2091,6 +2096,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
false,
ignore_binding,
+ ignore_import,
)
.ok()
};
@@ -2132,6 +2138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
// Check whether the name refers to an item in the value namespace.
let binding = if let Some(ribs) = ribs {
+ assert!(ignore_import.is_none());
self.resolve_ident_in_lexical_scope(
ident,
ValueNS,
@@ -2206,6 +2213,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
false,
ignore_binding,
+ ignore_import,
) {
let descr = binding.res().descr();
(format!("{descr} `{ident}` is not a crate or module"), suggestion)
@@ -2259,7 +2267,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) -> Option<(Vec, Option)> {
// Replace first ident with `self` and check if that is valid.
path[0].ident.name = kw::SelfLower;
- let result = self.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope, None);
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -2278,7 +2286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) -> Option<(Vec, Option)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = kw::Crate;
- let result = self.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope, None);
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
Some((
@@ -2309,7 +2317,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) -> Option<(Vec, Option)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = kw::Super;
- let result = self.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope, None);
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -2343,7 +2351,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
for name in extern_crate_names.into_iter() {
// Replace first ident with a crate name and check if that is valid.
path[0].ident.name = name;
- let result = self.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope, None);
debug!(
"make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result
@@ -2509,12 +2517,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
/// Finds a cfg-ed out item inside `module` with the matching name.
- pub(crate) fn find_cfg_stripped(
- &mut self,
- err: &mut Diag<'_>,
- segment: &Symbol,
- module: DefId,
- ) {
+ pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
let local_items;
let symbols = if module.is_local() {
local_items = self
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 947ba569ab0e2..149c639efab86 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -14,6 +14,7 @@ use Determinacy::*;
use Namespace::*;
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
+use crate::imports::Import;
use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
use crate::macros::{sub_namespace_match, MacroRulesScope};
use crate::{
@@ -351,6 +352,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding,
+ None,
);
if let Ok(binding) = item {
// The ident resolves to an item.
@@ -364,6 +366,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize,
finalize.is_some(),
ignore_binding,
+ None,
)
.ok()
.map(LexicalScopeBinding::Item)
@@ -383,6 +386,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize: Option,
force: bool,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> Result, Determinacy> {
bitflags::bitflags! {
#[derive(Clone, Copy)]
@@ -455,6 +459,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
true,
force,
+ ignore_import,
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
@@ -496,6 +501,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
finalize,
ignore_binding,
+ ignore_import,
);
match binding {
Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -518,6 +524,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
!matches!(scope_set, ScopeSet::Late(..)),
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding,
+ ignore_import,
);
match binding {
Ok(binding) => {
@@ -585,6 +592,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
None,
ignore_binding,
+ ignore_import,
) {
if matches!(use_prelude, UsePrelude::Yes)
|| this.is_builtin_macro(binding.res())
@@ -738,8 +746,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ident: Ident,
ns: Namespace,
parent_scope: &ParentScope<'a>,
+ ignore_import: Option>,
) -> Result, Determinacy> {
- self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
+ self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import)
.map_err(|(determinacy, _)| determinacy)
}
@@ -752,9 +761,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
finalize: Option,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> Result, Determinacy> {
- self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
- .map_err(|(determinacy, _)| determinacy)
+ self.resolve_ident_in_module_ext(
+ module,
+ ident,
+ ns,
+ parent_scope,
+ finalize,
+ ignore_binding,
+ ignore_import,
+ )
+ .map_err(|(determinacy, _)| determinacy)
}
#[instrument(level = "debug", skip(self))]
@@ -766,6 +784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
finalize: Option,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> Result, (Determinacy, Weak)> {
let tmp_parent_scope;
let mut adjusted_parent_scope = parent_scope;
@@ -792,6 +811,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
false,
finalize,
ignore_binding,
+ ignore_import,
)
}
@@ -804,6 +824,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
finalize: Option,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> Result, Determinacy> {
self.resolve_ident_in_module_unadjusted_ext(
module,
@@ -813,6 +834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
false,
finalize,
ignore_binding,
+ ignore_import,
)
.map_err(|(determinacy, _)| determinacy)
}
@@ -831,6 +853,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// This binding should be ignored during in-module resolution, so that we don't get
// "self-confirming" import resolutions during import validation and checking.
ignore_binding: Option>,
+ ignore_import: Option>,
) -> Result, (Determinacy, Weak)> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
@@ -843,6 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize,
finalize.is_some(),
ignore_binding,
+ ignore_import,
);
return binding.map_err(|determinacy| (determinacy, Weak::No));
}
@@ -879,6 +903,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize,
finalize.is_some(),
ignore_binding,
+ ignore_import,
);
return binding.map_err(|determinacy| (determinacy, Weak::No));
}
@@ -962,25 +987,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Check if one of single imports can still define the name,
// if it can then our result is not determined and can be invalidated.
for single_import in &resolution.single_imports {
- let Some(import_vis) = single_import.vis.get() else {
- // This branch handles a cycle in single imports, which occurs
- // when we've previously **steal** the `vis` value during an import
- // process.
+ if ignore_import == Some(*single_import) {
+ // This branch handles a cycle in single imports.
//
// For example:
// ```
// use a::b;
// use b as a;
// ```
- // 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the
+ // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the
// current module.
// 2. Encounter the import `use b as a`, which is a `single_import` for `a`,
// and try to find `b` in the current module.
// 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`.
// This leads to entering this branch.
continue;
- };
- if !self.is_accessible_from(import_vis, parent_scope.module) {
+ }
+ if !self.is_accessible_from(single_import.vis, parent_scope.module) {
continue;
}
if let Some(ignored) = ignore_binding
@@ -1022,6 +1045,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&single_import.parent_scope,
None,
ignore_binding,
+ ignore_import,
) {
Err(Determined) => continue,
Ok(binding)
@@ -1070,10 +1094,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Check if one of glob imports can still define the name,
// if it can then our "no resolution" result is not determined and can be invalidated.
for glob_import in module.globs.borrow().iter() {
- let Some(import_vis) = glob_import.vis.get() else {
+ if ignore_import == Some(*glob_import) {
continue;
- };
- if !self.is_accessible_from(import_vis, parent_scope.module) {
+ }
+ if !self.is_accessible_from(glob_import.vis, parent_scope.module) {
continue;
}
let module = match glob_import.imported_module.get() {
@@ -1100,6 +1124,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
adjusted_parent_scope,
None,
ignore_binding,
+ ignore_import,
);
match result {
@@ -1412,8 +1437,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path: &[Segment],
opt_ns: Option, // `None` indicates a module path in import
parent_scope: &ParentScope<'a>,
+ ignore_import: Option>,
) -> PathResult<'a> {
- self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
+ self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import)
}
#[instrument(level = "debug", skip(self))]
@@ -1424,8 +1450,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
finalize: Option,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> PathResult<'a> {
- self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
+ self.resolve_path_with_ribs(
+ path,
+ opt_ns,
+ parent_scope,
+ finalize,
+ None,
+ ignore_binding,
+ ignore_import,
+ )
}
pub(crate) fn resolve_path_with_ribs(
@@ -1436,6 +1471,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize: Option,
ribs: Option<&PerNS>>>,
ignore_binding: Option>,
+ ignore_import: Option>,
) -> PathResult<'a> {
let mut module = None;
let mut allow_super = true;
@@ -1538,10 +1574,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
finalize,
ignore_binding,
+ ignore_import,
)
} else if let Some(ribs) = ribs
&& let Some(TypeNS | ValueNS) = opt_ns
{
+ assert!(ignore_import.is_none());
match self.resolve_ident_in_lexical_scope(
ident,
ns,
@@ -1570,6 +1608,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
finalize,
finalize.is_some(),
ignore_binding,
+ ignore_import,
)
};
@@ -1644,6 +1683,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
ribs,
ignore_binding,
+ ignore_import,
module,
segment_idx,
ident,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index c7af21027b8d3..4a891d12281c4 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -175,7 +175,7 @@ pub(crate) struct ImportData<'a> {
pub module_path: Vec,
/// The resolution of `module_path`.
pub imported_module: Cell>>,
- pub vis: Cell >,
+ pub vis: ty::Visibility,
pub used: Cell >,
}
@@ -195,10 +195,6 @@ impl<'a> ImportData<'a> {
}
}
- pub(crate) fn expect_vis(&self) -> ty::Visibility {
- self.vis.get().expect("encountered cleared import visibility")
- }
-
pub(crate) fn id(&self) -> Option {
match self.kind {
ImportKind::Single { id, .. }
@@ -267,7 +263,7 @@ fn pub_use_of_private_extern_crate_hack(
match (&import.kind, &binding.kind) {
(ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. })
if let ImportKind::ExternCrate { id, .. } = binding_import.kind
- && import.expect_vis().is_public() =>
+ && import.vis.is_public() =>
{
Some(id)
}
@@ -279,7 +275,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Given a binding and an import that resolves to it,
/// return the corresponding binding defined by the import.
pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> {
- let import_vis = import.expect_vis().to_def_id();
+ let import_vis = import.vis.to_def_id();
let vis = if binding.vis.is_at_least(import_vis, self.tcx)
|| pub_use_of_private_extern_crate_hack(import, binding).is_some()
{
@@ -773,11 +769,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let module = if let Some(module) = import.imported_module.get() {
module
} else {
- // For better failure detection, pretend that the import will
- // not define any names while resolving its module path.
- let orig_vis = import.vis.take();
- let path_res = self.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
- import.vis.set(orig_vis);
+ let path_res = self.maybe_resolve_path(
+ &import.module_path,
+ None,
+ &import.parent_scope,
+ Some(import),
+ );
match path_res {
PathResult::Module(module) => module,
@@ -807,16 +804,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
if let Err(Undetermined) = source_bindings[ns].get() {
- // For better failure detection, pretend that the import will
- // not define any names while resolving its module path.
- let orig_vis = import.vis.take();
let binding = this.maybe_resolve_ident_in_module(
module,
source,
ns,
&import.parent_scope,
+ Some(import),
);
- import.vis.set(orig_vis);
source_bindings[ns].set(binding);
} else {
return;
@@ -855,7 +849,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Optionally returns an unresolved import error. This error is buffered and used to
/// consolidate multiple unresolved import errors into a single diagnostic.
fn finalize_import(&mut self, import: Import<'a>) -> Option {
- let orig_vis = import.vis.take();
let ignore_binding = match &import.kind {
ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
_ => None,
@@ -874,11 +867,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&import.parent_scope,
Some(finalize),
ignore_binding,
+ Some(import),
);
let no_ambiguity =
ambiguity_errors_len(&self.ambiguity_errors) == prev_ambiguity_errors_len;
- import.vis.set(orig_vis);
+
let module = match path_res {
PathResult::Module(module) => {
// Consistency checks, analogous to `finalize_macro_resolutions`.
@@ -1013,8 +1007,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
if !is_prelude
&& let Some(max_vis) = max_vis.get()
- && let import_vis = import.expect_vis()
- && !max_vis.is_at_least(import_vis, self.tcx)
+ && !max_vis.is_at_least(import.vis, self.tcx)
{
let def_id = self.local_def_id(id);
self.lint_buffer.buffer_lint(
@@ -1023,7 +1016,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
import.span,
BuiltinLintDiag::RedundantImportVisibility {
max_vis: max_vis.to_string(def_id, self.tcx),
- import_vis: import_vis.to_string(def_id, self.tcx),
+ import_vis: import.vis.to_string(def_id, self.tcx),
span: import.span,
},
);
@@ -1038,9 +1031,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// importing it if available.
let mut path = import.module_path.clone();
path.push(Segment::from_ident(ident));
- if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
- self.resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_binding)
- {
+ if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
+ &path,
+ None,
+ &import.parent_scope,
+ Some(finalize),
+ ignore_binding,
+ None,
+ ) {
let res = module.res().map(|r| (r, ident));
for error in &mut self.privacy_errors[privacy_errors_len..] {
error.outermost_res = res;
@@ -1051,7 +1049,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut all_ns_err = true;
self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
- let orig_vis = import.vis.take();
let binding = this.resolve_ident_in_module(
module,
ident,
@@ -1059,8 +1056,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&import.parent_scope,
Some(Finalize { report_private: false, ..finalize }),
target_bindings[ns].get(),
+ Some(import),
);
- import.vis.set(orig_vis);
match binding {
Ok(binding) => {
@@ -1123,6 +1120,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&import.parent_scope,
Some(finalize),
None,
+ None,
);
if binding.is_ok() {
all_ns_failed = false;
@@ -1233,7 +1231,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut crate_private_reexport = false;
self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
- if !binding.vis.is_at_least(import.expect_vis(), this.tcx) {
+ if !binding.vis.is_at_least(import.vis, this.tcx) {
reexport_error = Some((ns, binding));
if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
if binding_def_id.is_top_level_module() {
@@ -1370,6 +1368,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
false,
target_bindings[ns].get(),
+ None,
) {
Ok(other_binding) => {
is_redundant = binding.res() == other_binding.res()
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index f844930ad265e..4d28c0a3ef1bb 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1388,6 +1388,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
finalize,
Some(&self.ribs),
None,
+ None,
)
}
@@ -4186,7 +4187,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
if let Ok((_, res)) =
- self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
+ self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
{
return Ok(Some(PartialRes::new(res)));
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index f126563fe58f0..f9896fb21964d 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2058,6 +2058,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
ident,
ns,
&self.parent_scope,
+ None,
) {
let res = binding.res();
if filter_fn(res) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 79d3bb685b384..023e428dc1ba7 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -2120,7 +2120,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
- match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
+ match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
PathResult::NonModule(path_res) => path_res.full_res(),
PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
@@ -2204,6 +2204,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ident,
ValueNS,
parent_scope,
+ None,
) else {
return;
};
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 64ae0d82952d5..a6301a367a4b3 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -39,6 +39,7 @@ use crate::errors::{
self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
MacroExpectedFound, RemoveSurroundingDerive,
};
+use crate::imports::Import;
use crate::Namespace::*;
use crate::{
BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, MacroData, ModuleKind,
@@ -399,6 +400,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
&parent_scope,
true,
force,
+ None,
) {
Ok((Some(ext), _)) => {
if !ext.helper_attrs.is_empty() {
@@ -551,6 +553,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
force,
deleg_impl,
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
+ None,
) {
Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -704,8 +707,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
+ ignore_import: Option>,
) -> Result<(Option>, Res), Determinacy> {
- self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None, None)
+ self.resolve_macro_or_delegation_path(
+ path,
+ kind,
+ parent_scope,
+ trace,
+ force,
+ None,
+ None,
+ ignore_import,
+ )
}
fn resolve_macro_or_delegation_path(
@@ -717,6 +730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
force: bool,
deleg_impl: Option,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
+ ignore_import: Option>,
) -> Result<(Option>, Res), Determinacy> {
let path_span = ast_path.span;
let mut path = Segment::from_path(ast_path);
@@ -733,7 +747,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let res = if deleg_impl.is_some() || path.len() > 1 {
let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
- let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
+ let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
PathResult::NonModule(..)
@@ -768,6 +782,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
force,
None,
+ None,
);
if let Err(Determinacy::Undetermined) = binding {
return Err(Determinacy::Undetermined);
@@ -852,6 +867,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&parent_scope,
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
None,
+ None,
) {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
check_consistency(self, &path, path_span, kind, initial_res, res)
@@ -871,7 +887,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let PathResult::Failed { span, label, module, .. } = path_res {
// try to suggest if it's not a macro, maybe a function
if let PathResult::NonModule(partial_res) =
- self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+ self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None)
&& partial_res.unresolved_segments() == 0
{
let sm = self.tcx.sess.source_map();
@@ -921,6 +937,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
true,
None,
+ None,
) {
Ok(binding) => {
let initial_res = initial_binding.map(|initial_binding| {
@@ -966,6 +983,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
true,
None,
+ None,
);
}
}
@@ -1070,6 +1088,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
None,
false,
None,
+ None,
);
if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) {
self.tcx.sess.psess.buffer_lint(
@@ -1143,7 +1162,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut indeterminate = false;
for ns in namespaces {
- match self.maybe_resolve_path(path, Some(*ns), &parent_scope) {
+ match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) {
PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
return Ok(true);
From 273c67db83caf0260956b87dd976a7727e4d2cd3 Mon Sep 17 00:00:00 2001
From: Ralf Jung
Date: Mon, 5 Aug 2024 12:49:31 +0200
Subject: [PATCH 31/31] codegen: better centralize function attribute
computation
---
compiler/rustc_codegen_llvm/src/abi.rs | 26 ++++++++++++++++---
compiler/rustc_codegen_llvm/src/attributes.rs | 3 ++-
compiler/rustc_codegen_llvm/src/callee.rs | 4 +--
compiler/rustc_codegen_llvm/src/declare.rs | 2 +-
compiler/rustc_codegen_llvm/src/mono_item.rs | 4 +--
5 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index b8f4203126381..1277b7898c2d9 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -5,10 +5,10 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::MemFlags;
-use rustc_middle::bug;
use rustc_middle::ty::layout::LayoutOf;
pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
use rustc_middle::ty::Ty;
+use rustc_middle::{bug, ty};
use rustc_session::config;
pub use rustc_target::abi::call::*;
use rustc_target::abi::{self, HasDataLayout, Int, Size};
@@ -16,6 +16,7 @@ pub use rustc_target::spec::abi::Abi;
use rustc_target::spec::SanitizerSet;
use smallvec::SmallVec;
+use crate::attributes::llfn_attrs_from_instance;
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, Attribute, AttributePlace};
@@ -310,7 +311,16 @@ pub trait FnAbiLlvmExt<'ll, 'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
- fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
+
+ /// Apply attributes to a function declaration/definition.
+ fn apply_attrs_llfn(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ llfn: &'ll Value,
+ instance: Option>,
+ );
+
+ /// Apply attributes to a function call.
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value);
}
@@ -396,7 +406,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
self.conv.into()
}
- fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
+ fn apply_attrs_llfn(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ llfn: &'ll Value,
+ instance: Option>,
+ ) {
let mut func_attrs = SmallVec::<[_; 3]>::new();
if self.ret.layout.abi.is_uninhabited() {
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
@@ -477,6 +492,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}
}
}
+
+ // If the declaration has an associated instance, compute extra attributes based on that.
+ if let Some(instance) = instance {
+ llfn_attrs_from_instance(cx, llfn, instance);
+ }
}
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index ad38814a68b6d..0cd6810249453 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -324,9 +324,10 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
}
+/// Helper for `FnAbi::apply_attrs_llfn`:
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
-pub fn from_fn_attrs<'ll, 'tcx>(
+pub fn llfn_attrs_from_instance<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
llfn: &'ll Value,
instance: ty::Instance<'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 9030b3d848f9a..663c5be46e5e4 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -10,8 +10,8 @@ use rustc_middle::ty::{self, Instance, TypeVisitableExt};
use tracing::debug;
use crate::context::CodegenCx;
+use crate::llvm;
use crate::value::Value;
-use crate::{attributes, llvm};
/// Codegens a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
@@ -78,8 +78,6 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
};
debug!("get_fn: not casting pointer!");
- attributes::from_fn_attrs(cx, llfn, instance);
-
// Apply an appropriate linkage/visibility value to our item that we
// just declared.
//
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index c4887464e19c2..2aa349b278234 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -137,7 +137,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::Visibility::Default,
fn_abi.llvm_type(self),
);
- fn_abi.apply_attrs_llfn(self, llfn);
+ fn_abi.apply_attrs_llfn(self, llfn, instance);
if self.tcx.sess.is_sanitizer_cfi_enabled() {
if let Some(instance) = instance {
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index d59eaae1ba9b8..f1ef359594b4b 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -12,7 +12,7 @@ use tracing::debug;
use crate::context::CodegenCx;
use crate::errors::SymbolAlreadyDefined;
use crate::type_of::LayoutLlvmExt;
-use crate::{attributes, base, llvm};
+use crate::{base, llvm};
impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
fn predefine_static(
@@ -87,8 +87,6 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
debug!("predefine_fn: instance = {:?}", instance);
- attributes::from_fn_attrs(self, lldecl, instance);
-
unsafe {
if self.should_assume_dso_local(lldecl, false) {
llvm::LLVMRustSetDSOLocal(lldecl, true);