Skip to content

Commit 446b363

Browse files
committed
Auto merge of #129881 - veluca93:struct_tf, r=<try>
Implement struct_target_features. This PR implements a first version of RFC 3525. This is a roll-up of #129764, #129783 and #129764, which will hopefully result in a PR that does not introduce perf regressions in the first place. This PR also includes code to handle generics, unlike the original PR, since doing so influenced the design of the original PR significantly. r? Kobzol Tracking issue: #129107
2 parents 2b21f90 + d752ae8 commit 446b363

File tree

37 files changed

+751
-66
lines changed

37 files changed

+751
-66
lines changed

compiler/rustc_codegen_gcc/src/attributes.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_attr::InlineAttr;
66
use rustc_attr::InstructionSetAttr;
77
#[cfg(feature = "master")]
88
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
9-
use rustc_middle::ty;
9+
use rustc_middle::ty::{self, ParamEnv};
1010
use rustc_span::symbol::sym;
1111

1212
use crate::context::CodegenCx;
@@ -72,11 +72,10 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
7272
}
7373
}
7474

75-
let function_features = codegen_fn_attrs
76-
.target_features
77-
.iter()
78-
.map(|features| features.name.as_str())
79-
.collect::<Vec<&str>>();
75+
let function_features =
76+
codegen_fn_attrs.target_features_for_instance(cx.tcx, ParamEnv::reveal_all(), instance);
77+
let function_features =
78+
function_features.iter().map(|features| features.name.as_str()).collect::<Vec<&str>>();
8079

