Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ab6ad4d

Browse files
committedJul 19, 2024·
WIP: first try at implementing RFC 3525.
1 parent 3d68afc commit ab6ad4d

File tree

18 files changed

+267
-31
lines changed

18 files changed

+267
-31
lines changed
 

‎compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
22
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
3+
use rustc_data_structures::fx::FxHashSet;
34
use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage};
45
use rustc_hir as hir;
56
use rustc_hir::def::DefKind;
@@ -13,8 +14,10 @@ use rustc_middle::query::Providers;
1314
use rustc_middle::ty::{self as ty, TyCtxt};
1415
use rustc_session::{lint, parse::feature_err};
1516
use rustc_span::symbol::Ident;
16-
use rustc_span::{sym, Span};
17+
use rustc_span::{sym, Span, Symbol};
18+
use rustc_target::abi::VariantIdx;
1719
use rustc_target::spec::{abi, SanitizerSet};
20+
use rustc_type_ir::inherent::*;
1821

1922
use crate::errors;
2023
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
@@ -75,23 +78,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
7578
let mut link_ordinal_span = None;
7679
let mut no_sanitize_span = None;
7780

81+
// In some cases, attribute are only valid on functions, but it's the `check_attr`
82+
// pass that check that they aren't used anywhere else, rather this module.
83+
// In these cases, we bail from performing further checks that are only meaningful for
84+
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
85+
// report a delayed bug, just in case `check_attr` isn't doing its job.
86+
let fn_sig_outer = || {
87+
use DefKind::*;
88+
89+
let def_kind = tcx.def_kind(did);
90+
if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { None }
91+
};
92+
7893
for attr in attrs.iter() {
79-
// In some cases, attribute are only valid on functions, but it's the `check_attr`
80-
// pass that check that they aren't used anywhere else, rather this module.
81-
// In these cases, we bail from performing further checks that are only meaningful for
82-
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
83-
// report a delayed bug, just in case `check_attr` isn't doing its job.
8494
let fn_sig = || {
85-
use DefKind::*;
86-
87-
let def_kind = tcx.def_kind(did);
88-
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
89-
Some(tcx.fn_sig(did))
90-
} else {
95+
let sig = fn_sig_outer();
96+
if sig.is_none() {
9197
tcx.dcx()
9298
.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
93-
None
9499
}
100+
sig
95101
};
96102

97103
let Some(Ident { name, .. }) = attr.ident() else {
@@ -610,6 +616,57 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
610616
}
611617
}
612618

619+
if tcx.features().struct_target_features
620+
&& let Some(sig) = fn_sig_outer()
621+
{
622+
// Collect target features from types reachable from arguments.
623+
// We define a type as "reachable" if:
624+
// - it is a function argument
625+
// - it is a field of a reachable struct
626+
// - there is a reachable reference to it
627+
// FIXME: we may want to cache the result of this computation.
628+
let mut visited_types = FxHashSet::default();
629+
let mut reachable_types: Vec<_> = sig.skip_binder().inputs().skip_binder().to_owned();
630+
let mut additional_tf = vec![];
631+
632+
while let Some(ty) = reachable_types.pop() {
633+
if visited_types.contains(&ty) {
634+
continue;
635+
}
636+
visited_types.insert(ty);
637+
if ty.is_ref() {
638+
reachable_types.push(ty.builtin_deref(false).unwrap());
639+
} else if matches!(ty.kind(), ty::Tuple(_)) {
640+
reachable_types.extend(ty.tuple_fields().iter());
641+
} else if let ty::Adt(adt_def, args) = ty.kind() {
642+
additional_tf.extend_from_slice(&adt_def.target_features());
643+
if adt_def.is_struct() {
644+
reachable_types.extend(
645+
adt_def
646+
.variant(VariantIdx::from_usize(0))
647+
.fields
648+
.iter()
649+
.map(|field| field.ty(tcx, args)),
650+
);
651+
}
652+
}
653+
}
654+
655+
if !additional_tf.is_empty() && !sig.skip_binder().abi().is_rust() {
656+
tcx.dcx().span_err(
657+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
658+
"cannot use a struct with target features in a function with non-Rust ABI",
659+
);
660+
}
661+
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
662+
tcx.dcx().span_err(
663+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
664+
"cannot use a struct with target features in a #[inline(always)] function",
665+
);
666+
}
667+
codegen_fn_attrs.target_features.extend_from_slice(&additional_tf);
668+
}
669+
613670
// If a function uses #[target_feature] it can't be inlined into general
614671
// purpose functions as they wouldn't have the right target features
615672
// enabled. For that reason we also forbid #[inline(always)] as it can't be
@@ -755,6 +812,20 @@ fn check_link_name_xor_ordinal(
755812
}
756813
}
757814

