|
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};
|
@@ -485,7 +484,7 @@ impl Item {
|
485 | 484 | name,
|
486 | 485 | kind,
|
487 | 486 | Attributes::from_hir(hir_attrs),
|
488 |
| - hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), |
| 487 | + extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), |
489 | 488 | )
|
490 | 489 | }
|
491 | 490 |
|
@@ -996,147 +995,107 @@ pub(crate) struct Module {
|
996 | 995 | pub(crate) span: Span,
|
997 | 996 | }
|
998 | 997 |
|
999 |
| -pub(crate) trait AttributesExt { |
1000 |
| - type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> |
1001 |
| - where |
1002 |
| - Self: 'a; |
1003 |
| - type Attributes<'a>: Iterator<Item = &'a hir::Attribute> |
1004 |
| - where |
1005 |
| - Self: 'a; |
1006 |
| - |
1007 |
| - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_>; |
1008 |
| - |
1009 |
| - fn iter(&self) -> Self::Attributes<'_>; |
1010 |
| - |
1011 |
| - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> { |
1012 |
| - let sess = tcx.sess; |
1013 |
| - let doc_cfg_active = tcx.features().doc_cfg(); |
1014 |
| - let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); |
1015 |
| - |
1016 |
| - fn single<T: IntoIterator>(it: T) -> Option<T::Item> { |
1017 |
| - let mut iter = it.into_iter(); |
1018 |
| - let item = iter.next()?; |
1019 |
| - if iter.next().is_some() { |
1020 |
| - return None; |
1021 |
| - } |
1022 |
| - Some(item) |
| 998 | +pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>( |
| 999 | + attrs: I, |
| 1000 | + name: Symbol, |
| 1001 | +) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> { |
| 1002 | + attrs |
| 1003 | + .into_iter() |
| 1004 | + .filter(move |attr| attr.has_name(name)) |
| 1005 | + .filter_map(ast::attr::AttributeExt::meta_item_list) |
| 1006 | + .flatten() |
| 1007 | +} |
| 1008 | + |
| 1009 | +pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>( |
| 1010 | + attrs: I, |
| 1011 | + tcx: TyCtxt<'_>, |
| 1012 | + hidden_cfg: &FxHashSet<Cfg>, |
| 1013 | +) -> Option<Arc<Cfg>> { |
| 1014 | + let sess = tcx.sess; |
| 1015 | + let doc_cfg_active = tcx.features().doc_cfg(); |
| 1016 | + let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); |
| 1017 | + |
| 1018 | + fn single<T: IntoIterator>(it: T) -> Option<T::Item> { |
| 1019 | + let mut iter = it.into_iter(); |
| 1020 | + let item = iter.next()?; |
| 1021 | + if iter.next().is_some() { |
| 1022 | + return None; |
1023 | 1023 | }
|
| 1024 | + Some(item) |
| 1025 | + } |
1024 | 1026 |
|
1025 |
| - let mut cfg = if doc_cfg_active || doc_auto_cfg_active { |
1026 |
| - let mut doc_cfg = self |
1027 |
| - .iter() |
1028 |
| - .filter(|attr| attr.has_name(sym::doc)) |
1029 |
| - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) |
| 1027 | + let mut cfg = if doc_cfg_active || doc_auto_cfg_active { |
| 1028 | + let mut doc_cfg = attrs |
| 1029 | + .clone() |
| 1030 | + .filter(|attr| attr.has_name(sym::doc)) |
| 1031 | + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) |
| 1032 | + .filter(|attr| attr.has_name(sym::cfg)) |
| 1033 | + .peekable(); |
| 1034 | + if doc_cfg.peek().is_some() && doc_cfg_active { |
| 1035 | + doc_cfg |
| 1036 | + .filter_map(|attr| Cfg::parse(&attr).ok()) |
| 1037 | + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
| 1038 | + } else if doc_auto_cfg_active { |
| 1039 | + // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because |
| 1040 | + // `doc(cfg())` overrides `cfg()`). |
| 1041 | + attrs |
| 1042 | + .clone() |
1030 | 1043 | .filter(|attr| attr.has_name(sym::cfg))
|
1031 |
| - .peekable(); |
1032 |
| - if doc_cfg.peek().is_some() && doc_cfg_active { |
1033 |
| - doc_cfg |
1034 |
| - .filter_map(|attr| Cfg::parse(&attr).ok()) |
1035 |
| - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1036 |
| - } else if doc_auto_cfg_active { |
1037 |
| - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because |
1038 |
| - // `doc(cfg())` overrides `cfg()`). |
1039 |
| - self.iter() |
1040 |
| - .filter(|attr| attr.has_name(sym::cfg)) |
1041 |
| - .filter_map(|attr| single(attr.meta_item_list()?)) |
1042 |
| - .filter_map(|attr| { |
1043 |
| - Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() |
1044 |
| - }) |
1045 |
| - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1046 |
| - } else { |
1047 |
| - Cfg::True |
1048 |
| - } |
| 1044 | + .filter_map(|attr| single(attr.meta_item_list()?)) |
| 1045 | + .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) |
| 1046 | + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) |
1049 | 1047 | } else {
|
1050 | 1048 | Cfg::True
|
1051 |
| - }; |
1052 |
| - |
1053 |
| - for attr in self.iter() { |
1054 |
| - // #[doc] |
1055 |
| - if attr.doc_str().is_none() && attr.has_name(sym::doc) { |
1056 |
| - // #[doc(...)] |
1057 |
| - if let Some(list) = attr.meta_item_list() { |
1058 |
| - for item in list { |
1059 |
| - // #[doc(hidden)] |
1060 |
| - if !item.has_name(sym::cfg) { |
1061 |
| - continue; |
1062 |
| - } |
1063 |
| - // #[doc(cfg(...))] |
1064 |
| - if let Some(cfg_mi) = item |
1065 |
| - .meta_item() |
1066 |
| - .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) |
1067 |
| - { |
1068 |
| - match Cfg::parse(cfg_mi) { |
1069 |
| - Ok(new_cfg) => cfg &= new_cfg, |
1070 |
| - Err(e) => { |
1071 |
| - sess.dcx().span_err(e.span, e.msg); |
1072 |
| - } |
| 1049 | + } |
| 1050 | + } else { |
| 1051 | + Cfg::True |
| 1052 | + }; |
| 1053 | + |
| 1054 | + for attr in attrs.clone() { |
| 1055 | + // #[doc] |
| 1056 | + if attr.doc_str().is_none() && attr.has_name(sym::doc) { |
| 1057 | + // #[doc(...)] |
| 1058 | + if let Some(list) = attr.meta_item_list() { |
| 1059 | + for item in list { |
| 1060 | + // #[doc(hidden)] |
| 1061 | + if !item.has_name(sym::cfg) { |
| 1062 | + continue; |
| 1063 | + } |
| 1064 | + // #[doc(cfg(...))] |
| 1065 | + if let Some(cfg_mi) = item |
| 1066 | + .meta_item() |
| 1067 | + .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) |
| 1068 | + { |
| 1069 | + match Cfg::parse(cfg_mi) { |
| 1070 | + Ok(new_cfg) => cfg &= new_cfg, |
| 1071 | + Err(e) => { |
| 1072 | + sess.dcx().span_err(e.span, e.msg); |
1073 | 1073 | }
|
1074 | 1074 | }
|
1075 | 1075 | }
|
1076 | 1076 | }
|
1077 | 1077 | }
|
1078 | 1078 | }
|
| 1079 | + } |
1079 | 1080 |
|
1080 |
| - // treat #[target_feature(enable = "feat")] attributes as if they were |
1081 |
| - // #[doc(cfg(target_feature = "feat"))] attributes as well |
1082 |
| - for attr in self.lists(sym::target_feature) { |
1083 |
| - if attr.has_name(sym::enable) { |
1084 |
| - if attr.value_str().is_some() { |
1085 |
| - // Clone `enable = "feat"`, change to `target_feature = "feat"`. |
1086 |
| - // Unwrap is safe because `value_str` succeeded above. |
1087 |
| - let mut meta = attr.meta_item().unwrap().clone(); |
1088 |
| - meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); |
1089 |
| - |
1090 |
| - if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { |
1091 |
| - cfg &= feat_cfg; |
1092 |
| - } |
| 1081 | + // treat #[target_feature(enable = "feat")] attributes as if they were |
| 1082 | + // #[doc(cfg(target_feature = "feat"))] attributes as well |
| 1083 | + for attr in hir_attr_lists(attrs, sym::target_feature) { |
| 1084 | + if attr.has_name(sym::enable) { |
| 1085 | + if attr.value_str().is_some() { |
| 1086 | + // Clone `enable = "feat"`, change to `target_feature = "feat"`. |
| 1087 | + // Unwrap is safe because `value_str` succeeded above. |
| 1088 | + let mut meta = attr.meta_item().unwrap().clone(); |
| 1089 | + meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); |
| 1090 | + |
| 1091 | + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { |
| 1092 | + cfg &= feat_cfg; |
1093 | 1093 | }
|
1094 | 1094 | }
|
1095 | 1095 | }
|
1096 |
| - |
1097 |
| - if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } |
1098 | 1096 | }
|
1099 |
| -} |
1100 |
| - |
1101 |
| -impl AttributesExt for [hir::Attribute] { |
1102 |
| - type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; |
1103 |
| - type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a; |
1104 | 1097 |
|
1105 |
| - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { |
1106 |
| - self.iter() |
1107 |
| - .filter(move |attr| attr.has_name(name)) |
1108 |
| - .filter_map(ast::attr::AttributeExt::meta_item_list) |
1109 |
| - .flatten() |
1110 |
| - } |
1111 |
| - |
1112 |
| - fn iter(&self) -> Self::Attributes<'_> { |
1113 |
| - self.iter() |
1114 |
| - } |
1115 |
| -} |
1116 |
| - |
1117 |
| -impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] { |
1118 |
| - type AttributeIterator<'a> |
1119 |
| - = impl Iterator<Item = ast::MetaItemInner> + 'a |
1120 |
| - where |
1121 |
| - Self: 'a; |
1122 |
| - type Attributes<'a> |
1123 |
| - = impl Iterator<Item = &'a hir::Attribute> + 'a |
1124 |
| - where |
1125 |
| - Self: 'a; |
1126 |
| - |
1127 |
| - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { |
1128 |
| - AttributesExt::iter(self) |
1129 |
| - .filter(move |attr| attr.has_name(name)) |
1130 |
| - .filter_map(hir::Attribute::meta_item_list) |
1131 |
| - .flatten() |
1132 |
| - } |
1133 |
| - |
1134 |
| - fn iter(&self) -> Self::Attributes<'_> { |
1135 |
| - self.iter().map(move |(attr, _)| match attr { |
1136 |
| - Cow::Borrowed(attr) => *attr, |
1137 |
| - Cow::Owned(attr) => attr, |
1138 |
| - }) |
1139 |
| - } |
| 1098 | + if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } |
1140 | 1099 | }
|
1141 | 1100 |
|
1142 | 1101 | pub(crate) trait NestedAttributesExt {
|
@@ -1202,7 +1161,7 @@ pub(crate) struct Attributes {
|
1202 | 1161 |
|
1203 | 1162 | impl Attributes {
|
1204 | 1163 | pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ {
|
1205 |
| - self.other_attrs.lists(name) |
| 1164 | + hir_attr_lists(&self.other_attrs[..], name) |
1206 | 1165 | }
|
1207 | 1166 |
|
1208 | 1167 | pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
|
@@ -1269,7 +1228,9 @@ impl Attributes {
|
1269 | 1228 | pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
|
1270 | 1229 | let mut aliases = FxIndexSet::default();
|
1271 | 1230 |
|
1272 |
| - for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { |
| 1231 | + for attr in |
| 1232 | + hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias)) |
| 1233 | + { |
1273 | 1234 | if let Some(values) = attr.meta_item_list() {
|
1274 | 1235 | for l in values {
|
1275 | 1236 | if let Some(lit) = l.lit()
|
|
0 commit comments