mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}),
|
||||
|
||||
@@ -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,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);
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@
|
||||
pub mod output;
|
||||
|
||||
pub use getopts;
|
||||
pub mod features;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
pub(crate) mod crash_test;
|
||||
pub(crate) mod macros;
|
||||
pub(crate) mod ord_chaos;
|
||||
pub(crate) mod rng;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
#[path = "../../testing/crash_test.rs"]
|
||||
pub mod crash_test;
|
||||
#[path = "../../testing/macros.rs"]
|
||||
pub mod macros;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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}");
|
||||
|
||||
+1
-1
Submodule src/doc/book updated: 4433c9f0ca...8a6d44e45b
+1
-1
Submodule src/doc/reference updated: d4c66b346f...50fc1628f3
+1
-1
Submodule src/doc/rust-by-example updated: 9baa9e8631...05c7d8bae6
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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
|
||||
@@ -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{{(,-[^,]+)*}}"
|
||||
|
||||
@@ -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,?))*}}" }
|
||||
|
||||
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user