815+
fn struct_target_features(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<Symbol> {
816+
let mut features = vec![];
817+
let supported_features = tcx.supported_target_features(def_id.krate);
818+
for attr in tcx.get_attrs(def_id, sym::target_feature) {
819+
from_target_feature(tcx, attr, supported_features, &mut features);
820+
}
821+
features
822+
}
823+
758824
pub fn provide(providers: &mut Providers) {
759-
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
825+
*providers = Providers {
826+
codegen_fn_attrs,
827+
should_inherit_track_caller,
828+
struct_target_features,
829+
..*providers
830+
};
760831
}

‎compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,8 @@ declare_features! (
602602
(unstable, strict_provenance, "1.61.0", Some(95228)),
603603
/// Allows string patterns to dereference values to match them.
604604
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
605+
/// Allows structs to carry target_feature information.
606+
(unstable, struct_target_features, "CURRENT_RUSTC_VERSION", Some(871212)) /*FIXME*/,
605607
/// Allows the use of `#[target_feature]` on safe functions.
606608
(unstable, target_feature_11, "1.45.0", Some(69098)),
607609
/// Allows using `#[thread_local]` on `static` items.

‎compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
11471147
} else {
11481148
tcx.repr_options_of_def(def_id)
11491149
};
1150-
let (kind, variants) = match &item.kind {
1150+
let (kind, variants, features) = match &item.kind {
11511151
ItemKind::Enum(def, _) => {
11521152
let mut distance_from_explicit = 0;
11531153
let variants = def
@@ -1175,7 +1175,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
11751175
})
11761176
.collect();
11771177

1178-
(AdtKind::Enum, variants)
1178+
(AdtKind::Enum, variants, vec![])
11791179
}
11801180
ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
11811181
let adt_kind = match item.kind {
@@ -1194,11 +1194,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
11941194
))
11951195
.collect();
11961196

1197-
(adt_kind, variants)
1197+
(adt_kind, variants, tcx.struct_target_features(def_id).clone())
11981198
}
11991199
_ => bug!("{:?} is not an ADT", item.owner_id.def_id),
12001200
};
1201-
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
1201+
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, features, is_anonymous)
12021202
}
12031203

12041204
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {

‎compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11791179
adt_kind,
11801180
variants.into_iter().map(|(_, variant)| variant).collect(),
11811181
repr,
1182+
self.root
1183+
.tables
1184+
.adt_target_features
1185+
.get(self, item_id)
1186+
.expect("target features not encoded")
1187+
.decode(self)
1188+
.collect(),
11821189
false,
11831190
)
11841191
}

‎compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
15681568
record!(self.tables.fn_sig[variant.def_id] <- fn_sig);
15691569
}
15701570
}
1571+
record_array!(self.tables.adt_target_features[def_id] <- adt_def.target_features());
15711572
}
15721573

15731574
#[instrument(level = "debug", skip(self))]

‎compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ define_tables! {
459459
def_keys: Table<DefIndex, LazyValue<DefKey>>,
460460
proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
461461
variant_data: Table<DefIndex, LazyValue<VariantData>>,
462+
adt_target_features: Table<DefIndex, LazyArray<Symbol>>,
462463
assoc_container: Table<DefIndex, ty::AssocItemContainer>,
463464
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
464465
proc_macro: Table<DefIndex, MacroKind>,

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,11 @@ rustc_queries! {
12531253
feedable
12541254
}
12551255

1256+
query struct_target_features(def_id: DefId) -> &'tcx Vec<Symbol> {
1257+
arena_cache
1258+
desc { |tcx| "computing target features for struct `{}`", tcx.def_path_str(def_id) }
1259+
}
1260+
12561261
query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> {
12571262
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
12581263
}