8180
if let Some(features) = check_tied_features(
8281
cx.tcx.sess,

compiler/rustc_codegen_llvm/src/attributes.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
44
use rustc_codegen_ssa::traits::*;
55
use rustc_hir::def_id::DefId;
66
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
7-
use rustc_middle::ty::{self, TyCtxt};
7+
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
88
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
99
use rustc_span::symbol::sym;
1010
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
@@ -500,7 +500,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
500500
to_add.extend(tune_cpu_attr(cx));
501501

502502
let function_features =
503-
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
503+
codegen_fn_attrs.target_features_for_instance(cx.tcx, ParamEnv::reveal_all(), instance);
504+
let function_features =
505+
function_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
504506

505507
if let Some(f) = llvm_util::check_tied_features(
506508
cx.tcx.sess,

compiler/rustc_codegen_ssa/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` fa
238238
239239
codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
240240
241-
codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
241+
codegen_ssa_target_feature_safe_trait = `#[target_feature(enable = ..)]` cannot be applied to safe trait method
242242
.label = cannot be applied to safe trait method
243243
.label_def = not an `unsafe` function
244244

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+62-15
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
88
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
99
use rustc_hir::{LangItem, lang_items};
1010
use rustc_middle::middle::codegen_fn_attrs::{
11-
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
11+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature,
12+
extend_with_struct_target_features,
1213
};
1314
use rustc_middle::mir::mono::Linkage;
1415
use rustc_middle::query::Providers;
@@ -78,23 +79,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
7879
let mut link_ordinal_span = None;
7980
let mut no_sanitize_span = None;
8081

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

100104
let Some(Ident { name, .. }) = attr.ident() else {
@@ -246,7 +250,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
246250
&& let Some(fn_sig) = fn_sig()
247251
&& fn_sig.skip_binder().safety() == hir::Safety::Safe
248252
{
249-
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
253+
if attr.meta_item_list().is_some_and(|list| {
254+
list.len() == 1 && list[0].ident().is_some_and(|x| x.name == sym::from_args)
255+
}) {
256+
// #[target_feature(from_args)] can be applied to safe functions and safe
257+
// trait methods.
258+
} else if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
250259
// The `#[target_feature]` attribute is allowed on
251260
// WebAssembly targets on all functions, including safe
252261
// ones. Other targets require that `#[target_feature]` is
@@ -284,7 +293,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
284293
tcx,
285294
attr,
286295
supported_target_features,
287-
&mut codegen_fn_attrs.target_features,
296+
&mut codegen_fn_attrs.def_target_features,
297+
Some(&mut codegen_fn_attrs.target_features_from_args),
288298
);
289299
}
290300
sym::linkage => {
@@ -590,16 +600,39 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
590600
let owner_id = tcx.parent(did.to_def_id());
591601
if tcx.def_kind(owner_id).has_codegen_attrs() {
592602
codegen_fn_attrs
593-
.target_features
594-
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
603+
.def_target_features
604+
.extend(tcx.codegen_fn_attrs(owner_id).def_target_features.iter().copied());
595605
}
596606
}
597607

598-
// If a function uses #[target_feature] it can't be inlined into general
608+
if let Some(sig) = fn_sig_outer()
609+
&& codegen_fn_attrs.target_features_from_args
610+
{
611+
let mut additional_tf = vec![];
612+
for ty in sig.skip_binder().inputs().skip_binder() {
613+
extend_with_struct_target_features(
614+
tcx,
615+
tcx.param_env(did.to_def_id()).and(*ty),
616+
&mut additional_tf,
617+
)
618+
}
619+
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
620+
tcx.dcx().span_err(
621+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
622+
"cannot use a struct with target features in a #[inline(always)] function",
623+
);
624+
}
625+
codegen_fn_attrs
626+
.def_target_features
627+
.extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf }));
628+
}
629+
630+
// If a function uses non-default target_features it can't be inlined into general
599631
// purpose functions as they wouldn't have the right target features
600632
// enabled. For that reason we also forbid #[inline(always)] as it can't be
601633
// respected.
602-
if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always
634+
if !codegen_fn_attrs.def_target_features.is_empty()
635+
&& codegen_fn_attrs.inline == InlineAttr::Always
603636
{
604637
if let Some(span) = inline_span {
605638
tcx.dcx().span_err(
@@ -738,6 +771,20 @@ fn check_link_name_xor_ordinal(
738771
}
739772
}
740773

774+
fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeature] {
775+
let mut features = vec![];
776+
let supported_features = tcx.supported_target_features(LOCAL_CRATE);
777+
for attr in tcx.get_attrs(def_id, sym::target_feature) {
778+
from_target_feature(tcx, attr, supported_features, &mut features, None);
779+
}
780+
tcx.arena.alloc_slice(&features)
781+
}
782+
741783
pub(crate) fn provide(providers: &mut Providers) {
742-
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
784+
*providers = Providers {
785+
codegen_fn_attrs,
786+
should_inherit_track_caller,
787+
struct_target_features,
788+
..*providers
789+
};
743790
}

compiler/rustc_codegen_ssa/src/target_features.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub(crate) fn from_target_feature(
2020
attr: &ast::Attribute,
2121
supported_target_features: &UnordMap<String, Option<Symbol>>,
2222
target_features: &mut Vec<TargetFeature>,
23+
mut features_from_args: Option<&mut bool>,
2324
) {
2425
let Some(list) = attr.meta_item_list() else { return };
2526
let bad_item = |span| {
@@ -33,6 +34,14 @@ pub(crate) fn from_target_feature(
3334
let rust_features = tcx.features();
3435
let mut added_target_features = Vec::new();
3536
for item in list {
37+
if let Some(ref mut from_args) = features_from_args
38+
&& item.ident().is_some_and(|x| x.name == sym::from_args)
39+
&& tcx.features().struct_target_features
40+
{
41+
**from_args = true;
42+
continue;
43+
}
44+
3645
// Only `enable = ...` is accepted in the meta-item list.
3746
if !item.has_name(sym::enable) {
3847
bad_item(item.span());
@@ -128,7 +137,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
128137
let mut target_features = tcx.sess.unstable_target_features.clone();
129138
if tcx.def_kind(did).has_codegen_attrs() {
130139
let attrs = tcx.codegen_fn_attrs(did);
131-
target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
140+
target_features.extend(attrs.def_target_features.iter().map(|feature| feature.name));
132141
match attrs.instruction_set {
133142
None => {}
134143
Some(InstructionSetAttr::ArmA32) => {
@@ -144,7 +153,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
144153
tcx.arena.alloc(target_features)
145154
}
146155

147-
/// Checks the function annotated with `#[target_feature]` is not a safe
156+
/// Checks the function annotated with `#[target_feature(enable = ...)]` is not a safe
148157
/// trait method implementation, reporting an error if it is.
149158
pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
150159
if let DefKind::AssocFn = tcx.def_kind(id) {

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ declare_features! (
598598
(unstable, strict_provenance, "1.61.0", Some(95228)),
599599
/// Allows string patterns to dereference values to match them.
600600
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
601+
/// Allows structs to carry target_feature information.
602+
(incomplete, struct_target_features, "CURRENT_RUSTC_VERSION", Some(129107)),
601603
/// Allows the use of `#[target_feature]` on safe functions.
602604
(unstable, target_feature_11, "1.45.0", Some(69098)),
603605
/// Allows using `#[thread_local]` on `static` items.

compiler/rustc_hir/src/def.rs

+37
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,43 @@ impl DefKind {
329329
| DefKind::ExternCrate => false,
330330
}
331331
}
332+
333+
/// Whether `query struct_target_features` should be used with this definition.
334+
pub fn has_struct_target_features(self) -> bool {
335+
match self {
336+
DefKind::Struct => true,
337+
DefKind::Fn
338+
| DefKind::Union
339+
| DefKind::Enum
340+
| DefKind::AssocFn
341+
| DefKind::Ctor(..)
342+
| DefKind::Closure
343+
| DefKind::Static { .. }
344+
| DefKind::Mod
345+
| DefKind::Variant
346+
| DefKind::Trait
347+
| DefKind::TyAlias
348+
| DefKind::ForeignTy
349+
| DefKind::TraitAlias
350+
| DefKind::AssocTy
351+
| DefKind::Const
352+
| DefKind::AssocConst
353+
| DefKind::Macro(..)
354+
| DefKind::Use
355+
| DefKind::ForeignMod
356+
| DefKind::OpaqueTy
357+
| DefKind::Impl { .. }
358+
| DefKind::Field
359+
| DefKind::TyParam
360+
| DefKind::ConstParam
361+
| DefKind::LifetimeParam
362+
| DefKind::AnonConst
363+
| DefKind::InlineConst
364+
| DefKind::SyntheticCoroutineBody
365+
| DefKind::GlobalAsm
366+
| DefKind::ExternCrate => false,
367+
}
368+
}
332369
}
333370

334371
/// The resolution of a path or export.

compiler/rustc_hir_analysis/src/check/entry.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
105105
error = true;
106106
}
107107

108-
if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
108+
if !tcx.codegen_fn_attrs(main_def_id).def_target_features.is_empty()
109109
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
110110
&& !tcx.sess.target.is_like_wasm
111111
&& !tcx.sess.opts.actually_rustdoc

compiler/rustc_hir_typeck/src/coercion.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -909,10 +909,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
909909
return Err(TypeError::IntrinsicCast);
910910
}
911911

912-
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
913-
912+
// Safe functions with explicit `#[target_feature]` attributes are not
913+
// assignable to safe fn pointers (RFC 2396).
914914
if b_hdr.safety == hir::Safety::Safe
915-
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
915+
&& self
916+
.tcx
917+
.codegen_fn_attrs(def_id)
918+
.def_target_features
919+
.iter()
920+
.any(|x| !x.implied)
916921
{
917922
return Err(TypeError::TargetFeatureCast(def_id));
918923
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ provide! { tcx, def_id, other, cdata,
254254
variances_of => { table }
255255
fn_sig => { table }
256256
codegen_fn_attrs => { table }
257+
struct_target_features => { table_defaulted_array }
257258
impl_trait_header => { table }
258259
const_param_default => { table }
259260
object_lifetime_default => { table }

compiler/rustc_metadata/src/rmeta/encoder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13981398
if def_kind.has_codegen_attrs() {
13991399
record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
14001400
}
1401+
if def_kind.has_struct_target_features() {
1402+
record_defaulted_array!(self.tables.struct_target_features[def_id] <- self.tcx.struct_target_features(def_id));
1403+
}
14011404
if should_encode_visibility(def_kind) {
14021405
let vis =
14031406
self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index);

compiler/rustc_metadata/src/rmeta/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_macros::{
1919
Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, TyEncodable,
2020
};
2121
use rustc_middle::metadata::ModChild;
22-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
22+
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
2323
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2424
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2525
use rustc_middle::middle::lib_features::FeatureStability;
@@ -404,6 +404,7 @@ define_tables! {
404404
// individually instead of `DefId`s.
405405
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
406406
cross_crate_inlinable: Table<DefIndex, bool>,
407+
struct_target_features: Table<DefIndex, LazyArray<TargetFeature>>,
407408

408409
- optional:
409410
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,

0 commit comments

Comments
 (0)