|
1 |
| -use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr}; |
2 |
| -use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; |
| 1 | +use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; |
| 2 | +use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; |
3 | 3 | use rustc_errors::codes::*;
|
4 |
| -use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; |
| 4 | +use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage}; |
5 | 5 | use rustc_hir as hir;
|
6 | 6 | use rustc_hir::def::DefKind;
|
7 |
| -use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; |
| 7 | +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; |
8 | 8 | use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
|
9 |
| -use rustc_hir::{LangItem, lang_items}; |
| 9 | +use rustc_hir::{lang_items, LangItem}; |
10 | 10 | use rustc_middle::middle::codegen_fn_attrs::{
|
11 |
| - CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, |
| 11 | + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature, |
12 | 12 | };
|
13 | 13 | use rustc_middle::mir::mono::Linkage;
|
14 | 14 | use rustc_middle::query::Providers;
|
15 |
| -use rustc_middle::ty::{self as ty, TyCtxt}; |
| 15 | +use rustc_middle::ty::{self as ty, Ty, TyCtxt}; |
16 | 16 | use rustc_session::lint;
|
17 | 17 | use rustc_session::parse::feature_err;
|
18 | 18 | use rustc_span::symbol::Ident;
|
19 |
| -use rustc_span::{Span, sym}; |
20 |
| -use rustc_target::spec::{SanitizerSet, abi}; |
| 19 | +use rustc_span::{sym, Span}; |
| 20 | +use rustc_target::spec::{abi, SanitizerSet}; |
21 | 21 |
|
22 | 22 | use crate::errors;
|
23 | 23 | use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
|
@@ -78,23 +78,30 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
78 | 78 | let mut link_ordinal_span = None;
|
79 | 79 | let mut no_sanitize_span = None;
|
80 | 80 |
|
| 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 { |
| 86 | + Some(tcx.fn_sig(did)) |
| 87 | + } else { |
| 88 | + None |
| 89 | + } |
| 90 | + }; |
| 91 | + |
81 | 92 | for attr in attrs.iter() {
|
82 | 93 | // In some cases, attribute are only valid on functions, but it's the `check_attr`
|
83 | 94 | // pass that check that they aren't used anywhere else, rather this module.
|
84 | 95 | // In these cases, we bail from performing further checks that are only meaningful for
|
85 | 96 | // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
86 | 97 | // report a delayed bug, just in case `check_attr` isn't doing its job.
|
87 | 98 | 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 { |
| 99 | + let sig = fn_sig_outer(); |
| 100 | + if sig.is_none() { |
94 | 101 | tcx.dcx()
|
95 | 102 | .span_delayed_bug(attr.span, "this attribute can only be applied to functions");
|
96 |
| - None |
97 | 103 | }
|
| 104 | + sig |
98 | 105 | };
|
99 | 106 |
|
100 | 107 | let Some(Ident { name, .. }) = attr.ident() else {
|
@@ -595,7 +602,30 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
595 | 602 | }
|
596 | 603 | }
|
597 | 604 |
|
598 |
| - // If a function uses #[target_feature] it can't be inlined into general |
| 605 | + if let Some(sig) = fn_sig_outer() { |
| 606 | + for ty in sig.skip_binder().inputs().skip_binder() { |
| 607 | + let additional_tf = |
| 608 | + tcx.struct_reachable_target_features(tcx.param_env(did.to_def_id()).and(*ty)); |
| 609 | + // FIXME(struct_target_features): is this really necessary? |
| 610 | + if !additional_tf.is_empty() && sig.skip_binder().abi() != abi::Abi::Rust { |
| 611 | + tcx.dcx().span_err( |
| 612 | + tcx.hir().span(tcx.local_def_id_to_hir_id(did)), |
| 613 | + "cannot use a struct with target features in a function with non-Rust ABI", |
| 614 | + ); |
| 615 | + } |
| 616 | + if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always { |
| 617 | + tcx.dcx().span_err( |
| 618 | + tcx.hir().span(tcx.local_def_id_to_hir_id(did)), |
| 619 | + "cannot use a struct with target features in a #[inline(always)] function", |
| 620 | + ); |
| 621 | + } |
| 622 | + codegen_fn_attrs |
| 623 | + .target_features |
| 624 | + .extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf })); |
| 625 | + } |
| 626 | + } |
| 627 | + |
| 628 | + // If a function uses non-default target_features it can't be inlined into general |
599 | 629 | // purpose functions as they wouldn't have the right target features
|
600 | 630 | // enabled. For that reason we also forbid #[inline(always)] as it can't be
|
601 | 631 | // respected.
|
@@ -738,6 +768,47 @@ fn check_link_name_xor_ordinal(
|
738 | 768 | }
|
739 | 769 | }
|
740 | 770 |
|
| 771 | +fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeature] { |
| 772 | + let mut features = vec![]; |
| 773 | + let supported_features = tcx.supported_target_features(LOCAL_CRATE); |
| 774 | + for attr in tcx.get_attrs(def_id, sym::target_feature) { |
| 775 | + from_target_feature(tcx, attr, supported_features, &mut features); |
| 776 | + } |
| 777 | + tcx.arena.alloc_slice(&features) |
| 778 | +} |
| 779 | + |
| 780 | +fn struct_reachable_target_features<'tcx>( |
| 781 | + tcx: TyCtxt<'tcx>, |
| 782 | + env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, |
| 783 | +) -> &'tcx [TargetFeature] { |
| 784 | + // Collect target features from types reachable from `env.value` by dereferencing a certain |
| 785 | + // number of references and resolving aliases. |
| 786 | + |
| 787 | + let mut ty = env.value; |
| 788 | + if matches!(ty.kind(), ty::Alias(..)) { |
| 789 | + ty = match tcx.try_normalize_erasing_regions(env.param_env, ty) { |
| 790 | + Ok(ty) => ty, |
| 791 | + Err(_) => return tcx.arena.alloc_slice(&[]), |
| 792 | + }; |
| 793 | + } |
| 794 | + while let ty::Ref(_, inner, _) = ty.kind() { |
| 795 | + ty = *inner; |
| 796 | + } |
| 797 | + |
| 798 | + let tf = if let ty::Adt(adt_def, ..) = ty.kind() { |
| 799 | + tcx.struct_target_features(adt_def.did()) |
| 800 | + } else { |
| 801 | + &[] |
| 802 | + }; |
| 803 | + tcx.arena.alloc_slice(tf) |
| 804 | +} |
| 805 | + |
741 | 806 | pub(crate) fn provide(providers: &mut Providers) {
|
742 |
| - *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; |
| 807 | + *providers = Providers { |
| 808 | + codegen_fn_attrs, |
| 809 | + should_inherit_track_caller, |
| 810 | + struct_target_features, |
| 811 | + struct_reachable_target_features, |
| 812 | + ..*providers |
| 813 | + }; |
743 | 814 | }
|
0 commit comments