‎compiler/rustc_middle/src/ty/adt.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
1616
use rustc_query_system::ich::StableHashingContext;
1717
use rustc_session::DataTypeKind;
1818
use rustc_span::symbol::sym;
19+
use rustc_span::Symbol;
1920
use rustc_target::abi::{ReprOptions, VariantIdx, FIRST_VARIANT};
2021
use tracing::{debug, info, trace};
2122

@@ -103,6 +104,8 @@ pub struct AdtDefData {
103104
flags: AdtFlags,
104105
/// Repr options provided by the user.
105106
repr: ReprOptions,
107+
/// Target features that functions taking objects of this type by value will enable.
108+
target_features: Vec<Symbol>,
106109
}
107110

108111
impl PartialEq for AdtDefData {
@@ -115,8 +118,8 @@ impl PartialEq for AdtDefData {
115118
// definition of `AdtDefData` changes, a compile-error will be produced,
116119
// reminding us to revisit this assumption.
117120

118-
let Self { did: self_def_id, variants: _, flags: _, repr: _ } = self;
119-
let Self { did: other_def_id, variants: _, flags: _, repr: _ } = other;
121+
let Self { did: self_def_id, variants: _, flags: _, repr: _, target_features: _ } = self;
122+
let Self { did: other_def_id, variants: _, flags: _, repr: _, target_features: _ } = other;
120123

121124
let res = self_def_id == other_def_id;
122125

@@ -153,13 +156,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData {
153156
let addr = self as *const AdtDefData as usize;
154157
let hashing_controls = hcx.hashing_controls();
155158
*cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
156-
let ty::AdtDefData { did, ref variants, ref flags, ref repr } = *self;
159+
let ty::AdtDefData { did, ref variants, ref flags, ref repr, ref target_features } =
160+
*self;
157161

158162
let mut hasher = StableHasher::new();
159163
did.hash_stable(hcx, &mut hasher);
160164
variants.hash_stable(hcx, &mut hasher);
161165
flags.hash_stable(hcx, &mut hasher);
162166
repr.hash_stable(hcx, &mut hasher);
167+
target_features.hash_stable(hcx, &mut hasher);
163168

164169
hasher.finish()
165170
})
@@ -198,6 +203,11 @@ impl<'tcx> AdtDef<'tcx> {
198203
pub fn repr(self) -> ReprOptions {
199204
self.0.0.repr
200205
}
206+
207+
#[inline]
208+
pub fn target_features(self) -> &'tcx Vec<Symbol> {
209+
&self.0.0.target_features
210+
}
201211
}
202212

203213
impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
@@ -260,6 +270,7 @@ impl AdtDefData {
260270
kind: AdtKind,
261271
variants: IndexVec<VariantIdx, VariantDef>,
262272
repr: ReprOptions,
273+
target_features: Vec<Symbol>,
263274
is_anonymous: bool,
264275
) -> Self {
265276
debug!(
@@ -302,7 +313,7 @@ impl AdtDefData {
302313
flags |= AdtFlags::IS_ANONYMOUS;
303314
}
304315

305-
AdtDefData { did, variants, flags, repr }
316+
AdtDefData { did, variants, flags, repr, target_features }
306317
}
307318
}
308319

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,7 @@ impl<'tcx> TyCtxt<'tcx> {
14291429
kind: AdtKind,
14301430
variants: IndexVec<VariantIdx, ty::VariantDef>,
14311431
repr: ReprOptions,
1432+
features: Vec<Symbol>,
14321433
is_anonymous: bool,
14331434
) -> ty::AdtDef<'tcx> {
14341435
self.mk_adt_def_from_data(ty::AdtDefData::new(
@@ -1437,6 +1438,7 @@ impl<'tcx> TyCtxt<'tcx> {
14371438
kind,
14381439
variants,
14391440
repr,
1441+
features,
14401442
is_anonymous,
14411443
))
14421444
}

