Skip to content

Commit 24569e6

Browse files
committed
Error when a type requires a target feature and the target feature isn't enabled.
1 parent 558d253 commit 24569e6

File tree

15 files changed

+152
-57
lines changed

15 files changed

+152
-57
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ pub struct ReprOptions {
143143
pub align: Option<Align>,
144144
pub pack: Option<Align>,
145145
pub flags: ReprFlags,
146+
pub target_feature: Option<u16>,
146147
/// The seed to be used for randomizing a type's layout
147148
///
148149
/// Note: This could technically be a `u128` which would

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub enum ReprAttr {
6464
ReprRust,
6565
ReprC,
6666
ReprPacked(Align),
67-
ReprSimd,
67+
ReprSimd(Option<u16>),
6868
ReprTransparent,
6969
ReprAlign(Align),
7070
}

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,28 @@ fn parse_repr<S: Stage>(
143143

144144
(Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
145145
(Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
146-
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
146+
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd(None)),
147147
(Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
148148
(Some(name @ int_pat!()), ArgParser::NoArgs) => {
149149
// int_pat!() should make sure it always parses
150150
Some(ReprInt(int_type_of_word(name).unwrap()))
151151
}
152152

153+
(Some(sym::simd), ArgParser::List(x)) => {
154+
let Some(item) = x.single() else {
155+
todo!("Handle incorrect syntax");
156+
};
157+
let Some(lit) = item.lit() else {
158+
todo!("Handle invalid lit");
159+
};
160+
match lit.kind {
161+
LitKind::Int(v, _) => {
162+
Some(ReprSimd(Some(v.0 as u16)))
163+
}
164+
_ => todo!("Handle invalid lit kind"),
165+
}
166+
}
167+
153168
(
154169
Some(
155170
name @ sym::Rust
@@ -167,7 +182,7 @@ fn parse_repr<S: Stage>(
167182
Some(
168183
name @ sym::Rust
169184
| name @ sym::C
170-
| name @ sym::simd
185+
// | name @ sym::simd
171186
| name @ sym::transparent
172187
| name @ int_pat!(),
173188
),

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in
349349
350350
codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
351351
352+
codegen_ssa_type_depends_target_feature = The `{$ty}` type depends on the target feature `{$target_feature}` being enabled
353+
352354
codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
353355
.note = {$error}
354356
.command_note = {$command_formatted}

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,3 +1310,13 @@ pub(crate) struct FeatureNotValid<'a> {
13101310
#[help]
13111311
pub plus_hint: bool,
13121312
}
1313+
1314+
#[derive(Diagnostic)]
1315+
#[diag(codegen_ssa_type_depends_target_feature)]
1316+
pub(crate) struct TypeDependsOnTargetFeature<'tcx> {
1317+
#[primary_span]
1318+
pub span: Span,
1319+
1320+
pub target_feature: String,
1321+
pub ty: Ty<'tcx>,
1322+
}

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
88
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
99
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
1010
use rustc_middle::{bug, span_bug};
11+
use rustc_span::Symbol;
1112
use tracing::debug;
1213

1314
use super::FunctionCx;
15+
use crate::errors::TypeDependsOnTargetFeature;
1416
use crate::traits::*;
1517

1618
pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -157,6 +159,30 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
157159
self.visit_local(place_ref.local, context, location);
158160
}
159161
}
162+
163+
fn check_type_abi_concerns(&self, local: mir::Local) {
164+
static IGNORED_CRATES: [&str; 3] = ["memchr", "core", "hashbrown"];
165+
166+
let ty = self.fx.mir.local_decls[local].ty;
167+
let ty = self.fx.monomorphize(ty);
168+
let ty = ty.peel_refs();
169+
170+
if let Some(abi_feature) = ty.abi_target_feature() {
171+
let tcx = self.fx.cx.tcx();
172+
let krate = tcx.crate_name(self.fx.instance.def_id().krate);
173+
if !IGNORED_CRATES.contains(&krate.as_str()) {
174+
if !self.fx.target_features.contains(&Symbol::intern(&abi_feature)) {
175+
let span = self.fx.mir.local_decls[local].source_info.span;
176+
177+
tcx.sess.dcx().emit_err(TypeDependsOnTargetFeature {
178+
span,
179+
ty,
180+
target_feature: abi_feature,
181+
});
182+
}
183+
}
184+
}
185+
}
160186
}
161187

162188
impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer<'a, 'b, 'tcx, Bx> {
@@ -189,6 +215,8 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer
189215
}
190216

191217
fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) {
218+
self.check_type_abi_concerns(local);
219+
192220
match context {
193221
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
194222
let call = location.block;

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use std::iter;
22

3+
use rustc_data_structures::fx::FxIndexSet;
34
use rustc_index::IndexVec;
45
use rustc_index::bit_set::DenseBitSet;
56
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
67
use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal};
78
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
89
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
910
use rustc_middle::{bug, mir, span_bug};
11+
use rustc_span::Symbol;
1012
use rustc_target::callconv::{FnAbi, PassMode};
1113
use tracing::{debug, instrument};
1214

@@ -120,6 +122,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
120122

121123
/// Caller location propagated if this function has `#[track_caller]`.
122124
caller_location: Option<OperandRef<'tcx, Bx::Value>>,
125+
126+
target_features: FxIndexSet<Symbol>,
123127
}
124128

