Auto merge of #128796 - matthiaskrgr:rollup-r7l68ph, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #128221 (Add implied target features to target_feature attribute)
 - #128261 (impl `Default` for collection iterators that don't already have it)
 - #128353 (Change generate-copyright to generate HTML, with cargo dependencies included)
 - #128679 (codegen: better centralize function declaration attribute computation)
 - #128732 (make `import.vis` is immutable)
 - #128755 (Integrate crlf directly into related test file instead via of .gitattributes)
 - #128772 (rustc_codegen_ssa: Set architecture for object crate for 32-bit SPARC)
 - #128782 (unused_parens: do not lint against parens around &raw)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-08-07 20:00:29 +00:00
commit 8b3870784f
56 changed files with 1316 additions and 678 deletions

View File

@ -1406,8 +1406,11 @@ name = "generate-copyright"
version = "0.1.0"
dependencies = [
"anyhow",
"cargo_metadata 0.18.1",
"rinja",
"serde",
"serde_json",
"thiserror",
]
[[package]]
@ -3094,7 +3097,10 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd"
dependencies = [
"humansize",
"itoa",
"num-traits",
"percent-encoding",
"rinja_derive",
]

View File

@ -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.",
]

View File

@ -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::<Vec<&str>>();
if let Some(features) = check_tied_features(

View File

@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
let feature = backend_feature_name(s)?;
// Warn against use of GCC specific feature names on the CLI.
if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) {
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
let gcc_features = to_gcc_features(sess, rust_feature);
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
Some(rust_feature)

View File

@ -486,7 +486,7 @@ pub fn target_features(
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 {

View File

@ -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<ty::Instance<'tcx>>,
);
/// 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<ty::Instance<'tcx>>,
) {
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) {

View File

@ -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>,
@ -496,7 +497,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::<Vec<&str>>();
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
if let Some(f) = llvm_util::check_tied_features(
cx.tcx.sess,

View File

@ -95,11 +95,14 @@ pub fn write_output_file<'ll>(
}
}
pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
pub fn create_informational_target_machine(
sess: &Session,
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 = llvm_util::global_llvm_features(sess, false);
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())
}

View File

@ -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.
//

View File

@ -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, false);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
}

View File

@ -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 {

View File

@ -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)),
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
}
}
}

View File

@ -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};
@ -239,40 +240,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 => {
@ -308,11 +277,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<Symbol> {
let target_machine = create_informational_target_machine(sess);
let mut features = vec![];
// Add base features for the target
let target_machine = create_informational_target_machine(sess, true);
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 (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 {
features.retain(|f| {
!sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
});
}
}
// Filter enabled features based on feature gates
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 {
@ -320,18 +331,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
}
})
.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()
@ -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 =
@ -440,7 +440,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, false);
match req.kind {
PrintKind::TargetCPUs => {
// SAFETY generate a C compatible string from a byte slice to pass
@ -488,7 +488,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<String> {
pub(crate) fn global_llvm_features(
sess: &Session,
diagnostics: bool,
only_base_features: bool,
) -> Vec<String> {
// 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:
//
@ -548,94 +552,124 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
}
// -Ctarget-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 });
if !only_base_features {
let supported_features = sess.target.supported_target_features();
let (llvm_major, _, _) = get_version();
let mut featsmap = FxHashMap::default();
// 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,
Some(c @ ('+' | '-')) => c,
Some(_) => {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
}
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 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 });
}
}
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;
}
};
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 },
}
} else {
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
};
sess.dcx().emit_warn(unknown_feature);
} else if feature_state
.is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
{
// An unstable feature. Warn about using it.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
// 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);
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;
}
// 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) {
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 {
@ -646,30 +680,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
}
}
// This is a workaround for a LLVM bug that doesn't implicitly enable
// `simd128` when `relaxed-simd` is.
// See <https://github.com/llvm/llvm-project/pull/99803>, 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,
span: None,
missing_features: None,
});
}
features
}

View File

@ -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);

View File

@ -208,6 +208,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
"powerpc64" => (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),

View File

@ -1,11 +1,12 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::UnordMap;
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};
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<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
target_features: &mut Vec<TargetFeature>,
) {
let Some(list) = attr.meta_item_list() else { return };
let bad_item = |span| {
@ -30,6 +31,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 +46,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 +100,26 @@ 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 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() {
implied_target_features.extend(tcx.implied_target_features(*feature).clone());
}
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
@ -113,7 +128,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
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) => {
@ -158,10 +173,14 @@ pub(crate) fn provide(providers: &mut Providers) {
.target
.supported_target_features()
.iter()
.map(|&(a, b)| (a.to_string(), b.as_feature_name()))
.map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
.collect()
}
},
implied_target_features: |tcx, feature| {
UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
.into_sorted_stable_ord()
},
asm_target_features,
..*providers
}