‎compiler/rustc_mir_build/messages.ftl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,17 @@ mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed
125125
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
126126
.label = initializing type with `rustc_layout_scalar_valid_range` attr
127127
128+
mir_build_initializing_type_with_target_feature_requires_unsafe =
129+
initializing type with `target_feature` attr is unsafe and requires unsafe block
130+
.note = this struct can only be constructed if the corresponding `target_feature`s are available
131+
.label = initializing type with `target_feature` attr
132+
133+
mir_build_initializing_type_with_target_feature_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
134+
initializing type with `target_feature` attr is unsafe and requires unsafe function or block
135+
.note = this struct can only be constructed if the corresponding `target_feature`s are available
136+
.label = initializing type with `target_feature` attr
137+
138+
128139
mir_build_inline_assembly_requires_unsafe =
129140
use of inline assembly is unsafe and requires unsafe block
130141
.note = inline assembly is entirely unchecked and can cause undefined behavior
@@ -377,6 +388,11 @@ mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
377388
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
378389
.label = initializing type with `rustc_layout_scalar_valid_range` attr
379390
391+
mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_target_feature_requires_unsafe =
392+
initializing type with `target_feature` attr is unsafe and requires unsafe block
393+
.note = this struct can only be constructed if the corresponding `target_feature`s are available
394+
.label = initializing type with `target_feature` attr
395+
380396
mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
381397
use of inline assembly is unsafe and requires unsafe block
382398
.note = inline assembly is entirely unchecked and can cause undefined behavior

‎compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,16 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
492492
user_ty: _,
493493
fields: _,
494494
base: _,
495-
}) => match self.tcx.layout_scalar_valid_range(adt_def.did()) {
496-
(Bound::Unbounded, Bound::Unbounded) => {}
497-
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
498-
},
495+
}) => {
496+
match self.tcx.layout_scalar_valid_range(adt_def.did()) {
497+
(Bound::Unbounded, Bound::Unbounded) => {}
498+
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
499+
}
500+
if !adt_def.target_features().is_empty() {
501+
self.requires_unsafe(expr.span, ConstructingTargetFeaturesType)
502+
}
503+
}
504+
499505
ExprKind::Closure(box ClosureExpr {
500506
closure_id,
501507
args: _,
@@ -597,6 +603,7 @@ enum UnsafeOpKind {
597603
CallToUnsafeFunction(Option<DefId>),
598604
UseOfInlineAssembly,
599605
InitializingTypeWith,
606+
ConstructingTargetFeaturesType,
600607
UseOfMutableStatic,
601608
UseOfExternStatic,
602609
DerefOfRawPointer,
@@ -678,6 +685,15 @@ impl UnsafeOpKind {
678685
unsafe_not_inherited_note,
679686
},
680687
),
688+
ConstructingTargetFeaturesType => tcx.emit_node_span_lint(
689+
UNSAFE_OP_IN_UNSAFE_FN,
690+
hir_id,
691+
span,
692+
UnsafeOpInUnsafeFnInitializingTypeWithTargetFeatureRequiresUnsafe {
693+
span,
694+
unsafe_not_inherited_note,
695+
},
696+
),
681697
UseOfMutableStatic => tcx.emit_node_span_lint(
682698
UNSAFE_OP_IN_UNSAFE_FN,
683699
hir_id,
@@ -835,6 +851,20 @@ impl UnsafeOpKind {
835851
unsafe_not_inherited_note,
836852
});
837853
}
854+
ConstructingTargetFeaturesType if unsafe_op_in_unsafe_fn_allowed => {
855+
dcx.emit_err(
856+
InitializingTypeWithTargetFeatureRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
857+
span,
858+
unsafe_not_inherited_note,
859+
},
860+
);
861+
}
862+
ConstructingTargetFeaturesType => {
863+
dcx.emit_err(InitializingTypeWithTargetFeatureRequiresUnsafe {
864+
span,
865+
unsafe_not_inherited_note,
866+
});
867+
}
838868
UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
839869
dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
840870
span,

‎compiler/rustc_mir_build/src/errors.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
8585
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
8686
}
8787

88+
#[derive(LintDiagnostic)]
89+
#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_target_feature_requires_unsafe, code = E0133)]
90+
#[note]
91+
pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithTargetFeatureRequiresUnsafe {
92+
#[label]
93+
pub(crate) span: Span,
94+
#[subdiagnostic]
95+
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
96+
}
97+
8898
#[derive(LintDiagnostic)]
8999
#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe, code = E0133)]
90100
#[note]
@@ -249,6 +259,17 @@ pub(crate) struct InitializingTypeWithRequiresUnsafe {
249259
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
250260
}
251261

