@@ -5,6 +5,7 @@ use rustc_target::abi::Align;
55use rustc_target:: spec:: SanitizerSet ;
66
77use crate :: mir:: mono:: Linkage ;
8+ use crate :: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
89
910#[ derive( Clone , TyEncodable , TyDecodable , HashStable , Debug ) ]
1011pub struct CodegenFnAttrs {
@@ -28,7 +29,7 @@ pub struct CodegenFnAttrs {
2829 pub link_ordinal : Option < u16 > ,
2930 /// All the target features that are enabled for this function. Some features might be enabled
3031 /// implicitly.
31- pub target_features : Vec < TargetFeature > ,
32+ pub def_target_features : Vec < TargetFeature > ,
3233 /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3334 pub linkage : Option < Linkage > ,
3435 /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -139,6 +140,30 @@ bitflags::bitflags! {
139140}
140141rustc_data_structures:: external_bitflags_debug! { CodegenFnAttrFlags }
141142
143+ pub fn extend_with_struct_target_features < ' tcx > (
144+ tcx : TyCtxt < ' tcx > ,
145+ env : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
146+ target_features : & mut Vec < TargetFeature > ,
147+ ) {
148+ // Collect target features from types reachable from `env.value` by dereferencing a certain
149+ // number of references and resolving aliases.
150+
151+ let mut ty = env. value ;
152+ if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
153+ ty = match tcx. try_normalize_erasing_regions ( env. param_env , ty) {
154+ Ok ( ty) => ty,
155+ Err ( _) => return ,
156+ } ;
157+ }
158+ while let ty:: Ref ( _, inner, _) = ty. kind ( ) {
159+ ty = * inner;
160+ }
161+
162+ if let ty:: Adt ( adt_def, ..) = ty. kind ( ) {
163+ target_features. extend_from_slice ( & tcx. struct_target_features ( adt_def. did ( ) ) ) ;
164+ }
165+ }
166+
142167impl CodegenFnAttrs {
143168 pub const EMPTY : & ' static Self = & Self :: new ( ) ;
144169
@@ -150,7 +175,7 @@ impl CodegenFnAttrs {
150175 export_name : None ,
151176 link_name : None ,
152177 link_ordinal : None ,
153- target_features : vec ! [ ] ,
178+ def_target_features : vec ! [ ] ,
154179 linkage : None ,
155180 import_linkage : None ,
156181 link_section : None ,
@@ -177,4 +202,59 @@ impl CodegenFnAttrs {
177202 Some ( _) => true ,
178203 }
179204 }
205+
206+ pub fn target_features_for_instance < ' tcx > (
207+ & self ,
208+ tcx : TyCtxt < ' tcx > ,
209+ param_env : ParamEnv < ' tcx > ,
210+ instance : Instance < ' tcx > ,
211+ ) -> Vec < TargetFeature > {
212+ if !self . target_features_from_args {
213+ return self . def_target_features . clone ( ) ;
214+ }
215+ let inputs = match tcx. type_of ( instance. def_id ( ) ) . skip_binder ( ) . kind ( ) {
216+ ty:: Closure ( ..) => {
217+ let closure = instance. args . as_closure ( ) ;
218+ let mut inputs =
219+ tcx. instantiate_bound_regions_with_erased ( closure. sig ( ) ) . inputs ( ) . to_vec ( ) ;
220+ inputs. extend ( closure. upvar_tys ( ) ) ;
221+ inputs
222+ }
223+ ty:: CoroutineClosure ( ..) => {
224+ let closure = instance. args . as_coroutine_closure ( ) ;
225+ // FIXME: might be missing inputs to the closure
226+ closure. upvar_tys ( ) . to_vec ( )
227+ }
228+ ty:: Coroutine ( ..) => {
229+ let coro = instance. args . as_coroutine ( ) ;
230+ coro. upvar_tys ( ) . to_vec ( )
231+ }
232+ _ => {
233+ let ty = match tcx. try_instantiate_and_normalize_erasing_regions (
234+ instance. args ,
235+ param_env,
236+ tcx. type_of ( instance. def_id ( ) ) ,
237+ ) {
238+ Ok ( ty) => ty,
239+ Err ( _) => {
240+ return self . def_target_features . clone ( ) ;
241+ }
242+ } ;
243+ let sig = tcx. instantiate_bound_regions_with_erased ( ty. fn_sig ( tcx) ) ;
244+ sig. inputs ( ) . to_vec ( )
245+ }
246+ } ;
247+ let mut additional_features = vec ! [ ] ;
248+ for input in inputs {
249+ extend_with_struct_target_features ( tcx, param_env. and ( input) , & mut additional_features) ;
250+ }
251+ if additional_features. is_empty ( ) {
252+ self . def_target_features . clone ( )
253+ } else {
254+ additional_features. extend_from_slice ( & self . def_target_features ) ;
255+ additional_features. sort_by_key ( |a| ( a. name , a. implied ) ) ;
256+ additional_features. dedup_by_key ( |a| a. name ) ;
257+ additional_features
258+ }
259+ }
180260}
0 commit comments