|
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