Auto merge of #129881 - veluca93:struct_tf, r= · rust-lang/rust@41e69d8 (original) (raw)
1
1
`use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
`
2
2
`use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
`
``
3
`+
use rustc_data_structures::fx::FxHashSet;
`
3
4
`use rustc_errors::codes::*;
`
4
5
`use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage};
`
5
6
`use rustc_hir as hir;
`
`@@ -8,15 +9,16 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
`
8
9
`use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
`
9
10
`use rustc_hir::{lang_items, LangItem};
`
10
11
`use rustc_middle::middle::codegen_fn_attrs::{
`
11
``
`-
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
`
``
12
`+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature,
`
12
13
`};
`
13
14
`use rustc_middle::mir::mono::Linkage;
`
14
15
`use rustc_middle::query::Providers;
`
15
``
`-
use rustc_middle::ty::{self as ty, TyCtxt};
`
``
16
`+
use rustc_middle::ty::{self as ty, Ty, TyCtxt};
`
16
17
`use rustc_session::lint;
`
17
18
`use rustc_session::parse::feature_err;
`
18
19
`use rustc_span::symbol::Ident;
`
19
20
`use rustc_span::{sym, Span};
`
``
21
`+
use rustc_target::abi::VariantIdx;
`
20
22
`use rustc_target::spec::{abi, SanitizerSet};
`
21
23
``
22
24
`use crate::errors;
`
`@@ -78,23 +80,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
`
78
80
`let mut link_ordinal_span = None;
`
79
81
`let mut no_sanitize_span = None;
`
80
82
``
``
83
`+
let fn_sig_outer = || {
`
``
84
`+
use DefKind::*;
`
``
85
+
``
86
`+
let def_kind = tcx.def_kind(did);
`
``
87
`+
if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { None }
`
``
88
`+
};
`
``
89
+
81
90
`for attr in attrs.iter() {
`
82
91
`` // In some cases, attribute are only valid on functions, but it's the check_attr
``
83
92
`// pass that check that they aren't used anywhere else, rather this module.
`
84
93
`// In these cases, we bail from performing further checks that are only meaningful for
`
85
94
`` // functions (such as calling fn_sig
, which ICEs if given a non-function). We also
``
86
95
`` // report a delayed bug, just in case check_attr
isn't doing its job.
``
87
96
`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 {
`
``
97
`+
let sig = fn_sig_outer();
`
``
98
`+
if sig.is_none() {
`
94
99
` tcx.dcx()
`
95
100
`.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
`
96
``
`-
None
`
97
101
`}
`
``
102
`+
sig
`
98
103
`};
`
99
104
``
100
105
`let Some(Ident { name, .. }) = attr.ident() else {
`
`@@ -613,7 +618,30 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
`
613
618
`}
`
614
619
`}
`
615
620
``
616
``
`-
// If a function uses #[target_feature] it can't be inlined into general
`
``
621
`+
if let Some(sig) = fn_sig_outer() {
`
``
622
`+
for ty in sig.skip_binder().inputs().skip_binder() {
`
``
623
`+
let additional_tf =
`
``
624
`+
tcx.struct_reachable_target_features(tcx.param_env(did.to_def_id()).and(*ty));
`
``
625
`+
// FIXME(struct_target_features): is this really necessary?
`
``
626
`+
if !additional_tf.is_empty() && sig.skip_binder().abi() != abi::Abi::Rust {
`
``
627
`+
tcx.dcx().span_err(
`
``
628
`+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
`
``
629
`+
"cannot use a struct with target features in a function with non-Rust ABI",
`
``
630
`+
);
`
``
631
`+
}
`
``
632
`+
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
`
``
633
`+
tcx.dcx().span_err(
`
``
634
`+
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
`
``
635
`+
"cannot use a struct with target features in a #[inline(always)] function",
`
``
636
`+
);
`
``
637
`+
}
`
``
638
`+
codegen_fn_attrs
`
``
639
`+
.target_features
`
``
640
`+
.extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf }));
`
``
641
`+
}
`
``
642
`+
}
`
``
643
+
``
644
`+
// If a function uses non-default target_features it can't be inlined into general
`
617
645
`// purpose functions as they wouldn't have the right target features
`
618
646
`// enabled. For that reason we also forbid #[inline(always)] as it can't be
`
619
647
`// respected.
`
`@@ -758,6 +786,91 @@ fn check_link_name_xor_ordinal(
`
758
786
`}
`
759
787
`}
`
760
788
``
``
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);
`
``
794
`+
}
`
``
795
`+
tcx.arena.alloc_slice(&features)
`
``
796
`+
}
`
``
797
+
``
798
`+
fn struct_reachable_target_features<'tcx>(
`
``
799
`+
tcx: TyCtxt<'tcx>,
`
``
800
`+
env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
`
``
801
`+
) -> &'tcx [TargetFeature] {
`
``
802
`` +
// Collect target features from types reachable from env.value
.
``
``
803
`+
// We define a type as "reachable" if:
`
``
804
`+
// - it is a function argument
`
``
805
`+
// - it is a field of a reachable struct
`
``
806
`+
// - there is a reachable reference to it
`
``
807
`+
let mut visited_types = FxHashSet::default();
`
``
808
`+
let mut reachable_types = vec![env.value];
`
``
809
`+
let mut reachable_tf = vec![];
`
``
810
+
``
811
`+
while let Some(ty) = reachable_types.pop() {
`
``
812
`+
if visited_types.contains(&ty) {
`
``
813
`+
continue;
`
``
814
`+
}
`
``
815
`+
visited_types.insert(ty);
`
``
816
`+
match ty.kind() {
`
``
817
`+
ty::Alias(..) => {
`
``
818
`+
if let Ok(t) = tcx.try_normalize_erasing_regions(env.param_env, ty) {
`
``
819
`+
reachable_types.push(t)
`
``
820
`+
}
`
``
821
`+
}
`
``
822
+
``
823
`+
ty::Ref(_, inner, _) => reachable_types.push(*inner),
`
``
824
`+
ty::Tuple(tys) => reachable_types.extend(tys.iter()),
`
``
825
`+
ty::Adt(adt_def, args) => {
`
``
826
`+
reachable_tf.extend_from_slice(tcx.struct_target_features(adt_def.did()));
`
``
827
`+
// This only recurses into structs as i.e. an Option is an ADT
`
``
828
`+
// that doesn't actually always contain a TargetFeature.
`
``
829
`+
if adt_def.is_struct() {
`
``
830
`+
reachable_types.extend(
`
``
831
`+
adt_def
`
``
832
`+
.variant(VariantIdx::from_usize(0))
`
``
833
`+
.fields
`
``
834
`+
.iter()
`
``
835
`+
.map(|field| field.ty(tcx, args)),
`
``
836
`+
);
`
``
837
`+
}
`
``
838
`+
}
`
``
839
`+
ty::Bool
`
``
840
`+
| ty::Char
`
``
841
`+
| ty::Int(..)
`
``
842
`+
| ty::Uint(..)
`
``
843
`+
| ty::Float(..)
`
``
844
`+
| ty::Foreign(..)
`
``
845
`+
| ty::Str
`
``
846
`+
| ty::Array(..)
`
``
847
`+
| ty::Pat(..)
`
``
848
`+
| ty::Slice(..)
`
``
849
`+
| ty::RawPtr(..)
`
``
850
`+
| ty::FnDef(..)
`
``
851
`+
| ty::FnPtr(..)
`
``
852
`+
| ty::Dynamic(..)
`
``
853
`+
| ty::Closure(..)
`
``
854
`+
| ty::CoroutineClosure(..)
`
``
855
`+
| ty::Coroutine(..)
`
``
856
`+
| ty::CoroutineWitness(..)
`
``
857
`+
| ty::Never
`
``
858
`+
| ty::Param(..)
`
``
859
`+
| ty::Bound(..)
`
``
860
`+
| ty::Placeholder(..)
`
``
861
`+
| ty::Infer(..)
`
``
862
`+
| ty::Error(..) => (),
`
``
863
`+
}
`
``
864
`+
}
`
``
865
`+
tcx.arena.alloc_slice(&reachable_tf)
`
``
866
`+
}
`
``
867
+
761
868
`pub fn provide(providers: &mut Providers) {
`
762
``
`-
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
`
``
869
`+
*providers = Providers {
`
``
870
`+
codegen_fn_attrs,
`
``
871
`+
should_inherit_track_caller,
`
``
872
`+
struct_target_features,
`
``
873
`+
struct_reachable_target_features,
`
``
874
`+
..*providers
`
``
875
`+
};
`
763
876
`}
`