Skip to content

Commit e61a3ab

Browse files
committed
Auto merge of rust-lang#129881 - veluca93:struct_tf, r=<try>
Implement struct_target_features for non-generic functions. This PR implements a first version of RFC 3525. In particular, the current code does not handle structs with target features being passed to generic functions correctly. This is a roll-up of rust-lang#129764, rust-lang#129783 and rust-lang#129764, which will hopefully result in a PR that does not introduce perf regressions in the first place. r? Kobzol Tracking issue: rust-lang#129107
2 parents d3a8524 + a9a1ae4 commit e61a3ab

File tree

31 files changed

+646
-42
lines changed

31 files changed

+646
-42
lines changed

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

+81-12
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
88
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
99
use rustc_hir::{lang_items, LangItem};
1010
use rustc_middle::middle::codegen_fn_attrs::{
11-
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
11+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature,
1212
};
1313
use rustc_middle::mir::mono::Linkage;
1414
use rustc_middle::query::Providers;
15-
use rustc_middle::ty::{self as ty, TyCtxt};
15+
use rustc_middle::ty::{self as ty, Ty, TyCtxt};
1616
use rustc_session::lint;
1717
use rustc_session::parse::feature_err;
1818
use rustc_span::symbol::Ident;
@@ -78,23 +78,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
7878
let mut link_ordinal_span = None;
7979
let mut no_sanitize_span = None;
8080

81+
let fn_sig_outer = || {
82+
use DefKind::*;
83+
84+
let def_kind = tcx.def_kind(did);
85+
if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { None }
86+
};
87+
8188
for attr in attrs.iter() {
8289
// In some cases, attribute are only valid on functions, but it's the `check_attr`
8390
// pass that check that they aren't used anywhere else, rather this module.
8491
// In these cases, we bail from performing further checks that are only meaningful for
8592
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
8693
// report a delayed bug, just in case `check_attr` isn't doing its job.
8794
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 {
95+
let sig = fn_sig_outer();
96+
if sig.is_none() {
9497
tcx.dcx()
9598
.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
96-
None
9799
}
100+
sig
98101
};
99102

100103
let Some(Ident { name, .. }) = attr.ident() else {
@@ -264,7 +267,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
264267
&& let Some(fn_sig) = fn_sig()
265268
&& fn_sig.skip_binder().safety() == hir::Safety::Safe
266269
{
267-
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
270+
if attr.meta_item_list().is_some_and(|list| {
271+
list.len() == 1 && list[0].ident().is_some_and(|x| x.name == sym::from_args)
272+
}) {
273+
// #[target_feature(from_args)] can be applied to safe functions and safe
274+
// trait methods.
275+
} else if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
268276
// The `#[target_feature]` attribute is allowed on
269277
// WebAssembly targets on all functions, including safe
270278
// ones. Other targets require that `#[target_feature]` is
@@ -303,6 +311,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
303311
attr,
304312
supported_target_features,
305313
&mut codegen_fn_attrs.target_features,
314+
Some(&mut codegen_fn_attrs.target_features_from_args),
306315
);
307316
}
308317
sym::linkage => {
@@ -613,7 +622,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
613622
}
614623
}
615624

616-
// If a function uses #[target_feature] it can't be inlined into general
625+
if let Some(sig) = fn_sig_outer()
626+
&& codegen_fn_attrs.target_features_from_args
627+
{
628+
let mut additional_tf = vec![];
629+
for ty in sig.skip_binder().inputs().skip_binder() {
630+
extend_with_struct_target_features(
631+
tcx,
632+
tcx.param_env(did.to_def_id()).and(*ty),
633+
&mut additional_tf,
634+
)
635+
}
636+
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
637+
tcx.dcx().span_err(
638+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
639+
"cannot use a struct with target features in a #[inline(always)] function",
640+
);
641+
}
642+
codegen_fn_attrs
643+
.target_features
644+
.extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf }));
645+
}
646+
647+
// If a function uses non-default target_features it can't be inlined into general
617648
// purpose functions as they wouldn't have the right target features
618649
// enabled. For that reason we also forbid #[inline(always)] as it can't be
619650
// respected.
@@ -755,6 +786,44 @@ fn check_link_name_xor_ordinal(
755786
}
756787
}
757788

