10
10
//! Set and unset common attributes on LLVM values.
11
11
12
12
use std:: ffi:: { CStr , CString } ;
13
+ use std:: rc:: Rc ;
13
14
15
+ use rustc:: hir:: Unsafety ;
16
+ use rustc:: hir:: def_id:: { DefId , LOCAL_CRATE } ;
14
17
use rustc:: session:: config:: Sanitizer ;
18
+ use rustc:: ty:: TyCtxt ;
19
+ use rustc:: ty:: maps:: Providers ;
20
+ use rustc_data_structures:: fx:: FxHashSet ;
15
21
16
22
use llvm:: { self , Attribute , ValueRef } ;
17
23
use llvm:: AttributePlace :: Function ;
24
+ use llvm_util;
18
25
pub use syntax:: attr:: { self , InlineAttr } ;
19
26
use syntax:: ast;
20
27
use context:: CrateContext ;
@@ -94,23 +101,16 @@ pub fn set_probestack(ccx: &CrateContext, llfn: ValueRef) {
94
101
95
102
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
96
103
/// attributes.
97
- pub fn from_fn_attrs ( ccx : & CrateContext , attrs : & [ ast :: Attribute ] , llfn : ValueRef ) {
104
+ pub fn from_fn_attrs ( ccx : & CrateContext , llfn : ValueRef , id : DefId ) {
98
105
use syntax:: attr:: * ;
99
- inline ( llfn, find_inline_attr ( Some ( ccx. sess ( ) . diagnostic ( ) ) , attrs) ) ;
106
+ let attrs = ccx. tcx ( ) . get_attrs ( id) ;
107
+ inline ( llfn, find_inline_attr ( Some ( ccx. sess ( ) . diagnostic ( ) ) , & attrs) ) ;
100
108
101
109
set_frame_pointer_elimination ( ccx, llfn) ;
102
110
set_probestack ( ccx, llfn) ;
103
- let mut target_features = vec ! [ ] ;
104
- for attr in attrs {
105
- if attr. check_name ( "target_feature" ) {
106
- if let Some ( val) = attr. value_str ( ) {
107
- for feat in val. as_str ( ) . split ( "," ) . map ( |f| f. trim ( ) ) {
108
- if !feat. is_empty ( ) && !feat. contains ( '\0' ) {
109
- target_features. push ( feat. to_string ( ) ) ;
110
- }
111
- }
112
- }
113
- } else if attr. check_name ( "cold" ) {
111
+
112
+ for attr in attrs. iter ( ) {
113
+ if attr. check_name ( "cold" ) {
114
114
Attribute :: Cold . apply_llfn ( Function , llfn) ;
115
115
} else if attr. check_name ( "naked" ) {
116
116
naked ( llfn, true ) ;
@@ -123,6 +123,8 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
123
123
unwind ( llfn, false ) ;
124
124
}
125
125
}
126
+
127
+ let target_features = ccx. tcx ( ) . target_features_enabled ( id) ;
126
128
if !target_features. is_empty ( ) {
127
129
let val = CString :: new ( target_features. join ( "," ) ) . unwrap ( ) ;
128
130
llvm:: AddFunctionAttrStringValue (
@@ -134,3 +136,97 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
134
136
fn cstr ( s : & ' static str ) -> & CStr {
135
137
CStr :: from_bytes_with_nul ( s. as_bytes ( ) ) . expect ( "null-terminated string" )
136
138
}
139
+
140
+ pub fn provide ( providers : & mut Providers ) {
141
+ providers. target_features_whitelist = |tcx, cnum| {
142
+ assert_eq ! ( cnum, LOCAL_CRATE ) ;
143
+ Rc :: new ( llvm_util:: target_feature_whitelist ( tcx. sess )
144
+ . iter ( )
145
+ . map ( |c| c. to_str ( ) . unwrap ( ) . to_string ( ) )
146
+ . collect ( ) )
147
+ } ;
148
+
149
+ providers. target_features_enabled = |tcx, id| {
150
+ let whitelist = tcx. target_features_whitelist ( LOCAL_CRATE ) ;
151
+ let mut target_features = Vec :: new ( ) ;
152
+ for attr in tcx. get_attrs ( id) . iter ( ) {
153
+ if !attr. check_name ( "target_feature" ) {
154
+ continue
155
+ }
156
+ if let Some ( val) = attr. value_str ( ) {
157
+ for feat in val. as_str ( ) . split ( "," ) . map ( |f| f. trim ( ) ) {
158
+ if !feat. is_empty ( ) && !feat. contains ( '\0' ) {
159
+ target_features. push ( feat. to_string ( ) ) ;
160
+ }
161
+ }
162
+ let msg = "#[target_feature = \" ..\" ] is deprecated and will \
163
+ eventually be removed, use \
164
+ #[target_feature(enable = \" ..\" )] instead";
165
+ tcx. sess . span_warn ( attr. span , & msg) ;
166
+ continue
167
+ }
168
+
169
+ if tcx. fn_sig ( id) . unsafety ( ) == Unsafety :: Normal {
170
+ let msg = "#[target_feature(..)] can only be applied to \
171
+ `unsafe` function";
172
+ tcx. sess . span_err ( attr. span , msg) ;
173
+ }
174
+ from_target_feature ( tcx, attr, & whitelist, & mut target_features) ;
175
+ }
176
+ Rc :: new ( target_features)
177
+ } ;
178
+ }
179
+
180
+ fn from_target_feature (
181
+ tcx : TyCtxt ,
182
+ attr : & ast:: Attribute ,
183
+ whitelist : & FxHashSet < String > ,
184
+ target_features : & mut Vec < String > ,
185
+ ) {
186
+ let list = match attr. meta_item_list ( ) {
187
+ Some ( list) => list,
188
+ None => {
189
+ let msg = "#[target_feature] attribute must be of the form \
190
+ #[target_feature(..)]";
191
+ tcx. sess . span_err ( attr. span , & msg) ;
192
+ return
193
+ }
194
+ } ;
195
+
196
+ for item in list {
197
+ if !item. check_name ( "enable" ) {
198
+ let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
199
+ currently";
200
+ tcx. sess . span_err ( item. span , & msg) ;
201
+ continue
202
+ }
203
+ let value = match item. value_str ( ) {
204
+ Some ( list) => list,
205
+ None => {
206
+ let msg = "#[target_feature] attribute must be of the form \
207
+ #[target_feature(enable = \" ..\" )]";
208
+ tcx. sess . span_err ( item. span , & msg) ;
209
+ continue
210
+ }
211
+ } ;
212
+ let value = value. as_str ( ) ;
213
+ for feature in value. split ( ',' ) {
214
+ if whitelist. contains ( feature) {
215
+ target_features. push ( format ! ( "+{}" , feature) ) ;
216
+ continue
217
+ }
218
+
219
+ let msg = format ! ( "the feature named `{}` is not valid for \
220
+ this target", feature) ;
221
+ let mut err = tcx. sess . struct_span_err ( item. span , & msg) ;
222
+
223
+ if feature. starts_with ( "+" ) {
224
+ let valid = whitelist. contains ( & feature[ 1 ..] ) ;
225
+ if valid {
226
+ err. help ( "consider removing the leading `+` in the feature name" ) ;
227
+ }
228
+ }
229
+ err. emit ( ) ;
230
+ }
231
+ }
232
+ }
0 commit comments