125129
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -176,6 +180,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
176180

177181
let mut mir = tcx.instance_mir(instance.def);
178182

183+
let mut target_features = tcx.sess.unstable_target_features.clone();
184+
if tcx.def_kind(instance.def_id()).has_codegen_attrs() {
185+
let attrs = tcx.codegen_fn_attrs(instance.def_id());
186+
target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
187+
}
179188
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
180189
debug!("fn_abi: {:?}", fn_abi);
181190

@@ -228,6 +237,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
228237
debug_context,
229238
per_local_var_debug_info: None,
230239
caller_location: None,
240+
target_features,
231241
};
232242

233243
// It may seem like we should iterate over `required_consts` to ensure they all successfully

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,7 @@ impl<'tcx> TyCtxt<'tcx> {
15131513
let mut size = None;
15141514
let mut max_align: Option<Align> = None;
15151515
let mut min_pack: Option<Align> = None;
1516+
let mut target_feature: Option<u16> = None;
15161517

15171518
// Generate a deterministically-derived seed from the item's path hash
15181519
// to allow for cross-crate compilation to actually work
@@ -1541,7 +1542,10 @@ impl<'tcx> TyCtxt<'tcx> {
15411542
ReprFlags::empty()
15421543
}
15431544
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
1544-
attr::ReprSimd => ReprFlags::IS_SIMD,
1545+
attr::ReprSimd(feature) => {
1546+
target_feature = feature;
1547+
ReprFlags::IS_SIMD
1548+
}
15451549
attr::ReprInt(i) => {
15461550
size = Some(match i {
15471551
attr::IntType::SignedInt(x) => match x {
@@ -1586,7 +1590,14 @@ impl<'tcx> TyCtxt<'tcx> {
15861590
flags.insert(ReprFlags::IS_LINEAR);
15871591
}
15881592

1589-
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
1593+
ReprOptions {
1594+
int: size,
1595+
align: max_align,
1596+
pack: min_pack,
1597+
flags,
1598+
field_shuffle_seed,
1599+
target_feature,
1600+
}
15901601
}
15911602

15921603
/// Look up the name of a definition across crates. This does not look at HIR.

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,24 @@ impl<'tcx> Ty<'tcx> {
12021202
}
12031203
}
12041204

1205+
pub fn abi_target_feature(self) -> Option<String> {
1206+
self.ty_adt_def()
1207+
.map(|adt| {
1208+
adt.repr().target_feature.map(|id| {
1209+
String::from(match id {
1210+
0 => "neon",
1211+
1 => "sse",
1212+
2 => "sse2",
1213+
3 => "avx",
1214+
4 => "avx512f",
1215+
5 => "amx-avx512",
1216+
_ => panic!("Unknown ID: {id}"),
1217+
})
1218+
})
1219+
})
1220+
.flatten()
1221+
}
1222+
12051223
pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
12061224
let Adt(def, args) = self.kind() else {
12071225
bug!("`simd_size_and_type` called on invalid type")

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
20182018
continue;
20192019
}
20202020
}
2021-
ReprAttr::ReprSimd => {
2021+
ReprAttr::ReprSimd(_) => {
20222022
is_simd = true;
20232023
if target != Target::Struct {
20242024
self.dcx().emit_err(errors::AttrApplication::Struct {

0 commit comments

Comments
 (0)