789+
fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeature] {
790+
let mut features = vec![];
791+
let supported_features = tcx.supported_target_features(LOCAL_CRATE);
792+
for attr in tcx.get_attrs(def_id, sym::target_feature) {
793+
from_target_feature(tcx, attr, supported_features, &mut features, None);
794+
}
795+
tcx.arena.alloc_slice(&features)
796+
}
797+
798+
fn extend_with_struct_target_features<'tcx>(
799+
tcx: TyCtxt<'tcx>,
800+
env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
801+
target_features: &mut Vec<TargetFeature>,
802+
) {
803+
// Collect target features from types reachable from `env.value` by dereferencing a certain
804+
// number of references and resolving aliases.
805+
806+
let mut ty = env.value;
807+
if matches!(ty.kind(), ty::Alias(..)) {
808+
ty = match tcx.try_normalize_erasing_regions(env.param_env, ty) {
809+
Ok(ty) => ty,
810+
Err(_) => return,
811+
};
812+
}
813+
while let ty::Ref(_, inner, _) = ty.kind() {
814+
ty = *inner;
815+
}
816+
817+
if let ty::Adt(adt_def, ..) = ty.kind() {
818+
target_features.extend_from_slice(&tcx.struct_target_features(adt_def.did()));
819+
}
820+
}
821+
758822
pub fn provide(providers: &mut Providers) {
759-
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
823+
*providers = Providers {
824+
codegen_fn_attrs,
825+
should_inherit_track_caller,
826+
struct_target_features,
827+
..*providers
828+
};
760829
}

compiler/rustc_codegen_ssa/src/target_features.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub 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 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());
@@ -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 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
@@ -597,6 +597,8 @@ declare_features! (
597597
(unstable, strict_provenance, "1.61.0", Some(95228)),
598598
/// Allows string patterns to dereference values to match them.
599599
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
600+
/// Allows structs to carry target_feature information.
601+
(incomplete, struct_target_features, "CURRENT_RUSTC_VERSION", Some(129107)),
600602
/// Allows the use of `#[target_feature]` on safe functions.
601603
(unstable, target_feature_11, "1.45.0", Some(69098)),
602604
/// Allows using `#[thread_local]` on `static` items.

compiler/rustc_hir/src/def.rs

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

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

compiler/rustc_hir_typeck/src/coercion.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
850850
return Err(TypeError::IntrinsicCast);
851851
}
852852

853-
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
854-
853+
// Safe functions with explicit `#[target_feature]` attributes are not
854+
// assignable to safe fn pointers (RFC 2396).
855855
if b_hdr.safety == hir::Safety::Safe
856-
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
856+
&& self
857+
.tcx
858+
.codegen_fn_attrs(def_id)
859+
.target_features
860+
.iter()
861+
.any(|x| !x.implied)
857862
{
858863
return Err(TypeError::TargetFeatureCast(def_id));
859864
}

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>>,

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ pub struct CodegenFnAttrs {
2626
/// be set when `link_name` is set. This is for foreign items with the
2727
/// "raw-dylib" kind.
2828
pub link_ordinal: Option<u16>,
29-
/// The `#[target_feature(enable = "...")]` attribute and the enabled
30-
/// features (only enabled features are supported right now).
29+
/// All the target features that are enabled for this function. Some features might be enabled
30+
/// implicitly.
3131
pub target_features: Vec<TargetFeature>,
3232
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3333
pub linkage: Option<Linkage>,
@@ -49,14 +49,16 @@ pub struct CodegenFnAttrs {
4949
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
5050
/// the function entry.
5151
pub patchable_function_entry: Option<PatchableFunctionEntry>,
52+
/// Whether the target features can be extended through the arguments of the function.
53+
pub target_features_from_args: bool,
5254
}
5355

5456
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
5557
pub struct TargetFeature {
5658
/// The name of the target feature (e.g. "avx")
5759
pub name: Symbol,
58-
/// The feature is implied by another feature, rather than explicitly added by the
59-
/// `#[target_feature]` attribute
60+
/// The feature is implied by another feature or by an argument, rather than explicitly
61+
/// added by the `#[target_feature]` attribute
6062
pub implied: bool,
6163
}
6264

@@ -158,6 +160,7 @@ impl CodegenFnAttrs {
158160
instruction_set: None,
159161
alignment: None,
160162
patchable_function_entry: None,
163+
target_features_from_args: false,
161164
}
162165
}
163166

compiler/rustc_middle/src/query/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
4747
use crate::infer::canonical::{self, Canonical};
4848
use crate::lint::LintExpectation;
4949
use crate::metadata::ModChild;
50-
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
50+
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
5151
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
5252
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
5353
use crate::middle::lib_features::LibFeatures;
@@ -1249,6 +1249,11 @@ rustc_queries! {
12491249
feedable
12501250
}
12511251

1252+
query struct_target_features(def_id: DefId) -> &'tcx [TargetFeature] {
1253+
separate_provide_extern
1254+
desc { |tcx| "computing target features for struct `{}`", tcx.def_path_str(def_id) }
1255+
}
1256+
12521257
query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> {
12531258
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
12541259
}

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ trivially_parameterized_over_tcx! {
5959
std::string::String,
6060
crate::metadata::ModChild,
6161
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
62+
crate::middle::codegen_fn_attrs::TargetFeature,
6263
crate::middle::debugger_visualizer::DebuggerVisualizerFile,
6364
crate::middle::exported_symbols::SymbolExportInfo,
6465
crate::middle::lib_features::FeatureStability,

0 commit comments

Comments
 (0)