262+
#[derive(Diagnostic)]
263+
#[diag(mir_build_initializing_type_with_target_feature_requires_unsafe, code = E0133)]
264+
#[note]
265+
pub(crate) struct InitializingTypeWithTargetFeatureRequiresUnsafe {
266+
#[primary_span]
267+
#[label]
268+
pub(crate) span: Span,
269+
#[subdiagnostic]
270+
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
271+
}
272+
252273
#[derive(Diagnostic)]
253274
#[diag(
254275
mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
@@ -263,6 +284,20 @@ pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
263284
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
264285
}
265286

287+
#[derive(Diagnostic)]
288+
#[diag(
289+
mir_build_initializing_type_with_target_feature_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
290+
code = E0133
291+
)]
292+
#[note]
293+
pub(crate) struct InitializingTypeWithTargetFeatureRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
294+
#[primary_span]
295+
#[label]
296+
pub(crate) span: Span,
297+
#[subdiagnostic]
298+
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
299+
}
300+
266301
#[derive(Diagnostic)]
267302
#[diag(mir_build_mutable_static_requires_unsafe, code = E0133)]
268303
#[note]

‎compiler/rustc_passes/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,10 @@ passes_should_be_applied_to_fn =
652652
*[false] not a function definition
653653
}
654654
655+
passes_should_be_applied_to_fn_or_unit_struct =
656+
attribute should be applied to a function definition or unit struct
657+
.label = not a function definition or a unit struct
658+
655659
passes_should_be_applied_to_static =
656660
attribute should be applied to a static
657661
.label = not a static

‎compiler/rustc_passes/src/check_attr.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! item.
66
77
use crate::{errors, fluent_generated as fluent};
8+
use core::panic;
89
use rustc_ast::{ast, AttrKind, AttrStyle, Attribute, LitKind};
910
use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
1011
use rustc_data_structures::fx::FxHashMap;
@@ -643,12 +644,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
643644
self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
644645
true
645646
}
647+
Target::Struct if self.tcx.features().struct_target_features => {
648+
let ty = self.tcx.hir_node(hir_id).expect_item();
649+
match ty.kind {
650+
ItemKind::Struct(data, _) => {
651+
if data.fields().len() == 0 {
652+
true
653+
} else {
654+
self.dcx().emit_err(errors::AttrShouldBeAppliedToFnOrUnitStruct {
655+
attr_span: attr.span,
656+
defn_span: span,
657+
});
658+
false
659+
}
660+
}
661+
_ => {
662+
panic!("Target::Struct for a non-struct");
663+
}
664+
}
665+
}
646666
_ => {
647-
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
648-
attr_span: attr.span,
649-
defn_span: span,
650-
on_crate: hir_id == CRATE_HIR_ID,
651-
});
667+
if self.tcx.features().struct_target_features {
668+
self.dcx().emit_err(errors::AttrShouldBeAppliedToFnOrUnitStruct {
669+
attr_span: attr.span,
670+
defn_span: span,
671+
});
672+
} else {
673+
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
674+
attr_span: attr.span,
675+
defn_span: span,
676+
on_crate: hir_id == CRATE_HIR_ID,
677+
});
678+
}
652679
false
653680
}
654681
}

‎compiler/rustc_passes/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ pub struct AttrShouldBeAppliedToFn {
7979
pub on_crate: bool,
8080
}
8181

82+
#[derive(Diagnostic)]
83+
#[diag(passes_should_be_applied_to_fn_or_unit_struct)]
84+
pub struct AttrShouldBeAppliedToFnOrUnitStruct {
85+
#[primary_span]
86+
pub attr_span: Span,
87+
#[label]
88+
pub defn_span: Span,
89+
}
90+
8291
#[derive(Diagnostic)]
8392
#[diag(passes_naked_tracked_caller, code = E0736)]
8493
pub struct NakedTrackedCaller {

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,6 +1839,7 @@ symbols! {
18391839
stringify,
18401840
struct_field_attributes,
18411841
struct_inherit,
1842+
struct_target_features,
18421843
struct_variant,
18431844
structural_match,
18441845
structural_peq,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[target_feature(enable = "avx")] //~ ERROR attribute should be applied to a function definition
2+
struct Avx {}
3+
4+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: attribute should be applied to a function definition
2+
--> $DIR/feature-gate-struct-target-features.rs:1:1
3+
|
4+
LL | #[target_feature(enable = "avx")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
LL | struct Avx {}
7+
| ------------- not a function definition
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)
Please sign in to comment.