Auto merge of #142770 - tgross35:rollup-w74w39t, r=tgross35

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#138291 (rewrite `optimize` attribute to use new attribute parsing infrastructure)
 - rust-lang/rust#140920 (Extract some shared code from codegen backend target feature handling)
 - rust-lang/rust#141990 (Implement send_signal for unix child processes)
 - rust-lang/rust#142668 (vec_deque/fmt/vec tests: remove static mut)
 - rust-lang/rust#142687 (Reduce uses of `hir_crate`.)
 - rust-lang/rust#142699 (Update books)
 - rust-lang/rust#142714 (add comment to `src/bootstrap/build.rs`)
 - rust-lang/rust#142753 (Update library dependencies)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-06-20 09:59:20 +00:00
77 changed files with 868 additions and 1080 deletions
@@ -38,7 +38,8 @@ pub enum InstructionSetAttr {
ArmT32,
}
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic, Default)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum OptimizeAttr {
/// No `#[optimize(..)]` attribute
#[default]
@@ -229,7 +230,8 @@ pub enum AttributeKind {
/// Represents `#[rustc_macro_transparency]`.
MacroTransparency(Transparency),
/// Represents `#[optimize(size|speed)]`
Optimize(OptimizeAttr, Span),
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
Repr(ThinVec<(ReprAttr, Span)>),
@@ -0,0 +1,40 @@
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::sym;
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
pub(crate) struct OptimizeParser;
impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const PATH: &[rustc_span::Symbol] = &[sym::optimize];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span);
return None;
};
let Some(single) = list.single() else {
cx.expected_single_argument(list.span);
return None;
};
let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
Some(sym::size) => OptimizeAttr::Size,
Some(sym::speed) => OptimizeAttr::Speed,
Some(sym::none) => OptimizeAttr::DoNotOptimize,
_ => {
cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]);
OptimizeAttr::Default
}
};
Some(AttributeKind::Optimize(res, cx.attr_span))
}
}
@@ -28,6 +28,7 @@
pub(crate) mod allow_unstable;
pub(crate) mod cfg;
pub(crate) mod codegen_attrs;
pub(crate) mod confusables;
pub(crate) mod deprecation;
pub(crate) mod inline;
@@ -15,6 +15,7 @@
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::OptimizeParser;
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -108,6 +109,7 @@ mod late {
Single<ConstStabilityIndirectParser>,
Single<DeprecationParser>,
Single<InlineParser>,
Single<OptimizeParser>,
Single<RustcForceInlineParser>,
Single<TransparencyParser>,
// tidy-alphabetical-end
-16
View File
@@ -1,7 +1,3 @@
codegen_gcc_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_gcc_unwinding_inline_asm =
GCC backend does not support unwinding from inline asm
@@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
codegen_gcc_unknown_ctarget_feature =
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request
codegen_gcc_missing_features =
add the missing features in a `target_feature` attribute
codegen_gcc_target_feature_disable_or_enable =
the target features {$features} must all be either enabled or disabled together
+1 -25
View File
@@ -1,30 +1,6 @@
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::Diagnostic;
use rustc_span::Span;
#[derive(Diagnostic)]
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
#[note]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_unknown_ctarget_feature)]
#[note]
pub(crate) struct UnknownCTargetFeature<'a> {
pub feature: &'a str,
#[subdiagnostic]
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_gcc_possible_feature)]
Some { rust_feature: &'a str },
#[help(codegen_gcc_consider_filing_feature_request)]
None,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_unwinding_inline_asm)]
pub(crate) struct UnwindingInlineAsm {
+22 -99
View File
@@ -1,20 +1,12 @@
#[cfg(feature = "master")]
use gccjit::Context;
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_codegen_ssa::target_features;
use rustc_session::Session;
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use smallvec::{SmallVec, smallvec};
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
target_features::retpoline_features_by_flags(sess, features);
// FIXME: LLVM also sets +reserve-x18 here under some conditions.
}
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -44,98 +36,29 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
// -Ctarget-features
let known_features = sess.target.rust_target_features();
let mut featsmap = FxHashMap::default();
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
.to_sorted_stable_ord()
.iter()
.map(|&&s| (true, s)),
)
} else if let Some(feature) = feature.strip_prefix('-') {
// FIXME: Why do we not remove implied features on "-" here?
// We do the equivalent above in `target_config`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() && diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
// Remove features that are meant for rustc, not codegen.
all_rust_features.retain(|&(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(&feature)
});
// Check feature validity.
if diagnostics {
for &(enable, feature) in &all_rust_features {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature = known_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)
} 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);
}
Some(&(_, stability, _)) => {
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}
// Translate this into GCC features.
let feats =
all_rust_features.iter().flat_map(|&(enable, feature)| {
let enable_disable = if enable { '+' } else { '-' };
target_features::flag_to_backend_features(
sess,
diagnostics,
|feature| to_gcc_features(sess, feature),
|feature, enable| {
// We run through `to_gcc_features` when
// passing requests down to GCC. This means that all in-language
// features also work on the command line instead of having two
// different names when the GCC name and the Rust name differ.
to_gcc_features(sess, feature)
.iter()
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
.map(|feature| {
if enable_disable == '-' {
format!("-{}", feature)
} else {
feature.to_string()
}
})
.collect::<Vec<_>>()
});
features.extend(feats);
features.extend(
to_gcc_features(sess, feature)
.iter()
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
.map(
|feature| {
if !enable { format!("-{}", feature) } else { feature.to_string() }
},
),
);
},
);
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
features: f,
span: None,
missing_features: None,
});
}
gcc_features_by_flags(sess, &mut features);
features
}
+16 -36
View File
@@ -102,6 +102,7 @@
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
};
use rustc_codegen_ssa::base::codegen_crate;
use rustc_codegen_ssa::target_features::cfg_target_feature;
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
use rustc_data_structures::fx::FxIndexMap;
@@ -476,42 +477,21 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
/// Returns the features that should be set in `cfg(target_feature)`.
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
// TODO(antoyo): use global_gcc_features.
let f = |allow_unstable| {
sess.target
.rust_target_features()
.iter()
.filter_map(|&(feature, gate, _)| {
if allow_unstable
|| (gate.in_cfg()
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(feature)
} else {
None
}
})
.filter(|feature| {
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
if *feature == "neon" {
return false;
}
target_info.cpu_supports(feature)
// cSpell:disable
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
*/
// cSpell:enable
})
.map(Symbol::intern)
.collect()
};
let target_features = f(false);
let unstable_target_features = f(true);
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
if feature == "neon" {
return false;
}
target_info.cpu_supports(feature)
// cSpell:disable
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
*/
// cSpell:enable
});
let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16);
let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128);
-10
View File
@@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined =
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
codegen_llvm_unknown_ctarget_feature =
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request
codegen_llvm_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
+1 -25
View File
@@ -3,35 +3,11 @@
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::Diagnostic;
use rustc_span::Span;
use crate::fluent_generated as fluent;
#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
#[note]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_ctarget_feature)]
#[note]
pub(crate) struct UnknownCTargetFeature<'a> {
pub feature: &'a str,
#[subdiagnostic]
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_llvm_possible_feature)]
Some { rust_feature: &'a str },
#[help(codegen_llvm_consider_filing_feature_request)]
None,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_symbol_already_defined)]
pub(crate) struct SymbolAlreadyDefined<'a> {
+63 -216
View File
@@ -6,27 +6,20 @@
use std::{ptr, slice, str};
use libc::c_int;
use rustc_codegen_ssa::TargetConfig;
use rustc_codegen_ssa::base::wants_wasm_eh;
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_codegen_ssa::target_features::cfg_target_feature;
use rustc_codegen_ssa::{TargetConfig, target_features};
use rustc_data_structures::fx::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::Session;
use rustc_session::config::{PrintKind, PrintRequest};
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_span::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
use smallvec::{SmallVec, smallvec};
use crate::back::write::create_informational_target_machine;
use crate::errors::{
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
};
use crate::llvm;
use crate::{errors, llvm};
static INIT: Once = Once::new();
@@ -195,15 +188,6 @@ fn with_dependencies(
) -> Self {
Self { llvm_feature_name, dependencies }
}
fn contains(&'a self, feat: &str) -> bool {
self.iter().any(|dep| dep == feat)
}
fn iter(&'a self) -> impl Iterator<Item = &'a str> {
let dependencies = self.dependencies.iter().map(|feat| feat.as_str());
std::iter::once(self.llvm_feature_name).chain(dependencies)
}
}
impl<'a> IntoIterator for LLVMFeature<'a> {
@@ -216,18 +200,22 @@ fn into_iter(self) -> Self::IntoIter {
}
}
// WARNING: the features after applying `to_llvm_features` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
//
// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
//
// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/.
// The commit in use can be found via the `llvm-project` submodule in
// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with
// an external precompiled version of LLVM which might lead to failures if the oldest tested /
// supported LLVM version doesn't yet support the relevant intrinsics.
/// Convert a Rust feature name to an LLVM feature name. Returning `None` means the
/// feature should be skipped, usually because it is not supported by the current
/// LLVM version.
///
/// WARNING: the features after applying `to_llvm_features` must be known
/// to LLVM or the feature detection code will walk past the end of the feature
/// array, leading to crashes.
///
/// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
/// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
///
/// Check the current rustc fork of LLVM in the repo at
/// <https://github.com/rust-lang/llvm-project/>. The commit in use can be found via the
/// `llvm-project` submodule in <https://github.com/rust-lang/rust/tree/master/src> Though note that
/// Rust can also be build with an external precompiled version of LLVM which might lead to failures
/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics.
pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFeature<'a>> {
let arch = if sess.target.arch == "x86_64" {
"x86"
@@ -343,98 +331,25 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
// the target CPU, that is still expanded to target features (with all their implied features)
// by LLVM.
let target_machine = create_informational_target_machine(sess, true);
// Compute which of the known target features are enabled in the 'base' target machine. We only
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
let mut features: FxHashSet<Symbol> = sess
.target
.rust_target_features()
.iter()
.filter(|(feature, _, _)| {
// skip checking special features, as LLVM may not understand them
if RUSTC_SPECIAL_FEATURES.contains(feature) {
return true;
}
if let Some(feat) = to_llvm_features(sess, feature) {
for llvm_feature in feat {
let cstr = SmallCStr::new(llvm_feature);
// `LLVMRustHasFeature` is moderately expensive. On targets with many
// features (e.g. x86) these calls take a non-trivial fraction of runtime
// when compiling very small programs.
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
return false;
}
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
if let Some(feat) = to_llvm_features(sess, feature) {
// All the LLVM features this expands to must be enabled.
for llvm_feature in feat {
let cstr = SmallCStr::new(llvm_feature);
// `LLVMRustHasFeature` is moderately expensive. On targets with many
// features (e.g. x86) these calls take a non-trivial fraction of runtime
// when compiling very small programs.
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
return false;
}
true
} else {
false
}
})
.map(|(feature, _, _)| Symbol::intern(feature))
.collect();
// Add enabled and remove disabled 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 {
// Also add all transitively implied features.
// We don't care about the order in `features` since the only thing we use it for is the
// `features.contains` below.
#[allow(rustc::potential_query_instability)]
features.extend(
sess.target
.implied_target_features(feature.as_str())
.iter()
.map(|s| Symbol::intern(s)),
);
true
} else {
// Remove transitively reverse-implied features.
// We don't care about the order in `features` since the only thing we use it for is the
// `features.contains` below.
#[allow(rustc::potential_query_instability)]
features.retain(|f| {
if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
// remove `f`. (This is the standard logical contraposition principle.)
false
} else {
// We can keep `f`.
true
}
});
false
}
}
});
// Filter enabled features based on feature gates.
let f = |allow_unstable| {
sess.target
.rust_target_features()
.iter()
.filter_map(|(feature, gate, _)| {
// The `allow_unstable` set is used by rustc internally to determined which target
// features are truly available, so we want to return even perma-unstable
// "forbidden" features.
if allow_unstable
|| (gate.in_cfg()
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(Symbol::intern(feature))
} else {
None
}
})
.filter(|feature| features.contains(&feature))
.collect()
};
let target_features = f(false);
let unstable_target_features = f(true);
let mut cfg = TargetConfig {
target_features,
unstable_target_features,
@@ -707,10 +622,18 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
handle_native(cpu_name)
}
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
/// The target features for compiler flags other than `-Ctarget-features`.
fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
target_features::retpoline_features_by_flags(sess, features);
// -Zfixed-x18
if sess.opts.unstable_opts.fixed_x18 {
if sess.target.arch != "aarch64" {
sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch });
} else {
features.push("+reserve-x18".into());
}
}
}
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -777,6 +700,8 @@ pub(crate) fn global_llvm_features(
.split(',')
.filter(|v| !v.is_empty())
// Drop +v8plus feature introduced in LLVM 20.
// (Hard-coded target features do not go through `to_llvm_feature` since they already
// are LLVM feature names, hence we need a special case here.)
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
.map(String::from),
);
@@ -787,86 +712,23 @@ pub(crate) fn global_llvm_features(
// -Ctarget-features
if !only_base_features {
let known_features = sess.target.rust_target_features();
// Will only be filled when `diagnostics` is set!
let mut featsmap = FxHashMap::default();
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
.to_sorted_stable_ord()
.iter()
.map(|&&s| (true, s)),
)
} else if let Some(feature) = feature.strip_prefix('-') {
// FIXME: Why do we not remove implied features on "-" here?
// We do the equivalent above in `target_config`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
}
// Remove features that are meant for rustc, not LLVM.
all_rust_features.retain(|(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(feature)
});
// Check feature validity.
if diagnostics {
for &(enable, feature) in &all_rust_features {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature =
known_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);
}
Some((_, stability, _)) => {
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}
// Translate this into LLVM features.
let feats = all_rust_features
.iter()
.filter_map(|&(enable, feature)| {
target_features::flag_to_backend_features(
sess,
diagnostics,
|feature| {
to_llvm_features(sess, feature)
.map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter()))
.unwrap_or_default()
},
|feature, enable| {
let enable_disable = if enable { '+' } else { '-' };
// 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)?;
let Some(llvm_feature) = to_llvm_features(sess, feature) else { return };
Some(
features.extend(
std::iter::once(format!(
"{}{}",
enable_disable, llvm_feature.llvm_feature_name
@@ -881,27 +743,12 @@ pub(crate) fn global_llvm_features(
},
)),
)
})
.flatten();
features.extend(feats);
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable {
features: f,
span: None,
missing_features: None,
});
}
},
);
}
// -Zfixed-x18
if sess.opts.unstable_opts.fixed_x18 {
if sess.target.arch != "aarch64" {
sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch });
} else {
features.push("+reserve-x18".into());
}
}
// We add this in the "base target" so that these show up in `sess.unstable_target_features`.
llvm_features_by_flags(sess, &mut features);
features
}
+19 -5
View File
@@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file =
codegen_ssa_expected_name_value_pair = expected name value pair
codegen_ssa_expected_one_argument = expected one argument
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -68,6 +66,11 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
codegen_ssa_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
codegen_ssa_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
codegen_ssa_forbidden_target_feature_attr =
target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
@@ -86,9 +89,6 @@ codegen_ssa_incorrect_cgu_reuse_type =
codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
codegen_ssa_invalid_argument = invalid argument
.help = valid inline arguments are `always` and `never`
codegen_ssa_invalid_instruction_set = invalid instruction set specified
codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
@@ -368,8 +368,22 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name
codegen_ssa_unknown_archive_kind =
Don't know how to build archive of type: {$kind}
codegen_ssa_unknown_ctarget_feature =
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request
codegen_ssa_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
codegen_ssa_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
@@ -6,7 +6,6 @@
use rustc_attr_data_structures::{
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -18,13 +17,15 @@
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_session::{Session, lint};
use rustc_span::{Ident, Span, sym};
use rustc_target::spec::SanitizerSet;
use crate::errors;
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
use crate::target_features::{
check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
};
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
use rustc_middle::mir::mono::Linkage::*;
@@ -455,33 +456,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.inline = InlineAttr::Never;
}
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| {
if !attr.has_name(sym::optimize) {
return ia;
}
if attr.is_word() {
tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
return ia;
}
let Some(ref items) = attr.meta_item_list() else {
return OptimizeAttr::Default;
};
let [item] = &items[..] else {
tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
return OptimizeAttr::Default;
};
if item.has_name(sym::size) {
OptimizeAttr::Size
} else if item.has_name(sym::speed) {
OptimizeAttr::Speed
} else if item.has_name(sym::none) {
OptimizeAttr::DoNotOptimize
} else {
tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() });
OptimizeAttr::Default
}
});
codegen_fn_attrs.optimize =
find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default);
// #73631: closures inherit `#[target_feature]` annotations
//
@@ -615,25 +591,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs
}
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
/// combinations are allowed.
pub fn check_tied_features(
sess: &Session,
features: &FxHashMap<&str, bool>,
) -> Option<&'static [&'static str]> {
if !features.is_empty() {
for tied in sess.target.tied_target_features() {
// Tied features must be set to the same value, or not set at all
let mut tied_iter = tied.iter();
let enabled = features.get(tied_iter.next().unwrap());
if tied_iter.any(|f| enabled != features.get(f)) {
return Some(tied);
}
}
}
None
}
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+65 -38
View File
@@ -208,20 +208,6 @@ pub(crate) struct OutOfRangeInteger {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_expected_one_argument, code = E0722)]
pub(crate) struct ExpectedOneArgumentOptimize {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_invalid_argument, code = E0722)]
pub(crate) struct InvalidArgumentOptimize {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_copy_path_buf)]
pub(crate) struct CopyPathBuf {
@@ -1217,30 +1203,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
pub error: String,
}
pub struct TargetFeatureDisableOrEnable<'a> {
pub features: &'a [&'a str],
pub span: Option<Span>,
pub missing_features: Option<MissingFeatures>,
}
#[derive(Subdiagnostic)]
#[help(codegen_ssa_missing_features)]
pub struct MissingFeatures;
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
if let Some(span) = self.span {
diag.span(span);
};
if let Some(missing_features) = self.missing_features {
diag.subdiagnostic(missing_features);
}
diag.arg("features", self.features.join(", "));
diag
}
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_aix_strip_not_used)]
pub(crate) struct AixStripNotUsed;
@@ -1283,3 +1245,68 @@ pub(crate) struct XcrunSdkPathWarning {
#[derive(LintDiagnostic)]
#[diag(codegen_ssa_aarch64_softfloat_neon)]
pub(crate) struct Aarch64SoftfloatNeon;
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_ctarget_feature_prefix)]
#[note]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_ssa_possible_feature)]
Some { rust_feature: &'a str },
#[help(codegen_ssa_consider_filing_feature_request)]
None,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_ctarget_feature)]
#[note]
pub(crate) struct UnknownCTargetFeature<'a> {
pub feature: &'a str,
#[subdiagnostic]
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_forbidden_ctarget_feature)]
#[note]
#[note(codegen_ssa_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
pub struct TargetFeatureDisableOrEnable<'a> {
pub features: &'a [&'a str],
pub span: Option<Span>,
pub missing_features: Option<MissingFeatures>,
}
#[derive(Subdiagnostic)]
#[help(codegen_ssa_missing_features)]
pub struct MissingFeatures;
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
if let Some(span) = self.span {
diag.span(span);
};
if let Some(missing_features) = self.missing_features {
diag.subdiagnostic(missing_features);
}
diag.arg("features", self.features.join(", "));
diag
}
}
@@ -1,5 +1,5 @@
use rustc_attr_data_structures::InstructionSetAttr;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -8,11 +8,12 @@
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::features::StabilityExt;
use rustc_session::Session;
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_target::target_features::{self, Stability};
use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability};
use smallvec::SmallVec;
use crate::errors;
@@ -67,7 +68,7 @@ pub(crate) fn from_target_feature_attr(
// Only allow target features whose feature gates have been enabled
// and which are permitted to be toggled.
if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
if let Err(reason) = stability.toggle_allowed() {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature,
@@ -88,7 +89,7 @@ pub(crate) fn from_target_feature_attr(
let feature_sym = Symbol::intern(feature);
for &name in tcx.implied_target_features(feature_sym) {
// But ensure the ABI does not forbid enabling this.
// Here we do assume that LLVM doesn't add even more implied features
// Here we do assume that the backend doesn't add even more implied features
// we don't know about, at least no features that would have ABI effects!
// We skip this logic in rustdoc, where we want to allow all target features of
// all targets, so we can't check their ABI compatibility and anyway we are not
@@ -156,6 +157,276 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
}
}
/// Parse the value of `-Ctarget-feature`, also expanding implied features,
/// and call the closure for each (expanded) Rust feature. If the list contains
/// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked.
fn parse_rust_feature_flag<'a>(
sess: &'a Session,
err_callback: impl Fn(&'a str),
mut callback: impl FnMut(
/* base_feature */ &'a str,
/* with_implied */ FxHashSet<&'a str>,
/* enable */ bool,
),
) {
// A cache for the backwards implication map.
let mut inverse_implied_features: Option<FxHashMap<&str, FxHashSet<&str>>> = None;
for feature in sess.opts.cg.target_feature.split(',') {
if let Some(base_feature) = feature.strip_prefix('+') {
// Skip features that are not target features, but rustc features.
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
return;
}
callback(base_feature, sess.target.implied_target_features(base_feature), true)
} else if let Some(base_feature) = feature.strip_prefix('-') {
// Skip features that are not target features, but rustc features.
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
return;
}
// If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical
// contraposition. So we have to find all the reverse implications of `base_feature` and
// disable them, too.
let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| {
let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default();
for (f, _, is) in sess.target.rust_target_features() {
for i in is.iter() {
set.entry(i).or_default().insert(f);
}
}
set
});
// Inverse implied target features have their own inverse 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 = vec![base_feature];
while let Some(new_feature) = new_features.pop() {
if features.insert(new_feature) {
if let Some(implied_features) = inverse_implied_features.get(&new_feature) {
new_features.extend(implied_features)
}
}
}
callback(base_feature, features, false)
} else if !feature.is_empty() {
err_callback(feature)
}
}
}
/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically,
/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and
/// 2nd component of the return value, respectively).
///
/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is
/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`.
///
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere.
pub fn cfg_target_feature(
sess: &Session,
mut target_base_has_feature: impl FnMut(&str) -> bool,
) -> (Vec<Symbol>, Vec<Symbol>) {
// Compute which of the known target features are enabled in the 'base' target machine. We only
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
let mut features: UnordSet<Symbol> = sess
.target
.rust_target_features()
.iter()
.filter(|(feature, _, _)| target_base_has_feature(feature))
.map(|(feature, _, _)| Symbol::intern(feature))
.collect();
// Add enabled and remove disabled features.
parse_rust_feature_flag(
sess,
/* err_callback */
|_| {
// Errors are already emitted in `flag_to_backend_features`; avoid duplicates.
},
|_base_feature, new_features, enabled| {
// Iteration order is irrelevant since this only influences an `UnordSet`.
#[allow(rustc::potential_query_instability)]
if enabled {
features.extend(new_features.into_iter().map(|f| Symbol::intern(f)));
} else {
// Remove `new_features` from `features`.
for new in new_features {
features.remove(&Symbol::intern(new));
}
}
},
);
// Filter enabled features based on feature gates.
let f = |allow_unstable| {
sess.target
.rust_target_features()
.iter()
.filter_map(|(feature, gate, _)| {
// The `allow_unstable` set is used by rustc internally to determine which target
// features are truly available, so we want to return even perma-unstable
// "forbidden" features.
if allow_unstable
|| (gate.in_cfg()
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(Symbol::intern(feature))
} else {
None
}
})
.filter(|feature| features.contains(&feature))
.collect()
};
(f(true), f(false))
}
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
/// combinations are allowed.
pub fn check_tied_features(
sess: &Session,
features: &FxHashMap<&str, bool>,
) -> Option<&'static [&'static str]> {
if !features.is_empty() {
for tied in sess.target.tied_target_features() {
// Tied features must be set to the same value, or not set at all
let mut tied_iter = tied.iter();
let enabled = features.get(tied_iter.next().unwrap());
if tied_iter.any(|f| enabled != features.get(f)) {
return Some(tied);
}
}
}
None
}
/// Translates the `-Ctarget-feature` flag into a backend target feature list.
///
/// `to_backend_features` converts a Rust feature name into a list of backend feature names; this is
/// used for diagnostic purposes only.
///
/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state
/// accessible by that closure) to enable/disable the given Rust feature name.
pub fn flag_to_backend_features<'a, const N: usize>(
sess: &'a Session,
diagnostics: bool,
to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>,
mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool),
) {
let known_features = sess.target.rust_target_features();
// Compute implied features
let mut rust_features = vec![];
parse_rust_feature_flag(
sess,
/* err_callback */
|feature| {
if diagnostics {
sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature });
}
},
|base_feature, new_features, enable| {
rust_features.extend(
UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)),
);
// Check feature validity.
if diagnostics {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature);
match feature_state {
None => {
// This is definitely not a valid Rust feature name. Maybe it is a backend
// feature name? If so, give a better error message.
let rust_feature =
known_features.iter().find_map(|&(rust_feature, _, _)| {
let backend_features = to_backend_features(rust_feature);
if backend_features.contains(&base_feature)
&& !backend_features.contains(&rust_feature)
{
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
errors::UnknownCTargetFeature {
feature: base_feature,
rust_feature: errors::PossibleFeature::Some { rust_feature },
}
} else {
errors::UnknownCTargetFeature {
feature: base_feature,
rust_feature: errors::PossibleFeature::None,
}
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(errors::ForbiddenCTargetFeature {
feature: base_feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(errors::UnstableCTargetFeature {
feature: base_feature,
});
}
}
}
}
},
);
if diagnostics {
// FIXME(nagisa): figure out how to not allocate a full hashmap here.
if let Some(f) = check_tied_features(
sess,
&FxHashMap::from_iter(rust_features.iter().map(|&(enable, feature)| (feature, enable))),
) {
sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable {
features: f,
span: None,
missing_features: None,
});
}
}
// Add this to the backend features.
for (enable, feature) in rust_features {
extend_backend_features(feature, enable);
}
}
/// Computes the backend target features to be added to account for retpoline flags.
/// Used by both LLVM and GCC since their target features are, conveniently, the same.
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
// -Zretpoline without -Zretpoline-external-thunk enables
// retpoline-indirect-branches and retpoline-indirect-calls target features
let unstable_opts = &sess.opts.unstable_opts;
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
features.push("+retpoline-indirect-branches".into());
features.push("+retpoline-indirect-calls".into());
}
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
// retpoline-external-thunk, retpoline-indirect-branches and
// retpoline-indirect-calls target features
if unstable_opts.retpoline_external_thunk {
features.push("+retpoline-external-thunk".into());
features.push("+retpoline-indirect-branches".into());
features.push("+retpoline-indirect-calls".into());
}
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
rust_target_features: |tcx, cnum| {
@@ -182,7 +453,8 @@ pub(crate) fn provide(providers: &mut Providers) {
Stability::Unstable { .. } | Stability::Forbidden { .. },
)
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
// The stability in the entry is at least as good as the new one, just keep it.
// The stability in the entry is at least as good as the new
// one, just keep it.
}
_ => {
// Overwrite stabilite.
@@ -463,12 +463,6 @@ pub fn check_drop_terminator(
);
}
fn crate_inject_span(&self) -> Option<Span> {
self.tcx.hir_crate_items(()).definitions().next().and_then(|id| {
self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id))
})
}
/// Check the const stability of the given item (fn or trait).
fn check_callee_stability(&mut self, def_id: DefId) {
match self.tcx.lookup_const_stability(def_id) {
@@ -543,7 +537,6 @@ fn check_callee_stability(&mut self, def_id: DefId) {
feature,
feature_enabled,
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
suggestion_span: self.crate_inject_span(),
is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait,
});
}
@@ -919,7 +912,6 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
name: intrinsic.name,
feature,
const_stable_indirect: is_const_stable,
suggestion: self.crate_inject_span(),
});
}
Some(attrs::ConstStability {
@@ -1,8 +1,8 @@
//! Concrete error types for all operations which may be invalid in a certain const context.
use hir::{ConstContext, LangItem};
use rustc_errors::Diag;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
@@ -384,7 +384,6 @@ pub(crate) struct CallUnstable {
/// expose on stable.
pub feature_enabled: bool,
pub safe_to_expose_on_stable: bool,
pub suggestion_span: Option<Span>,
/// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait.
pub is_function_call: bool,
}
@@ -412,20 +411,7 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
def_path: ccx.tcx.def_path_str(self.def_id),
})
};
// FIXME: make this translatable
let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
#[allow(rustc::untranslatable_diagnostic)]
if let Some(span) = self.suggestion_span {
err.span_suggestion_verbose(
span,
msg,
format!("#![feature({})]\n", self.feature),
Applicability::MachineApplicable,
);
} else {
err.help(msg);
}
ccx.tcx.disabled_nightly_features(&mut err, [(String::new(), self.feature)]);
err
}
}
@@ -452,7 +438,6 @@ pub(crate) struct IntrinsicUnstable {
pub name: Symbol,
pub feature: Symbol,
pub const_stable_indirect: bool,
pub suggestion: Option<Span>,
}
impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
@@ -472,8 +457,7 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
span,
name: self.name,
feature: self.feature,
suggestion: self.suggestion,
help: self.suggestion.is_none(),
suggestion: ccx.tcx.crate_level_attribute_injection_span(),
})
}
}
+1 -3
View File
@@ -136,9 +136,7 @@ pub(crate) struct UnstableIntrinsic {
code = "#![feature({feature})]\n",
applicability = "machine-applicable"
)]
pub suggestion: Option<Span>,
#[help(const_eval_unstable_intrinsic_suggestion)]
pub help: bool,
pub suggestion: Span,
}
#[derive(Diagnostic)]
+5 -1
View File
@@ -292,7 +292,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
}
HirTree => {
debug!("pretty printing HIR tree");
format!("{:#?}", ex.tcx().hir_crate(()))
ex.tcx()
.hir_crate_items(())
.owners()
.map(|owner| format!("{:#?} => {:#?}\n", owner, ex.tcx().hir_owner_nodes(owner)))
.collect()
}
Mir => {
let mut out = Vec::new();
@@ -1,8 +1,14 @@
#### Note: this error code is no longer emitted by the compiler
This is because it was too specific to the `optimize` attribute.
Similar diagnostics occur for other attributes too.
The example here will now emit `E0539`
The `optimize` attribute was malformed.
Erroneous code example:
```compile_fail,E0722
```compile_fail,E0539
#![feature(optimize_attribute)]
#[optimize(something)] // error: invalid argument
+1
View File
@@ -686,6 +686,7 @@ macro_rules! error_codes {
// E0707, // multiple elided lifetimes used in arguments of `async fn`
// E0709, // multiple different lifetimes used in arguments of `async fn`
// E0721, // `await` keyword
// E0722, // replaced with a generic attribute input check
// E0723, // unstable feature in `const` context
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
// E0744, // merged into E0728
+1 -3
View File
@@ -311,9 +311,7 @@ fn default_body_is_unstable(
reason: reason_str,
});
let inject_span = item_did
.as_local()
.and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
&tcx.sess,
@@ -1064,7 +1064,7 @@ fn ty_is_local(ty: Ty<'_>) -> bool {
Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
};
if let Some(features) = may_suggest_feature {
tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features);
tcx.disabled_nightly_features(&mut diag, features);
}
Err(diag.emit())
-6
View File
@@ -30,8 +30,6 @@ pub(crate) struct BaseExpressionDoubleDot {
)]
pub default_field_values_suggestion: Option<Span>,
#[subdiagnostic]
pub default_field_values_help: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>,
#[subdiagnostic]
pub add_expr: Option<BaseExpressionDoubleDotAddExpr>,
#[subdiagnostic]
pub remove_dots: Option<BaseExpressionDoubleDotRemove>,
@@ -61,10 +59,6 @@ pub(crate) struct BaseExpressionDoubleDotAddExpr {
pub span: Span,
}
#[derive(Subdiagnostic)]
#[help(hir_typeck_base_expression_double_dot_enable_default_field_values)]
pub(crate) struct BaseExpressionDoubleDotEnableDefaultFieldValues;
#[derive(Diagnostic)]
#[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)]
pub(crate) struct FieldMultiplySpecifiedInInitializer {
+5 -16
View File
@@ -43,10 +43,9 @@
use crate::coercion::{CoerceMany, DynamicCoerceMany};
use crate::errors::{
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove,
CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant,
ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer,
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType,
NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
};
use crate::{
@@ -2158,7 +2157,7 @@ fn check_expr_struct_fields(
}
}
if !self.tcx.features().default_field_values() {
let sugg = self.tcx.crate_level_attribute_injection_span(expr.hir_id);
let sugg = self.tcx.crate_level_attribute_injection_span();
self.dcx().emit_err(BaseExpressionDoubleDot {
span: span.shrink_to_hi(),
// We only mention enabling the feature if this is a nightly rustc *and* the
@@ -2166,18 +2165,8 @@ fn check_expr_struct_fields(
default_field_values_suggestion: if self.tcx.sess.is_nightly_build()
&& missing_mandatory_fields.is_empty()
&& !missing_optional_fields.is_empty()
&& sugg.is_some()
{
sugg
} else {
None
},
default_field_values_help: if self.tcx.sess.is_nightly_build()
&& missing_mandatory_fields.is_empty()
&& !missing_optional_fields.is_empty()
&& sugg.is_none()
{
Some(BaseExpressionDoubleDotEnableDefaultFieldValues)
Some(sugg)
} else {
None
},
@@ -1727,7 +1727,6 @@ pub(crate) fn maybe_emit_unstable_name_collision_hint(
}
tcx.disabled_nightly_features(
lint,
Some(scope_expr_id),
self.unstable_candidates.iter().map(|(candidate, feature)| {
(format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature)
}),
+2 -2
View File
@@ -1011,8 +1011,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
// Prefetch this to prevent multiple threads from blocking on it later.
// This is needed since the `hir_id_validator::check_crate` call above is not guaranteed
// to use `hir_crate`.
tcx.ensure_done().hir_crate(());
// to use `hir_crate_items`.
tcx.ensure_done().hir_crate_items(());
let sess = tcx.sess;
sess.time("misc_checking_1", || {
+1 -2
View File
@@ -1,5 +1,4 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::CRATE_OWNER_ID;
use rustc_middle::lint::LintExpectation;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -18,7 +17,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
let mut expectations = Vec::new();
for owner in std::iter::once(CRATE_OWNER_ID).chain(krate.owners()) {
for owner in krate.owners() {
let lints = tcx.shallow_lint_levels_on(owner);
expectations.extend_from_slice(&lints.expectations);
}
+8 -8
View File
@@ -328,8 +328,7 @@ pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option<ConstContext>
}
/// Returns an iterator of the `DefId`s for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir_crate(()).body_ids.iter()`.
/// crate.
#[inline]
pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
self.hir_crate_items(()).body_owners.iter().copied()
@@ -396,12 +395,11 @@ pub fn hir_walk_attributes<V>(self, visitor: &mut V) -> V::Result
where
V: Visitor<'tcx>,
{
let krate = self.hir_crate(());
for info in krate.owners.iter() {
if let MaybeOwner::Owner(info) = info {
for attrs in info.attrs.map.values() {
walk_list!(visitor, visit_attribute, *attrs);
}
let krate = self.hir_crate_items(());
for owner in krate.owners() {
let attrs = self.hir_attr_map(owner);
for attrs in attrs.map.values() {
walk_list!(visitor, visit_attribute, *attrs);
}
}
V::Result::output()
@@ -1225,6 +1223,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
..
} = collector;
ModuleItems {
add_root: false,
submodules: submodules.into_boxed_slice(),
free_items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
@@ -1260,6 +1259,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
} = collector;
ModuleItems {
add_root: true,
submodules: submodules.into_boxed_slice(),
free_items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
+7 -3
View File
@@ -24,6 +24,9 @@
/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
#[derive(Debug, HashStable, Encodable, Decodable)]
pub struct ModuleItems {
/// Whether this represents the whole crate, in which case we need to add `CRATE_OWNER_ID` to
/// the iterators if we want to account for the crate root.
add_root: bool,
submodules: Box<[OwnerId]>,
free_items: Box<[ItemId]>,
trait_items: Box<[TraitItemId]>,
@@ -66,9 +69,10 @@ pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> {
}
pub fn owners(&self) -> impl Iterator<Item = OwnerId> {
self.free_items
.iter()
.map(|id| id.owner_id)
self.add_root
.then_some(CRATE_OWNER_ID)
.into_iter()
.chain(self.free_items.iter().map(|id| id.owner_id))
.chain(self.trait_items.iter().map(|id| id.owner_id))
.chain(self.impl_items.iter().map(|id| id.owner_id))
.chain(self.foreign_items.iter().map(|id| id.owner_id))
+13 -22
View File
@@ -2113,7 +2113,7 @@ pub fn def_path_hash_to_def_index_map(
) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
// Create a dependency to the crate to be sure we re-execute this when the amount of
// definitions change.
self.ensure_ok().hir_crate(());
self.ensure_ok().hir_crate_items(());
// Freeze definitions once we start iterating on them, to prevent adding new ones
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
@@ -3160,42 +3160,33 @@ pub fn node_span_lint(
lint_level(self.sess, lint, level, Some(span.into()), decorate);
}
/// Find the crate root and the appropriate span where `use` and outer attributes can be
/// inserted at.
pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option<Span> {
for (_hir_id, node) in self.hir_parent_iter(hir_id) {
if let hir::Node::Crate(m) = node {
return Some(m.spans.inject_use_span.shrink_to_lo());
}
}
None
/// Find the appropriate span where `use` and outer attributes can be inserted at.
pub fn crate_level_attribute_injection_span(self) -> Span {
let node = self.hir_node(hir::CRATE_HIR_ID);
let hir::Node::Crate(m) = node else { bug!() };
m.spans.inject_use_span.shrink_to_lo()
}
pub fn disabled_nightly_features<E: rustc_errors::EmissionGuarantee>(
self,
diag: &mut Diag<'_, E>,
hir_id: Option<HirId>,
features: impl IntoIterator<Item = (String, Symbol)>,
) {
if !self.sess.is_nightly_build() {
return;
}
let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id));
let span = self.crate_level_attribute_injection_span();
for (desc, feature) in features {
// FIXME: make this string translatable
let msg =
format!("add `#![feature({feature})]` to the crate attributes to enable{desc}");
if let Some(span) = span {
diag.span_suggestion_verbose(
span,
msg,
format!("#![feature({feature})]\n"),
Applicability::MaybeIncorrect,
);
} else {
diag.help(msg);
}
diag.span_suggestion_verbose(
span,
msg,
format!("#![feature({feature})]\n"),
Applicability::MaybeIncorrect,
);
}
}
@@ -291,6 +291,7 @@ fn emit_malformed_attribute(
| sym::repr
| sym::align
| sym::deprecated
| sym::optimize
) {
return;
}
+5 -3
View File
@@ -128,6 +128,9 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
self.check_inline(hir_id, *attr_span, span, kind, target)
}
Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => {
self.check_optimize(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
.check_allow_internal_unstable(
hir_id,
@@ -167,7 +170,6 @@ fn check_attributes(
self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
}
[sym::coverage, ..] => self.check_coverage(attr, span, target),
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
[sym::no_sanitize, ..] => {
self.check_no_sanitize(attr, span, target)
}
@@ -529,7 +531,7 @@ fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
/// Checks that `#[optimize(..)]` is applied to a function/closure/method,
/// or to an impl block or module.
fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_optimize(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
let is_valid = matches!(
target,
Target::Fn
@@ -538,7 +540,7 @@ fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Ta
);
if !is_valid {
self.dcx().emit_err(errors::OptimizeInvalidTarget {
attr_span: attr.span(),
attr_span,
defn_span: span,
on_crate: hir_id == CRATE_HIR_ID,
});
-8
View File
@@ -40,11 +40,6 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
session_file_write_fail = failed to write `{$path}` due to error `{$err}`
session_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
@@ -137,9 +132,6 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
session_unleashed_feature_help_named = skipping check for `{$gate}` feature
session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
session_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
session_unsupported_crate_type_for_target =
-17
View File
@@ -501,20 +501,3 @@ pub(crate) struct FailedToCreateProfiler {
#[note]
#[note(session_soft_float_deprecated_issue)]
pub(crate) struct SoftFloatDeprecated;
#[derive(Diagnostic)]
#[diag(session_forbidden_ctarget_feature)]
#[note]
#[note(session_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Diagnostic)]
#[diag(session_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
-59
View File
@@ -1,59 +0,0 @@
use rustc_target::target_features::Stability;
use crate::Session;
use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
pub trait StabilityExt {
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
/// Otherwise, some features also may only be enabled by flag (target modifier).
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
/// `requires_nightly`.)
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
/// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
}
impl StabilityExt for Stability {
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
match self {
Stability::Forbidden { reason } => Err(reason),
Stability::TargetModifierOnly { reason, flag } => {
if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
}
_ => Ok(()),
}
}
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
if let Err(reason) = self.is_toggle_permitted(sess) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if self.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
}
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
// -Zretpoline without -Zretpoline-external-thunk enables
// retpoline-indirect-branches and retpoline-indirect-calls target features
let unstable_opts = &sess.opts.unstable_opts;
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
features.push("+retpoline-indirect-branches");
features.push("+retpoline-indirect-calls");
}
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
// retpoline-external-thunk, retpoline-indirect-branches and
// retpoline-indirect-calls target features
if unstable_opts.retpoline_external_thunk {
features.push("+retpoline-external-thunk");
features.push("+retpoline-indirect-branches");
features.push("+retpoline-indirect-calls");
}
}
-1
View File
@@ -29,7 +29,6 @@
pub mod output;
pub use getopts;
pub mod features;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
-8
View File
@@ -290,14 +290,6 @@ pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> {
mods.sort_by(|a, b| a.opt.cmp(&b.opt));
mods
}
pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
match flag {
"retpoline" => self.unstable_opts.retpoline,
"retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
_ => false,
}
}
}
);
}
+16 -29
View File
@@ -11,11 +11,6 @@
/// These exist globally and are not in the target-specific lists below.
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
/// Features that require special handling when passing to LLVM:
/// these are target-specific (i.e., must also be listed in the target-specific list below)
/// but do not correspond to an LLVM target feature.
pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
/// Stability information for target features.
#[derive(Debug, Copy, Clone)]
pub enum Stability {
@@ -34,9 +29,6 @@ pub enum Stability {
/// particular for features are actually ABI configuration flags (not all targets are as nice as
/// RISC-V and have an explicit way to set the ABI separate from target features).
Forbidden { reason: &'static str },
/// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set
/// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules.
TargetModifierOnly { reason: &'static str, flag: &'static str },
}
use Stability::*;
@@ -52,7 +44,6 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
Stability::Forbidden { reason } => {
reason.hash_stable(hcx, hasher);
}
Stability::TargetModifierOnly { .. } => {}
}
}
}
@@ -62,7 +53,7 @@ impl Stability {
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
/// `requires_nightly`.)
pub fn in_cfg(&self) -> bool {
!matches!(self, Stability::Forbidden { .. })
matches!(self, Stability::Stable | Stability::Unstable { .. })
}
/// Returns the nightly feature that is required to toggle this target feature via
@@ -78,7 +69,16 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
Stability::Unstable(nightly_feature) => Some(nightly_feature),
Stability::Stable { .. } => None,
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
Stability::TargetModifierOnly { .. } => None,
}
}
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
/// `requires_nightly`.)
pub fn toggle_allowed(&self) -> Result<(), &'static str> {
match self {
Stability::Unstable(_) | Stability::Stable { .. } => Ok(()),
Stability::Forbidden { reason } => Err(reason),
}
}
}
@@ -270,12 +270,7 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
// FEAT_RDM
("rdm", Stable, &["neon"]),
// This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled globally using -Zfixed-x18, not
// #[target_feature].
// Note that cfg(target_feature = "reserve-x18") is currently not set for
// targets that reserve x18 by default.
("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]),
("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]),
// FEAT_SB
("sb", Stable, &[]),
// FEAT_SHA1 & FEAT_SHA256
@@ -450,26 +445,17 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
("rdseed", Stable, &[]),
(
"retpoline-external-thunk",
Stability::TargetModifierOnly {
reason: "use `retpoline-external-thunk` target modifier flag instead",
flag: "retpoline-external-thunk",
},
Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" },
&[],
),
(
"retpoline-indirect-branches",
Stability::TargetModifierOnly {
reason: "use `retpoline` target modifier flag instead",
flag: "retpoline",
},
Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
&[],
),
(
"retpoline-indirect-calls",
Stability::TargetModifierOnly {
reason: "use `retpoline` target modifier flag instead",
flag: "retpoline",
},
Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
&[],
),
("rtm", Unstable(sym::rtm_target_feature), &[]),
@@ -732,6 +718,7 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
#[rustfmt::skip]
const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
// For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker
("backchain", Unstable(sym::s390x_target_feature), &[]),
("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
@@ -3575,11 +3575,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
}
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
tcx.disabled_nightly_features(
err,
Some(tcx.local_def_id_to_hir_id(body_id)),
[(String::new(), sym::trivial_bounds)],
);
tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]);
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
+4 -6
View File
@@ -219,21 +219,19 @@ dependencies = [
[[package]]
name = "r-efi"
version = "5.2.0"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "r-efi-alloc"
version = "2.0.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
checksum = "dc2f58ef3ca9bb0f9c44d9aa8537601bcd3df94cc9314a40178cadf7d4466354"
dependencies = [
"compiler_builtins",
"r-efi",
"rustc-std-workspace-core",
]
@@ -1,4 +1,3 @@
use std::cell::Cell;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::thread;
@@ -6,6 +5,7 @@
use super::*;
use crate::testing::crash_test::{CrashTestDummy, Panic};
use crate::testing::macros::struct_with_counted_drop;
use crate::vec::Vec;
#[test]
@@ -1010,22 +1010,6 @@ fn extract_if_drop_panic_leak() {
assert_eq!(d7.dropped(), 1);
}
macro_rules! struct_with_counted_drop {
($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => {
thread_local! {static $drop_counter: Cell<u32> = Cell::new(0);}
struct $struct_name$(($elt_ty))?;
impl Drop for $struct_name {
fn drop(&mut self) {
$drop_counter.set($drop_counter.get() + 1);
$($drop_stmt(self))?
}
}
};
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn extract_if_pred_panic_leak() {
@@ -1,9 +1,7 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
use core::iter::TrustedLen;
use super::*;
use crate::testing::macros::struct_with_counted_drop;
#[bench]
fn bench_push_back_100(b: &mut test::Bencher) {
@@ -1086,36 +1084,24 @@ fn test_clone_from() {
#[test]
fn test_vec_deque_truncate_drop() {
static mut DROPS: u32 = 0;
#[derive(Clone)]
struct Elem(#[allow(dead_code)] i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem, DROPS);
let v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
for push_front in 0..=v.len() {
let v = v.clone();
let mut tester = VecDeque::with_capacity(5);
for (index, elem) in v.into_iter().enumerate() {
const LEN: usize = 5;
for push_front in 0..=LEN {
let mut tester = VecDeque::with_capacity(LEN);
for index in 0..LEN {
if index < push_front {
tester.push_front(elem);
tester.push_front(Elem);
} else {
tester.push_back(elem);
tester.push_back(Elem);
}
}
assert_eq!(unsafe { DROPS }, 0);
assert_eq!(DROPS.get(), 0);
tester.truncate(3);
assert_eq!(unsafe { DROPS }, 2);
assert_eq!(DROPS.get(), 2);
tester.truncate(0);
assert_eq!(unsafe { DROPS }, 5);
unsafe {
DROPS = 0;
}
assert_eq!(DROPS.get(), 5);
DROPS.set(0);
}
}
+37
View File
@@ -0,0 +1,37 @@
macro_rules! struct_with_counted_drop {
($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident $( => $drop_stmt:expr )? ) => {
thread_local! {static $drop_counter: ::core::cell::Cell<u32> = ::core::cell::Cell::new(0);}
#[derive(Clone, Debug, PartialEq)]
struct $struct_name $(( $( $elt_ty ),+ ))?;
impl ::std::ops::Drop for $struct_name {
fn drop(&mut self) {
$drop_counter.set($drop_counter.get() + 1);
$($drop_stmt(self))?
}
}
};
($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident[ $drop_key:expr,$key_ty:ty ] $( => $drop_stmt:expr )? ) => {
thread_local! {
static $drop_counter: ::core::cell::RefCell<::std::collections::HashMap<$key_ty, u32>> =
::core::cell::RefCell::new(::std::collections::HashMap::new());
}
#[derive(Clone, Debug, PartialEq)]
struct $struct_name $(( $( $elt_ty ),+ ))?;
impl ::std::ops::Drop for $struct_name {
fn drop(&mut self) {
$drop_counter.with_borrow_mut(|counter| {
*counter.entry($drop_key(self)).or_default() += 1;
});
$($drop_stmt(self))?
}
}
};
}
pub(crate) use struct_with_counted_drop;
+1
View File
@@ -1,3 +1,4 @@
pub(crate) mod crash_test;
pub(crate) mod macros;
pub(crate) mod ord_chaos;
pub(crate) mod rng;
+26 -20
View File
@@ -1,6 +1,4 @@
#![deny(warnings)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
#![allow(unnecessary_transmutes)]
use std::cell::RefCell;
@@ -285,19 +283,32 @@ fn test_format_args() {
t!(s, "args were: hello world");
}
macro_rules! counter_fn {
($name:ident) => {
fn $name() -> u32 {
thread_local! {static COUNTER: ::core::cell::Cell<u32> = ::core::cell::Cell::new(0);}
COUNTER.set(COUNTER.get() + 1);
COUNTER.get()
}
};
}
#[test]
fn test_order() {
// Make sure format!() arguments are always evaluated in a left-to-right
// ordering
fn foo() -> isize {
static mut FOO: isize = 0;
unsafe {
FOO += 1;
FOO
}
}
// Make sure format!() arguments are always evaluated in a left-to-right ordering
counter_fn!(count);
assert_eq!(
format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()),
format!(
"{} {} {a} {b} {} {c}",
count(),
count(),
count(),
a = count(),
b = count(),
c = count()
),
"1 2 4 5 3 6".to_string()
);
}
@@ -306,14 +317,9 @@ fn foo() -> isize {
fn test_once() {
// Make sure each argument are evaluated only once even though it may be
// formatted multiple times
fn foo() -> isize {
static mut FOO: isize = 0;
unsafe {
FOO += 1;
FOO
}
}
assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string());
counter_fn!(count);
assert_eq!(format!("{0} {0} {0} {a} {a} {a}", count(), a = count()), "1 1 1 2 2 2".to_string());
}
#[test]
+2
View File
@@ -1,2 +1,4 @@
#[path = "../../testing/crash_test.rs"]
pub mod crash_test;
#[path = "../../testing/macros.rs"]
pub mod macros;
+29 -90
View File
@@ -1,6 +1,3 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
use core::alloc::{Allocator, Layout};
use core::num::NonZero;
use core::ptr::NonNull;
@@ -20,6 +17,8 @@
use std::sync::atomic::{AtomicU32, Ordering};
use std::vec::{Drain, IntoIter};
use crate::testing::macros::struct_with_counted_drop;
struct DropCounter<'a> {
count: &'a mut u32,
}
@@ -548,32 +547,25 @@ fn test_cmp() {
#[test]
fn test_vec_truncate_drop() {
static mut DROPS: u32 = 0;
struct Elem(#[allow(dead_code)] i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem(i32), DROPS);
let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
assert_eq!(unsafe { DROPS }, 0);
assert_eq!(DROPS.get(), 0);
v.truncate(3);
assert_eq!(unsafe { DROPS }, 2);
assert_eq!(DROPS.get(), 2);
v.truncate(0);
assert_eq!(unsafe { DROPS }, 5);
assert_eq!(DROPS.get(), 5);
}
#[test]
#[should_panic]
fn test_vec_truncate_fail() {
struct BadElem(i32);
impl Drop for BadElem {
fn drop(&mut self) {
let BadElem(ref mut x) = *self;
if *x == 0xbadbeef {
if let BadElem(0xbadbeef) = self {
panic!("BadElem panic: 0xbadbeef")
}
}
@@ -812,22 +804,7 @@ fn test_drain_end_overflow() {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_drain_leak() {
static mut DROPS: i32 = 0;
#[derive(Debug, PartialEq)]
struct D(u32, bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.1 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); });
let mut v = vec![
D(0, false),
@@ -844,7 +821,7 @@ fn drop(&mut self) {
}))
.ok();
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
}
@@ -1057,27 +1034,13 @@ fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_into_iter_leak() {
static mut DROPS: i32 = 0;
struct D(bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.0 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); });
let v = vec![D(false), D(true), D(false)];
catch_unwind(move || drop(v.into_iter())).ok();
assert_eq!(unsafe { DROPS }, 3);
assert_eq!(DROPS.get(), 3);
}
#[test]
@@ -1274,55 +1237,31 @@ fn test_from_iter_specialization_panic_during_iteration_drops() {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#[allow(static_mut_refs)]
fn test_from_iter_specialization_panic_during_drop_doesnt_leak() {
static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5];
static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2];
#[derive(Debug)]
struct Old(usize);
impl Drop for Old {
fn drop(&mut self) {
unsafe {
DROP_COUNTER_OLD[self.0] += 1;
struct_with_counted_drop!(
Old(usize), DROP_COUNTER_OLD[|this: &Old| this.0, usize] =>
|this: &Old| {
if this.0 == 3 { panic!(); } println!("Dropped Old: {}", this.0)
}
if self.0 == 3 {
panic!();
}
println!("Dropped Old: {}", self.0);
}
}
#[derive(Debug)]
struct New(usize);
impl Drop for New {
fn drop(&mut self) {
unsafe {
DROP_COUNTER_NEW[self.0] += 1;
}
println!("Dropped New: {}", self.0);
}
}
);
struct_with_counted_drop!(
New(usize), DROP_COUNTER_NEW[|this: &New| this.0, usize] =>
|this: &New| println!("Dropped New: {}", this.0)
);
let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)];
let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::<Vec<_>>();
}));
assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1);
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&2), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&3), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&4), Some(&1)));
assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1);
assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1);
DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
}
// regression test for issue #85322. Peekable previously implemented InPlaceIterable,
+18 -101
View File
@@ -1,6 +1,3 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
use core::num::NonZero;
use std::assert_matches::assert_matches;
use std::collections::TryReserveErrorKind::*;
@@ -14,6 +11,7 @@
use Taggypar::*;
use crate::hash;
use crate::testing::macros::struct_with_counted_drop;
#[test]
fn test_simple() {
@@ -719,15 +717,7 @@ fn test_show() {
#[test]
fn test_drop() {
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem, DROPS);
let mut ring = VecDeque::new();
ring.push_back(Elem);
@@ -736,20 +726,12 @@ fn drop(&mut self) {
ring.push_front(Elem);
drop(ring);
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
}
#[test]
fn test_drop_with_pop() {
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem, DROPS);
let mut ring = VecDeque::new();
ring.push_back(Elem);
@@ -759,23 +741,15 @@ fn drop(&mut self) {
drop(ring.pop_back());
drop(ring.pop_front());
assert_eq!(unsafe { DROPS }, 2);
assert_eq!(DROPS.get(), 2);
drop(ring);
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
}
#[test]
fn test_drop_clear() {
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem, DROPS);
let mut ring = VecDeque::new();
ring.push_back(Elem);
@@ -783,30 +757,16 @@ fn drop(&mut self) {
ring.push_back(Elem);
ring.push_front(Elem);
ring.clear();
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
drop(ring);
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_drop_panic() {
static mut DROPS: i32 = 0;
struct D(bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.0 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
let mut q = VecDeque::new();
q.push_back(D(false));
@@ -820,7 +780,7 @@ fn drop(&mut self) {
catch_unwind(move || drop(q)).ok();
assert_eq!(unsafe { DROPS }, 8);
assert_eq!(DROPS.get(), 8);
}
#[test]
@@ -1655,21 +1615,7 @@ fn test_try_rfold_moves_iter() {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn truncate_leak() {
static mut DROPS: i32 = 0;
struct D(bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.0 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
let mut q = VecDeque::new();
q.push_back(D(false));
@@ -1683,27 +1629,13 @@ fn drop(&mut self) {
catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok();
assert_eq!(unsafe { DROPS }, 7);
assert_eq!(DROPS.get(), 7);
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn truncate_front_leak() {
static mut DROPS: i32 = 0;
struct D(bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.0 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
let mut q = VecDeque::new();
q.push_back(D(false));
@@ -1717,28 +1649,13 @@ fn drop(&mut self) {
catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok();
assert_eq!(unsafe { DROPS }, 7);
assert_eq!(DROPS.get(), 7);
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_drain_leak() {
static mut DROPS: i32 = 0;
#[derive(Debug, PartialEq)]
struct D(u32, bool);
impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
if self.1 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); } );
let mut v = VecDeque::new();
v.push_back(D(4, false));
@@ -1754,10 +1671,10 @@ fn drop(&mut self) {
}))
.ok();
assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
assert_eq!(v.len(), 3);
drop(v);
assert_eq!(unsafe { DROPS }, 7);
assert_eq!(DROPS.get(), 7);
}
#[test]
+12 -16
View File
@@ -228,24 +228,20 @@ fn static_init() {
}
#[test]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#[allow(static_mut_refs)]
fn atomic_access_bool() {
static mut ATOMIC: AtomicBool = AtomicBool::new(false);
let mut atom = AtomicBool::new(false);
unsafe {
assert_eq!(*ATOMIC.get_mut(), false);
ATOMIC.store(true, SeqCst);
assert_eq!(*ATOMIC.get_mut(), true);
ATOMIC.fetch_or(false, SeqCst);
assert_eq!(*ATOMIC.get_mut(), true);
ATOMIC.fetch_and(false, SeqCst);
assert_eq!(*ATOMIC.get_mut(), false);
ATOMIC.fetch_nand(true, SeqCst);
assert_eq!(*ATOMIC.get_mut(), true);
ATOMIC.fetch_xor(true, SeqCst);
assert_eq!(*ATOMIC.get_mut(), false);
}
assert_eq!(*atom.get_mut(), false);
atom.store(true, SeqCst);
assert_eq!(*atom.get_mut(), true);
atom.fetch_or(false, SeqCst);
assert_eq!(*atom.get_mut(), true);
atom.fetch_and(false, SeqCst);
assert_eq!(*atom.get_mut(), false);
atom.fetch_nand(true, SeqCst);
assert_eq!(*atom.get_mut(), true);
atom.fetch_xor(true, SeqCst);
assert_eq!(*atom.get_mut(), false);
}
#[test]
+3
View File
@@ -116,6 +116,9 @@ pub mod prelude {
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[doc(no_inline)]
#[unstable(feature = "unix_send_signal", issue = "141975")]
pub use super::process::ChildExt;
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::process::{CommandExt, ExitStatusExt};
#[doc(no_inline)]
+35
View File
@@ -378,6 +378,41 @@ fn into_raw(self) -> i32 {
}
}
#[unstable(feature = "unix_send_signal", issue = "141975")]
pub trait ChildExt: Sealed {
/// Sends a signal to a child process.
///
/// # Errors
///
/// This function will return an error if the signal is invalid. The integer values associated
/// with signals are implemenation-specific, so it's encouraged to use a crate that provides
/// posix bindings.
///
/// # Examples
///
/// ```rust
/// #![feature(unix_send_signal)]
///
/// use std::{io, os::unix::process::ChildExt, process::{Command, Stdio}};
///
/// use libc::SIGTERM;
///
/// fn main() -> io::Result<()> {
/// let child = Command::new("cat").stdin(Stdio::piped()).spawn()?;
/// child.send_signal(SIGTERM)?;
/// Ok(())
/// }
/// ```
fn send_signal(&self, signal: i32) -> io::Result<()>;
}
#[unstable(feature = "unix_send_signal", issue = "141975")]
impl ChildExt for process::Child {
fn send_signal(&self, signal: i32) -> io::Result<()> {
self.handle.send_signal(signal)
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
#[inline]
+5 -1
View File
@@ -13,11 +13,15 @@
impl PidFd {
pub fn kill(&self) -> io::Result<()> {
self.send_signal(libc::SIGKILL)
}
pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
cvt(unsafe {
libc::syscall(
libc::SYS_pidfd_send_signal,
self.0.as_raw_fd(),
libc::SIGKILL,
signal,
crate::ptr::null::<()>(),
0,
)
@@ -152,6 +152,11 @@ pub fn kill(&mut self) -> io::Result<()> {
Ok(())
}
pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
// Fuchsia doesn't have a direct equivalent for signals
unimplemented!()
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
let mut proc_info: zx_info_process_t = Default::default();
let mut actual: size_t = 0;
+8 -4
View File
@@ -963,9 +963,13 @@ pub fn id(&self) -> u32 {
self.pid as u32
}
pub fn kill(&mut self) -> io::Result<()> {
pub fn kill(&self) -> io::Result<()> {
self.send_signal(libc::SIGKILL)
}
pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled
// and used for another process, and we probably shouldn't be killing
// and used for another process, and we probably shouldn't be signaling
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
return Ok(());
@@ -973,9 +977,9 @@ pub fn kill(&mut self) -> io::Result<()> {
#[cfg(target_os = "linux")]
if let Some(pid_fd) = self.pidfd.as_ref() {
// pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
return pid_fd.kill();
return pid_fd.send_signal(signal);
}
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
@@ -40,7 +40,11 @@ pub fn id(&self) -> u32 {
0
}
pub fn kill(&mut self) -> io::Result<()> {
pub fn kill(&self) -> io::Result<()> {
unsupported()
}
pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
unsupported()
}
+6 -2
View File
@@ -146,14 +146,18 @@ pub fn id(&self) -> u32 {
self.pid as u32
}
pub fn kill(&mut self) -> io::Result<()> {
pub fn kill(&self) -> io::Result<()> {
self.send_signal(libc::SIGKILL)
}
pub fn send_signal(&self, signal: i32) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled
// and used for another process, and we probably shouldn't be killing
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
Ok(())
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
}
}
+1
View File
@@ -1,6 +1,7 @@
use std::env;
fn main() {
// this is needed because `HOST` is only available to build scripts.
let host = env::var("HOST").unwrap();
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-env=BUILD_TRIPLE={host}");
-2
View File
@@ -387,8 +387,6 @@ pub(crate) fn run_global_ctxt(
ctxt.external_traits.insert(sized_trait_did, sized_trait);
}
debug!("crate: {:?}", tcx.hir_crate(()));
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
if krate.module.doc_value().is_empty() {
+2 -3
View File
@@ -18,7 +18,6 @@
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::features::StabilityExt;
use rustc_span::def_id::LOCAL_CRATE;
use rustdoc_json_types as types;
// It's important to use the FxHashMap from rustdoc_json_types here, instead of
@@ -148,7 +147,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
.copied()
.filter(|(_, stability, _)| {
// Describe only target features which the user can toggle
stability.is_toggle_permitted(sess).is_ok()
stability.toggle_allowed().is_ok()
})
.map(|(name, stability, implied_features)| {
types::TargetFeature {
@@ -164,7 +163,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
// Imply only target features which the user can toggle
feature_stability
.get(name)
.map(|stability| stability.is_toggle_permitted(sess).is_ok())
.map(|stability| stability.toggle_allowed().is_ok())
.unwrap_or(false)
})
.map(String::from)
+2 -2
View File
@@ -37,8 +37,8 @@
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
// are deliberately not in a doc comment, because they need not be in public docs.)
//
// Latest feature: Pretty printing of inline attributes changed
pub const FORMAT_VERSION: u32 = 48;
// Latest feature: Pretty printing of optimize attributes changed
pub const FORMAT_VERSION: u32 = 49;
/// The root of the emitted JSON blob.
///
+4 -1
View File
@@ -1,5 +1,5 @@
//@ add-core-stubs
//@ revisions: enable-backchain disable-backchain
//@ revisions: enable-backchain disable-backchain default-backchain
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu
//@ needs-llvm-components: systemz
@@ -26,6 +26,8 @@ extern "C" fn test_backchain() -> i32 {
// enable-backchain: stg [[REG1]], 0(%r15)
// disable-backchain: aghi %r15, -160
// disable-backchain-NOT: stg %r{{.*}}, 0(%r15)
// default-backchain: aghi %r15, -160
// default-backchain-NOT: stg %r{{.*}}, 0(%r15)
unsafe {
extern_func();
}
@@ -35,6 +37,7 @@ extern "C" fn test_backchain() -> i32 {
// Make sure that the expected return value is written into %r2 (return register):
// enable-backchain-NEXT: lghi %r2, 1
// disable-backchain: lghi %r2, 0
// default-backchain: lghi %r2, 0
#[cfg(target_feature = "backchain")]
{
1
@@ -0,0 +1,20 @@
//@ add-core-stubs
//@ needs-llvm-components: x86
//@ compile-flags: --target=x86_64-unknown-linux-gnu
//@ compile-flags: -Ctarget-feature=-avx2
#![feature(no_core, lang_items)]
#![crate_type = "lib"]
#![no_core]
extern crate minicore;
use minicore::*;
#[no_mangle]
pub unsafe fn banana() {
// CHECK-LABEL: @banana()
// CHECK-SAME: [[BANANAATTRS:#[0-9]+]] {
}
// CHECK: attributes [[BANANAATTRS]]
// CHECK-SAME: -avx512
+3 -2
View File
@@ -1,3 +1,4 @@
// ignore-tidy-linelength
//@ add-core-stubs
//@ revisions: COMPAT INCOMPAT
//@ needs-llvm-components: x86
@@ -39,7 +40,7 @@ pub unsafe fn banana() -> u32 {
// CHECK: attributes [[APPLEATTRS]]
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}"
// CHECK: attributes [[BANANAATTRS]]
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx"
// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}"
+12 -3
View File
@@ -4,14 +4,23 @@
//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
//@ needs-llvm-components: aarch64
// Rust made SVE require neon.
//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
// ENABLE_SVE: attributes #0
// ENABLE_SVE-SAME: +neon
// ENABLE_SVE-SAME: +sve
// However, disabling SVE does not disable neon.
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-sve,?)|(\+neon,?))*}}" }
// DISABLE_SVE: attributes #0
// DISABLE_SVE-NOT: -neon
// DISABLE_SVE-SAME: -sve
// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way.
//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-fp-armv8,?)|(-neon,?))*}}" }
// DISABLE_NEON: attributes #0
// DISABLE_NEON-SAME: -neon
// DISABLE_NEON-SAME: -fp-armv8
//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" }
-4
View File
@@ -211,10 +211,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`reference-types`
`relax`
`relaxed-simd`
`reserve-x18`
`retpoline-external-thunk`
`retpoline-indirect-branches`
`retpoline-indirect-calls`
`rtm`
`sb`
`scq`
@@ -11,5 +11,5 @@ fn none() {}
#[optimize(banana)]
//~^ ERROR the `#[optimize]` attribute is an experimental feature
//~| ERROR E0722
//~| ERROR malformed `optimize` attribute input [E0539]
fn not_known() {}
@@ -38,13 +38,16 @@ LL | #[optimize(banana)]
= help: add `#![feature(optimize_attribute)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0722]: invalid argument
--> $DIR/feature-gate-optimize_attribute.rs:12:12
error[E0539]: malformed `optimize` attribute input
--> $DIR/feature-gate-optimize_attribute.rs:12:1
|
LL | #[optimize(banana)]
| ^^^^^^
| ^^^^^^^^^^^------^^
| | |
| | valid arguments are `size`, `speed` or `none`
| help: must be of the form: `#[optimize(size|speed|none)]`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0658, E0722.
For more information about an error, try `rustc --explain E0658`.
Some errors have detailed explanations: E0539, E0658.
For more information about an error, try `rustc --explain E0539`.
@@ -7,13 +7,5 @@ warning: unstable feature specified for `-Ctarget-feature`: `d`
|
= note: this feature is not stably supported; its behavior can change in the future
warning: unstable feature specified for `-Ctarget-feature`: `f`
|
= note: this feature is not stably supported; its behavior can change in the future
warning: unstable feature specified for `-Ctarget-feature`: `zicsr`
|
= note: this feature is not stably supported; its behavior can change in the future
warning: 4 warnings emitted
warning: 2 warnings emitted
@@ -24,5 +24,3 @@ pub trait Freeze {}
//~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly
//~? WARN unstable feature specified for `-Ctarget-feature`
//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
@@ -1,4 +1,4 @@
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline-external-thunk` compiler flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
@@ -1,4 +1,4 @@
warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
@@ -1,4 +1,4 @@
warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
@@ -16,6 +16,6 @@
#![no_core]
extern crate minicore;
//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`
//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`
//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`