|
1 | | -use std::borrow::Cow; |
2 | 1 | use std::hash::Hash; |
3 | 2 | use std::path::PathBuf; |
4 | 3 | use std::sync::{Arc, OnceLock as OnceCell}; |
@@ -479,7 +478,7 @@ impl Item { |
479 | 478 | name, |
480 | 479 | kind, |
481 | 480 | Attributes::from_hir(hir_attrs), |
482 | | - hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), |
| 481 | + extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), |
483 | 482 | ) |
484 | 483 | } |
485 | 484 |
|
@@ -990,147 +989,107 @@ pub(crate) struct Module { |
990 | 989 | pub(crate) span: Span, |
991 | 990 | } |
992 | 991 |
|
993 | | -pub(crate) trait AttributesExt { |
994 | | - type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> |
995 | | - where |
996 | | - Self: 'a; |
997 | | - type Attributes<'a>: Iterator<Item = &'a hir::Attribute> |
998 | | - where |
999 | | - Self: 'a; |
1000 | | - |
1001 | | - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_>; |
1002 | | - |
1003 | | - fn iter(&self) -> Self::Attributes<'_>; |
1004 | | - |
1005 | | - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> { |
1006 | | - let sess = tcx.sess; |
1007 | | - let doc_cfg_active = tcx.features().doc_cfg(); |
1008 | | - let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); |
1009 | | - |
1010 | | - fn single<T: IntoIterator>(it: T) -> Option<T::Item> { |
1011 | | - let mut iter = it.into_iter(); |
1012 | | - let item = iter.next()?; |
1013 | | - if iter.next().is_some() { |
1014 | | - return None; |
1015 | | - } |
1016 | | - Some(item) |
| 992 | +pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>( |
| 993 | + attrs: I, |
| 994 | + name: Symbol, |
| 995 | +) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> { |
| 996 | + attrs |
| 997 | + .into_iter() |
| 998 | + .filter(move |attr| attr.has_name(name)) |
| 999 | + .filter_map(ast::attr::AttributeExt::meta_item_list) |
| 1000 | + .flatten() |
| 1001 | +} |
| 1002 | + |
| 1003 | +pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>( |
| 1004 | + attrs: I, |
| 1005 | + tcx: TyCtxt<'_>, |
| 1006 | + hidden_cfg: &FxHashSet<Cfg>, |
| 1007 | +) -> Option<Arc<Cfg>> { |
| 1008 | + let sess = tcx.sess; |
| 1009 | + let doc_cfg_active = tcx.features().doc_cfg(); |
| 1010 | + let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); |
| 1011 | + |
| 1012 | + fn single<T: IntoIterator>(it: T) -> Option<T::Item> { |
| 1013 | + let mut iter = it.into_iter(); |
| 1014 | + let item = iter.next()?; |
| 1015 | + if iter.next().is_some() { |
| 1016 | + return None; |
1017 | 1017 | } |
| 1018 | + Some(item) |
| 1019 | + } |
1018 | 1020 |
|
1019 | | - let mut cfg = if doc_cfg_active || doc_auto_cfg_active { |
1020 | | - let mut doc_cfg = self |
1021 | | - .iter() |
1022 | | - .filter(|attr| attr.has_name(sym::doc)) |
1023 | | - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) |
| 1021 | + let mut cfg = if doc_cfg_active || doc_auto_cfg_active { |
| 1022 | + let mut doc_cfg = attrs |
| 1023 | + .clone() |
| 1024 | + .filter(|attr| attr.has_name(sym::doc)) |
| 1025 | + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) |
| 1026 | + .filter(|attr| attr.has_name(sym::cfg)) |
| 1027 | + .peekable(); |
| 1028 | + if doc_cfg.peek().is_some() && doc_cfg_active { |
| 1029 | + doc_cfg |
| 1030 | + .filter_map(|attr| Cfg::parse(&attr).ok()) |
| 1031 | + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
| 1032 | + } else if doc_auto_cfg_active { |
| 1033 | + // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because |
| 1034 | + // `doc(cfg())` overrides `cfg()`). |
| 1035 | + attrs |
| 1036 | + .clone() |
1024 | 1037 | .filter(|attr| attr.has_name(sym::cfg)) |
1025 | | - .peekable(); |
1026 | | - if doc_cfg.peek().is_some() && doc_cfg_active { |
1027 | | - doc_cfg |
1028 | | - .filter_map(|attr| Cfg::parse(&attr).ok()) |
1029 | | - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1030 | | - } else if doc_auto_cfg_active { |
1031 | | - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because |
1032 | | - // `doc(cfg())` overrides `cfg()`). |
1033 | | - self.iter() |
1034 | | - .filter(|attr| attr.has_name(sym::cfg)) |
1035 | | - .filter_map(|attr| single(attr.meta_item_list()?)) |
1036 | | - .filter_map(|attr| { |
1037 | | - Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() |
1038 | | - }) |
1039 | | - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1040 | | - } else { |
1041 | | - Cfg::True |
1042 | | - } |
| 1038 | + .filter_map(|attr| single(attr.meta_item_list()?)) |
| 1039 | + .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) |
| 1040 | + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1043 | 1041 | } else { |
1044 | 1042 | Cfg::True |
1045 | | - }; |
1046 | | - |
1047 | | - for attr in self.iter() { |
1048 | | - // #[doc] |
1049 | | - if attr.doc_str().is_none() && attr.has_name(sym::doc) { |
1050 | | - // #[doc(...)] |
1051 | | - if let Some(list) = attr.meta_item_list() { |
1052 | | - for item in list { |
1053 | | - // #[doc(hidden)] |
1054 | | - if !item.has_name(sym::cfg) { |
1055 | | - continue; |
1056 | | - } |
1057 | | - // #[doc(cfg(...))] |
1058 | | - if let Some(cfg_mi) = item |
1059 | | - .meta_item() |
1060 | | - .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) |
1061 | | - { |
1062 | | - match Cfg::parse(cfg_mi) { |
1063 | | - Ok(new_cfg) => cfg &= new_cfg, |
1064 | | - Err(e) => { |
1065 | | - sess.dcx().span_err(e.span, e.msg); |
1066 | | - } |
| 1043 | + } |
| 1044 | + } else { |
| 1045 | + Cfg::True |
| 1046 | + }; |
| 1047 | + |
| 1048 | + for attr in attrs.clone() { |
| 1049 | + // #[doc] |
| 1050 | + if attr.doc_str().is_none() && attr.has_name(sym::doc) { |
| 1051 | + // #[doc(...)] |
| 1052 | + if let Some(list) = attr.meta_item_list() { |
| 1053 | + for item in list { |
| 1054 | + // #[doc(hidden)] |
| 1055 | + if !item.has_name(sym::cfg) { |
| 1056 | + continue; |
| 1057 | + } |
| 1058 | + // #[doc(cfg(...))] |
| 1059 | + if let Some(cfg_mi) = item |
| 1060 | + .meta_item() |
| 1061 | + .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) |
| 1062 | + { |
| 1063 | + match Cfg::parse(cfg_mi) { |
| 1064 | + Ok(new_cfg) => cfg &= new_cfg, |
| 1065 | + Err(e) => { |
| 1066 | + sess.dcx().span_err(e.span, e.msg); |
1067 | 1067 | } |
1068 | 1068 | } |
1069 | 1069 | } |
1070 | 1070 | } |
1071 | 1071 | } |
1072 | 1072 | } |
| 1073 | + } |
1073 | 1074 |
|
1074 | | - // treat #[target_feature(enable = "feat")] attributes as if they were |
1075 | | - // #[doc(cfg(target_feature = "feat"))] attributes as well |
1076 | | - for attr in self.lists(sym::target_feature) { |
1077 | | - if attr.has_name(sym::enable) { |
1078 | | - if attr.value_str().is_some() { |
1079 | | - // Clone `enable = "feat"`, change to `target_feature = "feat"`. |
1080 | | - // Unwrap is safe because `value_str` succeeded above. |
1081 | | - let mut meta = attr.meta_item().unwrap().clone(); |
1082 | | - meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); |
1083 | | - |
1084 | | - if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { |
1085 | | - cfg &= feat_cfg; |
1086 | | - } |
| 1075 | + // treat #[target_feature(enable = "feat")] attributes as if they were |
| 1076 | + // #[doc(cfg(target_feature = "feat"))] attributes as well |
| 1077 | + for attr in hir_attr_lists(attrs, sym::target_feature) { |
| 1078 | + if attr.has_name(sym::enable) { |
| 1079 | + if attr.value_str().is_some() { |
| 1080 | + // Clone `enable = "feat"`, change to `target_feature = "feat"`. |
| 1081 | + // Unwrap is safe because `value_str` succeeded above. |
| 1082 | + let mut meta = attr.meta_item().unwrap().clone(); |
| 1083 | + meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); |
| 1084 | + |
| 1085 | + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { |
| 1086 | + cfg &= feat_cfg; |
1087 | 1087 | } |
1088 | 1088 | } |
1089 | 1089 | } |
1090 | | - |
1091 | | - if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } |
1092 | 1090 | } |
1093 | | -} |
1094 | | - |
1095 | | -impl AttributesExt for [hir::Attribute] { |
1096 | | - type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; |
1097 | | - type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a; |
1098 | 1091 |
|
1099 | | - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { |
1100 | | - self.iter() |
1101 | | - .filter(move |attr| attr.has_name(name)) |
1102 | | - .filter_map(ast::attr::AttributeExt::meta_item_list) |
1103 | | - .flatten() |
1104 | | - } |
1105 | | - |
1106 | | - fn iter(&self) -> Self::Attributes<'_> { |
1107 | | - self.iter() |
1108 | | - } |
1109 | | -} |
1110 | | - |
1111 | | -impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] { |
1112 | | - type AttributeIterator<'a> |
1113 | | - = impl Iterator<Item = ast::MetaItemInner> + 'a |
1114 | | - where |
1115 | | - Self: 'a; |
1116 | | - type Attributes<'a> |
1117 | | - = impl Iterator<Item = &'a hir::Attribute> + 'a |
1118 | | - where |
1119 | | - Self: 'a; |
1120 | | - |
1121 | | - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { |
1122 | | - AttributesExt::iter(self) |
1123 | | - .filter(move |attr| attr.has_name(name)) |
1124 | | - .filter_map(hir::Attribute::meta_item_list) |
1125 | | - .flatten() |
1126 | | - } |
1127 | | - |
1128 | | - fn iter(&self) -> Self::Attributes<'_> { |
1129 | | - self.iter().map(move |(attr, _)| match attr { |
1130 | | - Cow::Borrowed(attr) => *attr, |
1131 | | - Cow::Owned(attr) => attr, |
1132 | | - }) |
1133 | | - } |
| 1092 | + if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } |
1134 | 1093 | } |
1135 | 1094 |
|
1136 | 1095 | pub(crate) trait NestedAttributesExt { |
@@ -1196,7 +1155,7 @@ pub(crate) struct Attributes { |
1196 | 1155 |
|
1197 | 1156 | impl Attributes { |
1198 | 1157 | pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ { |
1199 | | - self.other_attrs.lists(name) |
| 1158 | + hir_attr_lists(&self.other_attrs[..], name) |
1200 | 1159 | } |
1201 | 1160 |
|
1202 | 1161 | pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool { |
@@ -1263,7 +1222,9 @@ impl Attributes { |
1263 | 1222 | pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { |
1264 | 1223 | let mut aliases = FxIndexSet::default(); |
1265 | 1224 |
|
1266 | | - for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { |
| 1225 | + for attr in |
| 1226 | + hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias)) |
| 1227 | + { |
1267 | 1228 | if let Some(values) = attr.meta_item_list() { |
1268 | 1229 | for l in values { |
1269 | 1230 | if let Some(lit) = l.lit() |
|
0 commit comments