+
+pub fn provide(providers: &mut Providers) {
+ providers.target_features_whitelist = |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ Rc::new(llvm_util::target_feature_whitelist(tcx.sess)
+ .iter()
+ .map(|c| c.to_str().unwrap().to_string())
+ .collect())
+ };
+
+ providers.target_features_enabled = |tcx, id| {
+ let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
+ let mut target_features = Vec::new();
+ for attr in tcx.get_attrs(id).iter() {
+ if !attr.check_name("target_feature") {
+ continue
+ }
+ if let Some(val) = attr.value_str() {
+ for feat in val.as_str().split(",").map(|f| f.trim()) {
+ if !feat.is_empty() && !feat.contains('\0') {
+ target_features.push(feat.to_string());
+ }
+ }
+ let msg = "#[target_feature = \"..\"] is deprecated and will \
+ eventually be removed, use \
+ #[target_feature(enable = \"..\")] instead";
+ tcx.sess.span_warn(attr.span, &msg);
+ continue
+ }
+
+ if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
+ let msg = "#[target_feature(..)] can only be applied to \
+ `unsafe` function";
+ tcx.sess.span_err(attr.span, msg);
+ }
+ from_target_feature(tcx, attr, &whitelist, &mut target_features);
+ }
+ Rc::new(target_features)
+ };
+}
+
+fn from_target_feature(
+ tcx: TyCtxt,
+ attr: &ast::Attribute,
+ whitelist: &FxHashSet<String>,
+ target_features: &mut Vec<String>,
+) {
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
+ None => {
+ let msg = "#[target_feature] attribute must be of the form \
+ #[target_feature(..)]";
+ tcx.sess.span_err(attr.span, &msg);
+ return
+ }
+ };
+
+ for item in list {
+ if !item.check_name("enable") {
+ let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
+ currently";
+ tcx.sess.span_err(item.span, &msg);
+ continue
+ }
+ let value = match item.value_str() {
+ Some(list) => list,
+ None => {
+ let msg = "#[target_feature] attribute must be of the form \
+ #[target_feature(enable = \"..\")]";
+ tcx.sess.span_err(item.span, &msg);
+ continue
+ }
+ };
+ let value = value.as_str();
+ for feature in value.split(',') {
+ if whitelist.contains(feature) {
+ target_features.push(format!("+{}", feature));
+ continue
+ }
+
+ let msg = format!("the feature named `{}` is not valid for \
+ this target", feature);
+ let mut err = tcx.sess.struct_span_err(item.span, &msg);
+
+ if feature.starts_with("+") {
+ let valid = whitelist.contains(&feature[1..]);
+ if valid {
+ err.help("consider removing the leading `+` in the feature name");
+ }
+ }
+ err.emit();
+ }
+ }
+}