Skip to content

Commit 1a72d8a

Browse files
committed
Move rustc_codegen_ssa target features to rustc_session - part 2
1 parent dd9cdba commit 1a72d8a

File tree

4 files changed

+159
-155
lines changed

4 files changed

+159
-155
lines changed

compiler/rustc_codegen_llvm/src/llvm_util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ use crate::errors::{
55
};
66
use crate::llvm;
77
use libc::c_int;
8-
use rustc_codegen_ssa::target_features::{
9-
supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
10-
};
118
use rustc_codegen_ssa::traits::PrintBackendInfo;
129
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1310
use rustc_data_structures::small_c_str::SmallCStr;
1411
use rustc_fs_util::path_to_c_string;
1512
use rustc_middle::bug;
1613
use rustc_session::config::{PrintKind, PrintRequest};
14+
use rustc_session::target_features::{
15+
supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
16+
};
1717
use rustc_session::Session;
1818
use rustc_span::symbol::Symbol;
1919
use rustc_target::spec::{MergeFunctions, PanicStrategy};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use crate::errors;
2+
use rustc_ast::ast;
3+
use rustc_attr::InstructionSetAttr;
4+
use rustc_data_structures::fx::FxHashMap;
5+
use rustc_data_structures::fx::FxIndexSet;
6+
use rustc_errors::Applicability;
7+
use rustc_hir::def::DefKind;
8+
use rustc_hir::def_id::DefId;
9+
use rustc_hir::def_id::LocalDefId;
10+
use rustc_hir::def_id::LOCAL_CRATE;
11+
use rustc_middle::query::Providers;
12+
use rustc_middle::ty::TyCtxt;
13+
use rustc_session::parse::feature_err;
14+
use rustc_span::symbol::sym;
15+
use rustc_span::symbol::Symbol;
16+
use rustc_span::Span;
17+
18+
pub fn from_target_feature(
19+
tcx: TyCtxt<'_>,
20+
attr: &ast::Attribute,
21+
supported_target_features: &FxHashMap<String, Option<Symbol>>,
22+
target_features: &mut Vec<Symbol>,
23+
) {
24+
let Some(list) = attr.meta_item_list() else { return };
25+
let bad_item = |span| {
26+
let msg = "malformed `target_feature` attribute input";
27+
let code = "enable = \"..\"";
28+
tcx.sess
29+
.struct_span_err(span, msg)
30+
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
31+
.emit();
32+
};
33+
let rust_features = tcx.features();
34+
for item in list {
35+
// Only `enable = ...` is accepted in the meta-item list.
36+
if !item.has_name(sym::enable) {
37+
bad_item(item.span());
38+
continue;
39+
}
40+
41+
// Must be of the form `enable = "..."` (a string).
42+
let Some(value) = item.value_str() else {
43+
bad_item(item.span());
44+
continue;
45+
};
46+
47+
// We allow comma separation to enable multiple features.
48+
target_features.extend(value.as_str().split(',').filter_map(|feature| {
49+
let Some(feature_gate) = supported_target_features.get(feature) else {
50+
let msg = format!("the feature named `{feature}` is not valid for this target");
51+
let mut err = tcx.sess.struct_span_err(item.span(), msg);
52+
err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
53+
if let Some(stripped) = feature.strip_prefix('+') {
54+
let valid = supported_target_features.contains_key(stripped);
55+
if valid {
56+
err.help("consider removing the leading `+` in the feature name");
57+
}
58+
}
59+
err.emit();
60+
return None;
61+
};
62+
63+
// Only allow features whose feature gates have been enabled.
64+
let allowed = match feature_gate.as_ref().copied() {
65+
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
66+
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
67+
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
68+
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
69+
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
70+
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
71+
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
72+
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
73+
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
74+
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
75+
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
76+
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
77+
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
78+
Some(sym::csky_target_feature) => rust_features.csky_target_feature,
79+
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
80+
Some(name) => bug!("unknown target feature gate {}", name),
81+
None => true,
82+
};
83+
if !allowed {
84+
feature_err(
85+
&tcx.sess.parse_sess,
86+
feature_gate.unwrap(),
87+
item.span(),
88+
format!("the target feature `{feature}` is currently unstable"),
89+
)
90+
.emit();
91+
}
92+
Some(Symbol::intern(feature))
93+
}));
94+
}
95+
}
96+
97+
/// Computes the set of target features used in a function for the purposes of
98+
/// inline assembly.
99+
fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
100+
let mut target_features = tcx.sess.unstable_target_features.clone();
101+
if tcx.def_kind(did).has_codegen_attrs() {
102+
let attrs = tcx.codegen_fn_attrs(did);
103+
target_features.extend(&attrs.target_features);
104+
match attrs.instruction_set {
105+
None => {}
106+
Some(InstructionSetAttr::ArmA32) => {
107+
target_features.remove(&sym::thumb_mode);
108+
}
109+
Some(InstructionSetAttr::ArmT32) => {
110+
target_features.insert(sym::thumb_mode);
111+
}
112+
}
113+
}
114+
115+
tcx.arena.alloc(target_features)
116+
}
117+
118+
/// Checks the function annotated with `#[target_feature]` is not a safe
119+
/// trait method implementation, reporting an error if it is.
120+
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
121+
if let DefKind::AssocFn = tcx.def_kind(id) {
122+
let parent_id = tcx.local_parent(id);
123+
if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
124+
tcx.sess.emit_err(errors::TargetFeatureSafeTrait {
125+
span: attr_span,
126+
def: tcx.def_span(id),
127+
});
128+
}
129+
}
130+
}
131+
132+
pub(crate) fn provide(providers: &mut Providers) {
133+
*providers = Providers {
134+
supported_target_features: |tcx, cnum| {
135+
assert_eq!(cnum, LOCAL_CRATE);
136+
if tcx.sess.opts.actually_rustdoc {
137+
// rustdoc needs to be able to document functions that use all the features, so
138+
// whitelist them all
139+
rustc_session::target_features::all_known_features()
140+
.map(|(a, b)| (a.to_string(), b.as_feature_name()))
141+
.collect()
142+
} else {
143+
rustc_session::target_features::supported_target_features(tcx.sess)
144+
.iter()
145+
.map(|&(a, b)| (a.to_string(), b.as_feature_name()))
146+
.collect()
147+
}
148+
},
149+
asm_target_features,
150+
..*providers
151+
}
152+
}

compiler/rustc_session/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub mod cstore;
2929
pub mod filesearch;
3030
mod options;
3131
pub mod search_paths;
32+
pub mod target_features;
3233

3334
mod session;
3435
pub use session::*;

compiler/rustc_session/src/target_features.rs

+3-152
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,5 @@
1-
use crate::errors;
2-
use rustc_ast::ast;
3-
use rustc_attr::InstructionSetAttr;
4-
use rustc_data_structures::fx::FxHashMap;
5-
use rustc_data_structures::fx::FxIndexSet;
6-
use rustc_errors::Applicability;
7-
use rustc_hir::def::DefKind;
8-
use rustc_hir::def_id::DefId;
9-
use rustc_hir::def_id::LocalDefId;
10-
use rustc_hir::def_id::LOCAL_CRATE;
11-
use rustc_middle::query::Providers;
12-
use rustc_middle::ty::TyCtxt;
13-
use rustc_session::parse::feature_err;
14-
use rustc_session::Session;
151
use rustc_span::symbol::sym;
162
use rustc_span::symbol::Symbol;
17-
use rustc_span::Span;
183

194
/// Features that control behaviour of rustc, rather than the codegen.
205
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
@@ -32,7 +17,7 @@ pub enum Stability {
3217
use Stability::*;
3318

3419
impl Stability {
35-
fn as_feature_name(self) -> Option<Symbol> {
20+
pub fn as_feature_name(self) -> Option<Symbol> {
3621
match self {
3722
Stable => None,
3823
Unstable(s) => Some(s),
@@ -417,7 +402,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
417402
.cloned()
418403
}
419404

420-
pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Stability)] {
405+
pub fn supported_target_features(sess: &crate::Session) -> &'static [(&'static str, Stability)] {
421406
match &*sess.target.arch {
422407
"arm" => ARM_ALLOWED_FEATURES,
423408
"aarch64" => AARCH64_ALLOWED_FEATURES,
@@ -434,143 +419,9 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Sta
434419
}
435420
}
436421

437-
pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
422+
pub fn tied_target_features(sess: &crate::Session) -> &'static [&'static [&'static str]] {
438423
match &*sess.target.arch {
439424
"aarch64" => AARCH64_TIED_FEATURES,
440425
_ => &[],
441426
}
442427
}
443-
444-
pub fn from_target_feature(
445-
tcx: TyCtxt<'_>,
446-
attr: &ast::Attribute,
447-
supported_target_features: &FxHashMap<String, Option<Symbol>>,
448-
target_features: &mut Vec<Symbol>,
449-
) {
450-
let Some(list) = attr.meta_item_list() else { return };
451-
let bad_item = |span| {
452-
let msg = "malformed `target_feature` attribute input";
453-
let code = "enable = \"..\"";
454-
tcx.sess
455-
.struct_span_err(span, msg)
456-
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
457-
.emit();
458-
};
459-
let rust_features = tcx.features();
460-
for item in list {
461-
// Only `enable = ...` is accepted in the meta-item list.
462-
if !item.has_name(sym::enable) {
463-
bad_item(item.span());
464-
continue;
465-
}
466-
467-
// Must be of the form `enable = "..."` (a string).
468-
let Some(value) = item.value_str() else {
469-
bad_item(item.span());
470-
continue;
471-
};
472-
473-
// We allow comma separation to enable multiple features.
474-
target_features.extend(value.as_str().split(',').filter_map(|feature| {
475-
let Some(feature_gate) = supported_target_features.get(feature) else {
476-
let msg = format!("the feature named `{feature}` is not valid for this target");
477-
let mut err = tcx.sess.struct_span_err(item.span(), msg);
478-
err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
479-
if let Some(stripped) = feature.strip_prefix('+') {
480-
let valid = supported_target_features.contains_key(stripped);
481-
if valid {
482-
err.help("consider removing the leading `+` in the feature name");
483-
}
484-
}
485-
err.emit();
486-
return None;
487-
};
488-
489-
// Only allow features whose feature gates have been enabled.
490-
let allowed = match feature_gate.as_ref().copied() {
491-
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
492-
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
493-
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
494-
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
495-
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
496-
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
497-
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
498-
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
499-
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
500-
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
501-
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
502-
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
503-
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
504-
Some(sym::csky_target_feature) => rust_features.csky_target_feature,
505-
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
506-
Some(name) => bug!("unknown target feature gate {}", name),
507-
None => true,
508-
};
509-
if !allowed {
510-
feature_err(
511-
&tcx.sess.parse_sess,
512-
feature_gate.unwrap(),
513-
item.span(),
514-
format!("the target feature `{feature}` is currently unstable"),
515-
)
516-
.emit();
517-
}
518-
Some(Symbol::intern(feature))
519-
}));
520-
}
521-
}
522-
523-
/// Computes the set of target features used in a function for the purposes of
524-
/// inline assembly.
525-
fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
526-
let mut target_features = tcx.sess.unstable_target_features.clone();
527-
if tcx.def_kind(did).has_codegen_attrs() {
528-
let attrs = tcx.codegen_fn_attrs(did);
529-
target_features.extend(&attrs.target_features);
530-
match attrs.instruction_set {
531-
None => {}
532-
Some(InstructionSetAttr::ArmA32) => {
533-
target_features.remove(&sym::thumb_mode);
534-
}
535-
Some(InstructionSetAttr::ArmT32) => {
536-
target_features.insert(sym::thumb_mode);
537-
}
538-
}
539-
}
540-
541-
tcx.arena.alloc(target_features)
542-
}
543-
544-
/// Checks the function annotated with `#[target_feature]` is not a safe
545-
/// trait method implementation, reporting an error if it is.
546-
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
547-
if let DefKind::AssocFn = tcx.def_kind(id) {
548-
let parent_id = tcx.local_parent(id);
549-
if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
550-
tcx.sess.emit_err(errors::TargetFeatureSafeTrait {
551-
span: attr_span,
552-
def: tcx.def_span(id),
553-
});
554-
}
555-
}
556-
}
557-
558-
pub(crate) fn provide(providers: &mut Providers) {
559-
*providers = Providers {
560-
supported_target_features: |tcx, cnum| {
561-
assert_eq!(cnum, LOCAL_CRATE);
562-
if tcx.sess.opts.actually_rustdoc {
563-
// rustdoc needs to be able to document functions that use all the features, so
564-
// whitelist them all
565-
all_known_features().map(|(a, b)| (a.to_string(), b.as_feature_name())).collect()
566-
} else {
567-
supported_target_features(tcx.sess)
568-
.iter()
569-
.map(|&(a, b)| (a.to_string(), b.as_feature_name()))
570-
.collect()
571-
}
572-
},
573-
asm_target_features,
574-
..*providers
575-
}
576-
}

0 commit comments

Comments
 (0)