View File

@ -317,19 +317,20 @@ 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))
{
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| !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
}),
);

View File

@ -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) }`.
//

View File

@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
pub link_ordinal: Option<u16>,
/// The `#[target_feature(enable = "...")]` attribute and the enabled
/// features (only enabled features are supported right now).
pub target_features: Vec<Symbol>,
pub target_features: Vec<TargetFeature>,
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
pub linkage: Option<Linkage>,
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@ -51,6 +51,15 @@ pub struct CodegenFnAttrs {
pub patchable_function_entry: Option<PatchableFunctionEntry>,
}
#[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

View File

@ -2183,6 +2183,12 @@ rustc_queries! {
desc { "looking up supported target features" }
}
query implied_target_features(feature: Symbol) -> &'tcx Vec<Symbol> {
arena_cache
eval_always
desc { "looking up implied target features" }
}
query features_query(_: ()) -> &'tcx rustc_feature::Features {
feedable
desc { "looking up enabled feature gates" }

View File

@ -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<Ty<'tcx>>,
@ -442,14 +443,21 @@ 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)
})
{
let missing: Vec<_> = callee_features
.iter()
.copied()
.filter(|feature| !self.body_target_features.contains(feature))
.filter(|feature| {
!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

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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<Vec<Rib<'a>>>>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
module: Option<ModuleOrUniformRoot<'a>>,
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<Segment>, Option<String>)> {
// 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<Segment>, Option<String>)> {
// 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<Segment>, Option<String>)> {
// 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

View File

@ -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<Finalize>,
force: bool,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> Result<NameBinding<'a>, 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<Import<'a>>,
) -> Result<NameBinding<'a>, 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<Finalize>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> Result<NameBinding<'a>, 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<Finalize>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> Result<NameBinding<'a>, (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<Finalize>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> Result<NameBinding<'a>, 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<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> Result<NameBinding<'a>, (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<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'a>,
ignore_import: Option<Import<'a>>,
) -> 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<Finalize>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> 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<Finalize>,
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
ignore_binding: Option<NameBinding<'a>>,
ignore_import: Option<Import<'a>>,
) -> 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,

View File

@ -175,7 +175,7 @@ pub(crate) struct ImportData<'a> {
pub module_path: Vec<Segment>,
/// The resolution of `module_path`.
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
pub vis: Cell<Option<ty::Visibility>>,
pub vis: ty::Visibility,
pub used: Cell<Option<Used>>,
}
@ -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<NodeId> {
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<UnresolvedImportError> {
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()

View File

@ -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)));
}

View File

@ -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) {

View File

@ -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;
};

View File

@ -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<Import<'a>>,
) -> Result<(Option<Lrc<SyntaxExtension>>, 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<LocalDefId>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
ignore_import: Option<Import<'a>>,
) -> Result<(Option<Lrc<SyntaxExtension>>, 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);

View File

@ -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.
@ -53,136 +54,154 @@ 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),
// Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
("fp16", Stable, &["neon"]),
// FEAT_FRINTTS
("frintts", Stable),
("frintts", Stable, &[]),
// FEAT_I8MM
("i8mm", Stable),
("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),
("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),
// It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
//
// LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
// exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
//
// "For backwards compatibility, Neon and VFP are required in the latest architectures."
("sve", Stable, &["neon"]),
// 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,224 +209,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", "zbkc", "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 WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")];
const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
&[("alu32", Unstable(sym::bpf_target_feature), &[])];
const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("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)),
("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)] = &[
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// 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)),
("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 IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
("backchain", Unstable(sym::s390x_target_feature)),
("vector", Unstable(sym::s390x_target_feature)),
("backchain", Unstable(sym::s390x_target_feature), &[]),
("vector", Unstable(sym::s390x_target_feature), &[]),
// tidy-alphabetical-end
];
@ -430,10 +448,13 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
.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,
@ -458,12 +479,27 @@ 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)] {
match &*self.arch {
"wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES,
_ => &[],
pub fn implied_target_features(
&self,
base_features: impl Iterator<Item = Symbol>,
) -> FxHashSet<Symbol> {
let implied_features = self
.supported_target_features()
.iter()
.map(|(f, _, i)| (Symbol::intern(f), i))
.collect::<FxHashMap<_, _>>();
// 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::<Vec<Symbol>>();
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
}
}

View File

@ -1433,6 +1433,20 @@ pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
}
#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl<T> 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<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -2016,6 +2016,20 @@ impl<K, V> Default for Range<'_, K, V> {
}
}
#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl<K, V> 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<K, V> ExactSizeIterator for ValuesMut<'_, K, V> {
#[stable(feature = "fused", since = "1.26.0")]
impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl<K, V> 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<K, V, A: Allocator + Clone> Iterator for IntoKeys<K, V, A> {
type Item = K;

View File

@ -28,6 +28,20 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
}
}
#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl<T> 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<T> Clone for Iter<'_, T> {

View File

@ -28,6 +28,20 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
}
}
#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
impl<T> 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;

View File

@ -212,11 +212,13 @@ 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);
cmd.env("DEST", &dest);
cmd.env("OUT_DIR", &builder.out);
cmd.env("CARGO", &builder.initial_cargo);
cmd.run(builder);
dest

View File

@ -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"

View File

@ -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();

View File

@ -2,10 +2,14 @@
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
[dependencies]
anyhow = "1.0.65"
cargo_metadata = "0.18.1"
rinja = "0.3.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.85"
thiserror = "1"

View File

@ -0,0 +1,191 @@
//! Gets metadata about a workspace from Cargo
use std::collections::BTreeMap;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
/// Describes how this module can fail
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[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")]
RunningVendor,
#[error("Bad path {0:?} whilst scraping files")]
Scraping(PathBuf),
}
/// Uniquely describes a package on crates.io
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
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
pub authors: Vec<String>,
/// 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<String, String>,
/// If this is true, this dep is in the Rust Standard Library
pub is_in_libstd: Option<bool>,
}
/// 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_metadata_and_notices(
cargo: &Path,
dest: &Path,
root_path: &Path,
manifest_paths: &[&Path],
) -> Result<BTreeMap<Package, PackageMetadata>, 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<BTreeMap<Package, PackageMetadata>, 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")) {
panic!("cargo_manifest::get requires a path to a Cargo.toml file");
}
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 package_id = Package { name: package.name, version: package.version.to_string() };
output.insert(
package_id,
PackageMetadata {
license: package.license.unwrap_or_else(|| String::from("Unspecified")),
authors: package.authors,
notices: BTreeMap::new(),
is_in_libstd: None,
},
);
}
}
Ok(output)
}
/// 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(Error::LaunchingVendor)?;
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(
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)? {
let entry = entry?;
let metadata = entry.metadata()?;
let path = entry.path();
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() {
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)?);
}
}
}
Ok(())
}

View File

