Auto merge of #129881 - veluca93:struct_tf, r= · rust-lang/rust@15965d5 (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

`}

`