codegen_ssa: consolidate tied feature checking
`rustc_codegen_llvm` and `rustc_codegen_gcc` duplicated logic for checking if tied target features were partially enabled. This commit consolidates these checks into `rustc_codegen_ssa` in the `codegen_fn_attrs` query, which also is run pre-monomorphisation for each function, which ensures that this check is run for unused functions, as would be expected.
This commit is contained in:
parent
6edd86d58e
commit
207bc77e15
13 changed files with 100 additions and 163 deletions
|
@ -183,6 +183,8 @@ codegen_ssa_metadata_object_file_write = error writing metadata object file: {$e
|
|||
|
||||
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
|
||||
|
||||
codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
|
||||
|
||||
codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
|
||||
|
||||
codegen_ssa_missing_query_depgraph =
|
||||
|
@ -238,6 +240,9 @@ codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` fa
|
|||
|
||||
codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
|
||||
|
||||
codegen_ssa_target_feature_disable_or_enable =
|
||||
the target features {$features} must all be either enabled or disabled together
|
||||
|
||||
codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
|
||||
.label = cannot be applied to safe trait method
|
||||
.label_def = not an `unsafe` function
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr};
|
||||
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
|
@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{
|
|||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::query::Providers;
|
||||
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::symbol::Ident;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_target::spec::{SanitizerSet, abi};
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::{self, MissingFeatures, TargetFeatureDisableOrEnable};
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
|
||||
|
||||
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
||||
|
@ -662,9 +663,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(features) = check_tied_features(
|
||||
tcx.sess,
|
||||
&codegen_fn_attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.map(|features| (features.name.as_str(), true))
|
||||
.collect(),
|
||||
) {
|
||||
let span = tcx
|
||||
.get_attrs(did, sym::target_feature)
|
||||
.next()
|
||||
.map_or_else(|| tcx.def_span(did), |a| a.span);
|
||||
tcx.dcx()
|
||||
.create_err(TargetFeatureDisableOrEnable {
|
||||
features,
|
||||
span: Some(span),
|
||||
missing_features: Some(MissingFeatures),
|
||||
})
|
||||
.emit();
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_errors::codes::*;
|
|||
use rustc_errors::{
|
||||
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -1068,3 +1068,27 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
|||
pub lib_name: &'a str,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue