Skip to content

Commit 87ed04b

Browse files
Support target features implications in target_feature 1.1
We vendor the list of implications, which isn't nice, but t-compiler doesn't want to make rustc_target available to us.
1 parent 3bb49be commit 87ed04b

File tree

4 files changed

+268
-36
lines changed

4 files changed

+268
-36
lines changed

crates/hir-ty/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ mod inhabitedness;
3636
mod interner;
3737
mod lower;
3838
mod mapping;
39+
mod target_feature;
3940
mod tls;
4041
mod utils;
4142

@@ -107,10 +108,9 @@ pub use mapping::{
107108
to_foreign_def_id, to_placeholder_idx,
108109
};
109110
pub use method_resolution::check_orphan_rules;
111+
pub use target_feature::TargetFeatures;
110112
pub use traits::TraitEnvironment;
111-
pub use utils::{
112-
all_super_traits, direct_super_traits, is_fn_unsafe_to_call, TargetFeatures, Unsafety,
113-
};
113+
pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call, Unsafety};
114114
pub use variance::Variance;
115115

116116
pub use chalk_ir::{

crates/hir-ty/src/target_feature.rs

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
//! Stuff for handling `#[target_feature]` (needed for unsafe check).
2+
3+
use std::sync::LazyLock;
4+
5+
use hir_def::attr::Attrs;
6+
use hir_def::tt;
7+
use intern::{sym, Symbol};
8+
use rustc_hash::{FxHashMap, FxHashSet};
9+
10+
#[derive(Debug, Default)]
11+
pub struct TargetFeatures {
12+
pub(crate) enabled: FxHashSet<Symbol>,
13+
}
14+
15+
impl TargetFeatures {
16+
pub fn from_attrs(attrs: &Attrs) -> Self {
17+
let mut result = TargetFeatures::from_attrs_no_implications(attrs);
18+
result.expand_implications();
19+
result
20+
}
21+
22+
fn expand_implications(&mut self) {
23+
let all_implications = LazyLock::force(&TARGET_FEATURE_IMPLICATIONS);
24+
let mut queue = self.enabled.iter().cloned().collect::<Vec<_>>();
25+
while let Some(feature) = queue.pop() {
26+
if let Some(implications) = all_implications.get(&feature) {
27+
for implication in implications {
28+
if self.enabled.insert(implication.clone()) {
29+
queue.push(implication.clone());
30+
}
31+
}
32+
}
33+
}
34+
}
35+
36+
/// Retrieves the target features from the attributes, and does not expand the target features implied by them.
37+
pub(crate) fn from_attrs_no_implications(attrs: &Attrs) -> Self {
38+
let enabled = attrs
39+
.by_key(&sym::target_feature)
40+
.tt_values()
41+
.filter_map(|tt| {
42+
match tt.token_trees().flat_tokens() {
43+
[
44+
tt::TokenTree::Leaf(tt::Leaf::Ident(enable_ident)),
45+
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. })),
46+
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { kind: tt::LitKind::Str, symbol: features, .. })),
47+
] if enable_ident.sym == sym::enable => Some(features),
48+
_ => None,
49+
}
50+
})
51+
.flat_map(|features| features.as_str().split(',').map(Symbol::intern))
52+
.collect();
53+
Self { enabled }
54+
}
55+
}
56+
57+
// List of the target features each target feature implies.
58+
// Ideally we'd depend on rustc for this, but rustc_target doesn't compile on stable,
59+
// and t-compiler prefers for it to stay this way.
60+
61+
static TARGET_FEATURE_IMPLICATIONS: LazyLock<FxHashMap<Symbol, Box<[Symbol]>>> =
62+
LazyLock::new(|| {
63+
let mut result = FxHashMap::<Symbol, FxHashSet<Symbol>>::default();
64+
for &(feature_str, implications) in TARGET_FEATURE_IMPLICATIONS_RAW {
65+
let feature = Symbol::intern(feature_str);
66+
let implications = implications.iter().copied().map(Symbol::intern);
67+
// Some target features appear in two archs, e.g. Arm and x86.
68+
// Sometimes they contain different implications, e.g. `aes`.
69+
// We should probably choose by the active arch, but for now just merge them.
70+
result.entry(feature).or_default().extend(implications);
71+
}
72+
let mut result = result
73+
.into_iter()
74+
.map(|(feature, implications)| (feature, Box::from_iter(implications)))
75+
.collect::<FxHashMap<_, _>>();
76+
result.shrink_to_fit();
77+
result
78+
});
79+
80+
const TARGET_FEATURE_IMPLICATIONS_RAW: &[(&str, &[&str])] = &[
81+
// Arm
82+
("aes", &["neon"]),
83+
("dotprod", &["neon"]),
84+
("fp-armv8", &["vfp4"]),
85+
("fp16", &["neon"]),
86+
("i8mm", &["neon"]),
87+
("neon", &["vfp3"]),
88+
("sha2", &["neon"]),
89+
("v6", &["v5te"]),
90+
("v6k", &["v6"]),
91+
("v6t2", &["v6k", "thumb2"]),
92+
("v7", &["v6t2"]),
93+
("v8", &["v7"]),
94+
("vfp3", &["vfp2", "d32"]),
95+
("vfp4", &["vfp3"]),
96+
// Aarch64
97+
("aes", &["neon"]),
98+
("dotprod", &["neon"]),
99+
("dpb2", &["dpb"]),
100+
("f32mm", &["sve"]),
101+
("f64mm", &["sve"]),
102+
("fcma", &["neon"]),
103+
("fhm", &["fp16"]),
104+
("fp16", &["neon"]),
105+
("fp8", &["faminmax", "lut", "bf16"]),
106+
("fp8dot2", &["fp8dot4"]),
107+
("fp8dot4", &["fp8fma"]),
108+
("fp8fma", &["fp8"]),
109+
("jsconv", &["neon"]),
110+
("lse128", &["lse"]),
111+
("rcpc2", &["rcpc"]),
112+
("rcpc3", &["rcpc2"]),
113+
("rdm", &["neon"]),
114+
("sha2", &["neon"]),
115+
("sha3", &["sha2"]),
116+
("sm4", &["neon"]),
117+
("sme", &["bf16"]),
118+
("sme-b16b16", &["bf16", "sme2", "sve-b16b16"]),
119+
("sme-f16f16", &["sme2"]),
120+
("sme-f64f64", &["sme"]),
121+
("sme-f8f16", &["sme-f8f32"]),
122+
("sme-f8f32", &["sme2", "fp8"]),
123+
("sme-fa64", &["sme", "sve2"]),
124+
("sme-i16i64", &["sme"]),
125+
("sme2", &["sme"]),
126+
("sme2p1", &["sme2"]),
127+
("ssve-fp8dot2", &["ssve-fp8dot4"]),
128+
("ssve-fp8dot4", &["ssve-fp8fma"]),
129+
("ssve-fp8fma", &["sme2", "fp8"]),
130+
("sve", &["neon"]),
131+
("sve-b16b16", &["bf16"]),
132+
("sve2", &["sve"]),
133+
("sve2-aes", &["sve2", "aes"]),
134+
("sve2-bitperm", &["sve2"]),
135+
("sve2-sha3", &["sve2", "sha3"]),
136+
("sve2-sm4", &["sve2", "sm4"]),
137+
("sve2p1", &["sve2"]),
138+
("v8.1a", &["crc", "lse", "rdm", "pan", "lor", "vh"]),
139+
("v8.2a", &["v8.1a", "ras", "dpb"]),
140+
("v8.3a", &["v8.2a", "rcpc", "paca", "pacg", "jsconv"]),
141+
("v8.4a", &["v8.3a", "dotprod", "dit", "flagm"]),
142+
("v8.5a", &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
143+
("v8.6a", &["v8.5a", "bf16", "i8mm"]),
144+
("v8.7a", &["v8.6a", "wfxt"]),
145+
("v8.8a", &["v8.7a", "hbc", "mops"]),
146+
("v8.9a", &["v8.8a", "cssc"]),
147+
("v9.1a", &["v9a", "v8.6a"]),
148+
("v9.2a", &["v9.1a", "v8.7a"]),
149+
("v9.3a", &["v9.2a", "v8.8a"]),
150+
("v9.4a", &["v9.3a", "v8.9a"]),
151+
("v9.5a", &["v9.4a"]),
152+
("v9a", &["v8.5a", "sve2"]),
153+
// x86
154+
("aes", &["sse2"]),
155+
("amx-bf16", &["amx-tile"]),
156+
("amx-complex", &["amx-tile"]),
157+
("amx-fp16", &["amx-tile"]),
158+
("amx-int8", &["amx-tile"]),
159+
("avx", &["sse4.2"]),
160+
("avx2", &["avx"]),
161+
("avx512bf16", &["avx512bw"]),
162+
("avx512bitalg", &["avx512bw"]),
163+
("avx512bw", &["avx512f"]),
164+
("avx512cd", &["avx512f"]),
165+
("avx512dq", &["avx512f"]),
166+
("avx512f", &["avx2", "fma", "f16c"]),
167+
("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]),
168+
("avx512ifma", &["avx512f"]),
169+
("avx512vbmi", &["avx512bw"]),
170+
("avx512vbmi2", &["avx512bw"]),
171+
("avx512vl", &["avx512f"]),
172+
("avx512vnni", &["avx512f"]),
173+
("avx512vp2intersect", &["avx512f"]),
174+
("avx512vpopcntdq", &["avx512f"]),
175+
("avxifma", &["avx2"]),
176+
("avxneconvert", &["avx2"]),
177+
("avxvnni", &["avx2"]),
178+
("avxvnniint16", &["avx2"]),
179+
("avxvnniint8", &["avx2"]),
180+
("f16c", &["avx"]),
181+
("fma", &["avx"]),
182+
("gfni", &["sse2"]),
183+
("kl", &["sse2"]),
184+
("pclmulqdq", &["sse2"]),
185+
("sha", &["sse2"]),
186+
("sha512", &["avx2"]),
187+
("sm3", &["avx"]),
188+
("sm4", &["avx2"]),
189+
("sse2", &["sse"]),
190+
("sse3", &["sse2"]),
191+
("sse4.1", &["ssse3"]),
192+
("sse4.2", &["sse4.1"]),
193+
("sse4a", &["sse3"]),
194+
("ssse3", &["sse3"]),
195+
("vaes", &["avx2", "aes"]),
196+
("vpclmulqdq", &["avx", "pclmulqdq"]),
197+
("widekl", &["kl"]),
198+
("xop", &[/*"fma4", */ "avx", "sse4a"]),
199+
("xsavec", &["xsave"]),
200+
("xsaveopt", &["xsave"]),
201+
("xsaves", &["xsave"]),
202+
// Hexagon
203+
("hvx-length128b", &["hvx"]),
204+
// PowerPC
205+
("power10-vector", &["power9-vector"]),
206+
("power8-altivec", &["altivec"]),
207+
("power8-crypto", &["power8-altivec"]),
208+
("power8-vector", &["vsx", "power8-altivec"]),
209+
("power9-altivec", &["power8-altivec"]),
210+
("power9-vector", &["power8-vector", "power9-altivec"]),
211+
("vsx", &["altivec"]),
212+
// MIPS
213+
// RISC-V
214+
("a", &["zaamo", "zalrsc"]),
215+
("d", &["f"]),
216+
("zabha", &["zaamo"]),
217+
("zdinx", &["zfinx"]),
218+
("zfh", &["zfhmin"]),
219+
("zfhmin", &["f"]),
220+
("zhinx", &["zhinxmin"]),
221+
("zhinxmin", &["zfinx"]),
222+
("zk", &["zkn", "zkr", "zkt"]),
223+
("zkn", &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
224+
("zks", &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
225+
// WASM
226+
("relaxed-simd", &["simd128"]),
227+
// BPF
228+
("alu32", &[]),
229+
// CSKY
230+
("10e60", &["7e10"]),
231+
("2e3", &["e2"]),
232+
("3e3r2", &["3e3r1", "doloop"]),
233+
("3e3r3", &["doloop"]),
234+
("3e7", &["2e3"]),
235+
("7e10", &["3e7"]),
236+
("e1", &["elrw"]),
237+
("e2", &["e2"]),
238+
("mp", &["2e3"]),
239+
("mp1e2", &["3e7"]),
240+
// LoongArch
241+
("d", &["f"]),
242+
("lasx", &["lsx"]),
243+
("lsx", &["d"]),
244+
// IBM Z
245+
("nnp-assist", &["vector"]),
246+
("vector-enhancements-1", &["vector"]),
247+
("vector-enhancements-2", &["vector-enhancements-1"]),
248+
("vector-packed-decimal", &["vector"]),
249+
("vector-packed-decimal-enhancement", &["vector-packed-decimal"]),
250+
("vector-packed-decimal-enhancement-2", &["vector-packed-decimal-enhancement"]),
251+
// SPARC
252+
// m68k
253+
("isa-68010", &["isa-68000"]),
254+
("isa-68020", &["isa-68010"]),
255+
("isa-68030", &["isa-68020"]),
256+
("isa-68040", &["isa-68030", "isa-68882"]),
257+
("isa-68060", &["isa-68040"]),
258+
("isa-68882", &["isa-68881"]),
259+
];

crates/hir-ty/src/utils.rs

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,16 @@ use chalk_ir::{
99
DebruijnIndex,
1010
};
1111
use hir_def::{
12-
attr::Attrs,
1312
db::DefDatabase,
1413
generics::{WherePredicate, WherePredicateTypeTarget},
1514
lang_item::LangItem,
1615
resolver::{HasResolver, TypeNs},
17-
tt,
1816
type_ref::{TraitBoundModifier, TypeRef},
1917
EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
2018
TypeOrConstParamId,
2119
};
2220
use hir_expand::name::Name;
23-
use intern::{sym, Symbol};
21+
use intern::sym;
2422
use rustc_abi::TargetDataLayout;
2523
use rustc_hash::FxHashSet;
2624
use smallvec::{smallvec, SmallVec};
@@ -32,8 +30,8 @@ use crate::{
3230
db::HirDatabase,
3331
layout::{Layout, TagEncoding},
3432
mir::pad16,
35-
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
36-
Ty, WhereClause,
33+
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TargetFeatures, TraitRef,
34+
TraitRefExt, Ty, WhereClause,
3735
};
3836

3937
pub(crate) fn fn_traits(
@@ -267,32 +265,6 @@ impl<'a> ClosureSubst<'a> {
267265
}
268266
}
269267

270-
#[derive(Debug, Default)]
271-
pub struct TargetFeatures {
272-
enabled: FxHashSet<Symbol>,
273-
}
274-
275-
impl TargetFeatures {
276-
pub fn from_attrs(attrs: &Attrs) -> Self {
277-
let enabled = attrs
278-
.by_key(&sym::target_feature)
279-
.tt_values()
280-
.filter_map(|tt| {
281-
match tt.token_trees().flat_tokens() {
282-
[
283-
tt::TokenTree::Leaf(tt::Leaf::Ident(enable_ident)),
284-
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. })),
285-
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { kind: tt::LitKind::Str, symbol: features, .. })),
286-
] if enable_ident.sym == sym::enable => Some(features),
287-
_ => None,
288-
}
289-
})
290-
.flat_map(|features| features.as_str().split(',').map(Symbol::intern))
291-
.collect();
292-
Self { enabled }
293-
}
294-
}
295-
296268
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
297269
pub enum Unsafety {
298270
Safe,
@@ -314,7 +286,8 @@ pub fn is_fn_unsafe_to_call(
314286

315287
if data.has_target_feature() {
316288
// RFC 2396 <https://rust-lang.github.io/rfcs/2396-target-feature-1.1.html>.
317-
let callee_target_features = TargetFeatures::from_attrs(&db.attrs(func.into()));
289+
let callee_target_features =
290+
TargetFeatures::from_attrs_no_implications(&db.attrs(func.into()));
318291
if !caller_target_features.enabled.is_superset(&callee_target_features.enabled) {
319292
return Unsafety::Unsafe;
320293
}

crates/ide-diagnostics/src/handlers/missing_unsafe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ fn main() {
854854
#[target_feature(enable = "avx")]
855855
fn foo() {}
856856
857-
#[target_feature(enable = "avx,avx2")]
857+
#[target_feature(enable = "avx2")]
858858
fn bar() {
859859
foo();
860860
}

0 commit comments

Comments
 (0)