@ -1,79 +1,70 @@
use std::io::Write;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use anyhow::Error;
use rinja::Template;
mod cargo_metadata;
#[derive(Template)]
#[template(path = "COPYRIGHT.html")]
struct CopyrightTemplate {
in_tree: Node,
dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
}
/// The entry point to the binary.
///
/// You should probably let `bootstrap` execute this program instead of running it directly.
///
/// Run `x.py run generate-copyright`
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 mut buffer = Vec::new();
render_recursive(&metadata.files, &mut buffer, 0)?;
let root_path = std::path::absolute(".")?;
let workspace_paths = [
Path::new("./Cargo.toml"),
Path::new("./src/tools/cargo/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)?;
std::fs::write(&dest, &buffer)?;
Ok(())
}
fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
match node {
Node::Root { children } => {
for child in children {
render_recursive(child, buffer, depth)?;
}
}
Node::Directory { name, children, license } => {
render_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)?;
}
}
}
Node::Group { files, directories, license } => {
render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?;
}
Node::File { name, license } => {
render_license(&prefix, std::iter::once(name), Some(license), buffer)?;
}
}
Ok(())
}
fn render_license<'a>(
prefix: &str,
names: impl Iterator<Item = &'a String>,
license: Option<&License>,
buffer: &mut Vec<u8>,
) -> Result<(), Error> {
for name in names {
writeln!(buffer, "{prefix}**`{name}`** ")?;
}
if let Some(license) = license {
writeln!(buffer, "{prefix}License: `{}`", license.spdx)?;
for copyright in license.copyright.iter() {
writeln!(buffer, "{prefix}Copyright: {copyright}")?;
}
}
let stdlib_set =
cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
for (key, value) in collected_cargo_metadata.iter_mut() {
value.is_in_libstd = Some(stdlib_set.contains_key(key));
}
let template = CopyrightTemplate {
in_tree: collected_tree_metadata.files,
dependencies: collected_cargo_metadata,
};
let output = template.render()?;
std::fs::write(&dest_file, output)?;
Ok(())
}
/// Describes a tree of metadata for our filesystem tree
#[derive(serde::Deserialize)]
struct Metadata {
files: Node,
}
#[derive(serde::Deserialize)]
/// Describes one node in our metadata tree
#[derive(serde::Deserialize, rinja::Template)]
#[serde(rename_all = "kebab-case", tag = "type")]
#[template(path = "Node.html")]
pub(crate) enum Node {
Root { children: Vec<Node> },
Directory { name: String, children: Vec<Node>, license: Option<License> },
@ -81,12 +72,14 @@ pub(crate) enum Node {
Group { files: Vec<String>, directories: Vec<String>, license: License },
}
/// A License has an SPDX license name and a list of copyright holders.
#[derive(serde::Deserialize)]
struct License {
spdx: String,
copyright: Vec<String>,
}
/// Grab an environment variable as a PathBuf, or fail nicely.
fn env_path(var: &str) -> Result<PathBuf, Error> {
if let Some(var) = std::env::var_os(var) {
Ok(var.into())

View File

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Copyright notices for The Rust Toolchain</title>
</head>
<body>
<h1>Copyright notices for The Rust Toolchain</h1>
<p>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).</p>
<h2>Table of Contents</h2>
<ul>
<li><a href="#in-tree-files">In-tree files</a></li>
<li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
</ul>
<h2 id="in-tree-files">In-tree files</h2>
<p>The following licenses cover the in-tree source files that were used in this
release:</p>
{{ in_tree|safe }}
<h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2>
<p>The following licenses cover the out-of-tree crates that were used in this
release:</p>
{% for (key, value) in dependencies %}
<h3>📦 {{key.name}}-{{key.version}}</h3>
<p><b>URL:</b> <a href="https://crates.io/crates/{{ key.name }}/{{ key.version }}">https://crates.io/crates/{{ key.name }}/{{ key.version }}</a></p>
<p><b>In libstd:</b> {% if value.is_in_libstd.unwrap() %} Yes {% else %} No {% endif %}</p>
<p><b>Authors:</b> {{ value.authors|join(", ") }}</p>
<p><b>License:</b> {{ value.license }}</p>
{% let len = value.notices.len() %}
{% if len > 0 %}
<p><b>Notices:</b>
{% for (notice_name, notice_text) in value.notices %}
<details>
<summary><code>{{ notice_name }}</code></summary>
<pre>
{{ notice_text }}
</pre>
</details>
{% endfor %}
</p>
{% endif %}
{% endfor %}
</body>
</html>

View File

@ -0,0 +1,71 @@
{% match self %}
{% when Node::Root { children } %}
{% for child in children %}
{{ child|safe }}
{% endfor %}
{% when Node::Directory { name, children, license } %}
<div style="border:1px solid black; padding: 5px;">
<p>
<b>File/Directory:</b> <code>{{ name }}</code>
</p>
{% if let Some(license) = license %}
<p><b>License:</b> {{ license.spdx }}</p>
{% for copyright in license.copyright.iter() %}
<p><b>Copyright:</b> {{ copyright }}</p>
{% endfor %}
{% endif %}
{% if !children.is_empty() %}
<p><b>Exceptions:</b></p>
{% for child in children %}
{{ child|safe }}
{% endfor %}
{% endif %}
</div>
{% when Node::File { name, license } %}
<div style="border:1px solid black; padding: 5px;">
<p>
<b>File/Directory:</b> <code>{{ name }}</code>
</p>
<p><b>License:</b> {{ license.spdx }}</p>
{% for copyright in license.copyright.iter() %}
<p><b>Copyright:</b> {{ copyright }}</p>
{% endfor %}
</div>
{% when Node::Group { files, directories, license } %}
<div style="border:1px solid black; padding: 5px;">
<p>
<b>File/Directory:</b>
{% for name in files %}
<code>{{ name }}</code>
{% endfor %}
{% for name in directories %}
<code>{{ name }}</code>
{% endfor %}
</p>
<p><b>License:</b> {{ license.spdx }}</p>
{% for copyright in license.copyright.iter() %}
<p><b>Copyright:</b> {{ copyright }}</p>
{% endfor %}
</div>
{% endmatch %}

View File

@ -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.*"}}

View File

@ -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,+avx"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+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"

View File

@ -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,?))*}}" }

View File

@ -1 +1 @@
warning-crlf.rs eol=crlf
warning-crlf.rs -text

View File

@ -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`

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -24,7 +24,7 @@ LL | Quux.avx_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:37:5
--> $DIR/safe-calls.rs:38:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
@ -32,22 +32,13 @@ LL | avx_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: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]`
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,16 +56,7 @@ 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]`
@ -83,7 +65,7 @@ LL | const _: () = 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:63:15
--> $DIR/safe-calls.rs:64:15
|
LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@ -92,7 +74,7 @@ LL | const _: () = 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:70:5
--> $DIR/safe-calls.rs:69:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
@ -101,16 +83,16 @@ LL | sse2();
= 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: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`.

View File

@ -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() {}

View File

@ -0,0 +1,24 @@
//@ only-x86_64
//@ build-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() {}