diff options
Diffstat (limited to 'src/librustdoc')
| -rw-r--r-- | src/librustdoc/clean/cfg.rs | 6 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 17 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 22 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 252 | ||||
| -rw-r--r-- | src/librustdoc/clean/utils.rs | 6 | ||||
| -rw-r--r-- | src/librustdoc/config.rs | 6 | ||||
| -rw-r--r-- | src/librustdoc/doctest/rust.rs | 7 | ||||
| -rw-r--r-- | src/librustdoc/formats/cache.rs | 23 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 9 | ||||
| -rw-r--r-- | src/librustdoc/html/highlight.rs | 15 | ||||
| -rw-r--r-- | src/librustdoc/html/render/print_item.rs | 55 | ||||
| -rw-r--r-- | src/librustdoc/html/render/search_index.rs | 27 | ||||
| -rw-r--r-- | src/librustdoc/html/render/span_map.rs | 33 | ||||
| -rw-r--r-- | src/librustdoc/html/render/write_shared.rs | 10 | ||||
| -rw-r--r-- | src/librustdoc/html/static/css/rustdoc.css | 50 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/search.js | 62 | ||||
| -rw-r--r-- | src/librustdoc/json/conversions.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 9 | ||||
| -rw-r--r-- | src/librustdoc/passes/propagate_stability.rs | 27 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 6 |
20 files changed, 397 insertions, 247 deletions
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index c59dce185f4..bfa789b1f39 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -90,11 +90,11 @@ impl Cfg { }, MetaItemKind::List(ref items) => { let orig_len = items.len(); - let sub_cfgs = + let mut sub_cfgs = items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose()); let ret = match name { - sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), - sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), + sym::all => sub_cfgs.try_fold(Cfg::True, |x, y| Ok(x & y?)), + sym::any => sub_cfgs.try_fold(Cfg::False, |x, y| Ok(x | y?)), sym::not => { if orig_len == 1 { let mut sub_cfgs = sub_cfgs.collect::<Vec<_>>(); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 019a888bd2f..3d51ab1967d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -17,12 +17,12 @@ use rustc_span::symbol::{Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; -use super::Item; +use super::{Item, extract_cfg_from_attrs}; use crate::clean::{ - self, Attributes, AttributesExt, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, - clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, - clean_poly_fn_sig, clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, - clean_ty_generics, clean_variant_def, utils, + self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item, + clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig, + clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics, + clean_variant_def, utils, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -408,10 +408,13 @@ pub(crate) fn merge_attrs( } else { Attributes::from_hir(&both) }, - both.cfg(cx.tcx, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg), ) } else { - (Attributes::from_hir(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) + ( + Attributes::from_hir(old_attrs), + extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), + ) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2ed2df799dd..fbd934bf718 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -186,8 +186,7 @@ fn generate_item_with_correct_attrs( // For glob re-exports the item may or may not exist to be re-exported (potentially the cfgs // on the path up until the glob can be removed, and only cfgs on the globbed item itself // matter), for non-inlined re-exports see #85043. - let is_inline = inline::load_attrs(cx, import_id.to_def_id()) - .lists(sym::doc) + let is_inline = hir_attr_lists(inline::load_attrs(cx, import_id.to_def_id()), sym::doc) .get_word_attr(sym::inline) .is_some() || (is_glob_import(cx.tcx, import_id) @@ -199,8 +198,14 @@ fn generate_item_with_correct_attrs( // We only keep the item's attributes. target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect() }; - - let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); + let cfg = extract_cfg_from_attrs( + attrs.iter().map(move |(attr, _)| match attr { + Cow::Borrowed(attr) => *attr, + Cow::Owned(attr) => attr, + }), + cx.tcx, + &cx.cache.hidden_cfg, + ); let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); let name = renamed.or(Some(name)); @@ -979,13 +984,14 @@ fn clean_proc_macro<'tcx>( ) -> ItemKind { let attrs = cx.tcx.hir().attrs(item.hir_id()); if kind == MacroKind::Derive - && let Some(derive_name) = attrs.lists(sym::proc_macro_derive).find_map(|mi| mi.ident()) + && let Some(derive_name) = + hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident()) { *name = derive_name.name; } let mut helpers = Vec::new(); - for mi in attrs.lists(sym::proc_macro_derive) { + for mi in hir_attr_lists(attrs, sym::proc_macro_derive) { if !mi.has_name(sym::attributes) { continue; } @@ -2985,7 +2991,7 @@ fn clean_use_statement_inner<'tcx>( let visibility = cx.tcx.visibility(import.owner_id); let attrs = cx.tcx.hir().attrs(import.hir_id()); - let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline); + let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline); let pub_underscore = visibility.is_public() && name == kw::Underscore; let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3094,7 +3100,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let kind = match item.kind { hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem( clean_function(cx, &sig, generics, FunctionArgs::Names(names)), - sig.header.safety, + sig.header.safety(), ), hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None }, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index dcee96978d2..6e817af0d6e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::hash::Hash; use std::path::PathBuf; use std::sync::{Arc, OnceLock as OnceCell}; @@ -6,7 +5,9 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince}; +use rustc_attr_parsing::{ + AllowedThroughUnstableModules, ConstStability, Deprecation, Stability, StableSince, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -406,15 +407,19 @@ impl Item { // were never supposed to work at all. let stab = self.stability(tcx)?; if let rustc_attr_parsing::StabilityLevel::Stable { - allowed_through_unstable_modules: true, + allowed_through_unstable_modules: Some(note), .. } = stab.level { + let note = match note { + AllowedThroughUnstableModules::WithDeprecation(note) => Some(note), + // FIXME: Would be better to say *something* here about the *path* being + // deprecated rather than the item. + AllowedThroughUnstableModules::WithoutDeprecation => None, + }; Some(Deprecation { - // FIXME(#131676, #135003): when a note is added to this stability tag, - // translate it here since: rustc_attr_parsing::DeprecatedSince::Unspecified, - note: None, + note, suggestion: None, }) } else { @@ -479,7 +484,7 @@ impl Item { name, kind, Attributes::from_hir(hir_attrs), - hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), ) } @@ -668,17 +673,28 @@ impl Item { ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), ty::Asyncness::No => hir::IsAsync::NotAsync, }; - hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness } + hir::FnHeader { + safety: if tcx.codegen_fn_attrs(def_id).safe_target_features { + hir::HeaderSafety::SafeTargetFeatures + } else { + sig.safety().into() + }, + abi: sig.abi(), + constness, + asyncness, + } } let header = match self.kind { ItemKind::ForeignFunctionItem(_, safety) => { let def_id = self.def_id().unwrap(); let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { - safety: if abi == ExternAbi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, def_id.expect_local()) + safety: if tcx.codegen_fn_attrs(def_id).safe_target_features { + hir::HeaderSafety::SafeTargetFeatures + } else if abi == ExternAbi::RustIntrinsic { + intrinsic_operation_unsafety(tcx, def_id.expect_local()).into() } else { - safety + safety.into() }, abi, constness: if tcx.is_const_fn(def_id) { @@ -979,147 +995,107 @@ pub(crate) struct Module { pub(crate) span: Span, } -pub(crate) trait AttributesExt { - type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> - where - Self: 'a; - type Attributes<'a>: Iterator<Item = &'a hir::Attribute> - where - Self: 'a; - - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_>; - - fn iter(&self) -> Self::Attributes<'_>; - - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> { - let sess = tcx.sess; - let doc_cfg_active = tcx.features().doc_cfg(); - let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); - - fn single<T: IntoIterator>(it: T) -> Option<T::Item> { - let mut iter = it.into_iter(); - let item = iter.next()?; - if iter.next().is_some() { - return None; - } - Some(item) +pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>( + attrs: I, + name: Symbol, +) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> { + attrs + .into_iter() + .filter(move |attr| attr.has_name(name)) + .filter_map(ast::attr::AttributeExt::meta_item_list) + .flatten() +} + +pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>( + attrs: I, + tcx: TyCtxt<'_>, + hidden_cfg: &FxHashSet<Cfg>, +) -> Option<Arc<Cfg>> { + let sess = tcx.sess; + let doc_cfg_active = tcx.features().doc_cfg(); + let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); + + fn single<T: IntoIterator>(it: T) -> Option<T::Item> { + let mut iter = it.into_iter(); + let item = iter.next()?; + if iter.next().is_some() { + return None; } + Some(item) + } - let mut cfg = if doc_cfg_active || doc_auto_cfg_active { - let mut doc_cfg = self - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + let mut cfg = if doc_cfg_active || doc_auto_cfg_active { + let mut doc_cfg = attrs + .clone() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + if doc_cfg.peek().is_some() && doc_cfg_active { + doc_cfg + .filter_map(|attr| Cfg::parse(&attr).ok()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else if doc_auto_cfg_active { + // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because + // `doc(cfg())` overrides `cfg()`). + attrs + .clone() .filter(|attr| attr.has_name(sym::cfg)) - .peekable(); - if doc_cfg.peek().is_some() && doc_cfg_active { - doc_cfg - .filter_map(|attr| Cfg::parse(&attr).ok()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else if doc_auto_cfg_active { - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because - // `doc(cfg())` overrides `cfg()`). - self.iter() - .filter(|attr| attr.has_name(sym::cfg)) - .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| { - Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() - }) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else { - Cfg::True - } + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { Cfg::True - }; - - for attr in self.iter() { - // #[doc] - if attr.doc_str().is_none() && attr.has_name(sym::doc) { - // #[doc(...)] - if let Some(list) = attr.meta_item_list() { - for item in list { - // #[doc(hidden)] - if !item.has_name(sym::cfg) { - continue; - } - // #[doc(cfg(...))] - if let Some(cfg_mi) = item - .meta_item() - .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) - { - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => { - sess.dcx().span_err(e.span, e.msg); - } + } + } else { + Cfg::True + }; + + for attr in attrs.clone() { + // #[doc] + if attr.doc_str().is_none() && attr.has_name(sym::doc) { + // #[doc(...)] + if let Some(list) = attr.meta_item_list() { + for item in list { + // #[doc(hidden)] + if !item.has_name(sym::cfg) { + continue; + } + // #[doc(cfg(...))] + if let Some(cfg_mi) = item + .meta_item() + .and_then(|item| rustc_expand::config::parse_cfg(item, sess)) + { + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => { + sess.dcx().span_err(e.span, e.msg); } } } } } } + } - // treat #[target_feature(enable = "feat")] attributes as if they were - // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in self.lists(sym::target_feature) { - if attr.has_name(sym::enable) { - if attr.value_str().is_some() { - // Clone `enable = "feat"`, change to `target_feature = "feat"`. - // Unwrap is safe because `value_str` succeeded above. - let mut meta = attr.meta_item().unwrap().clone(); - meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - - if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { - cfg &= feat_cfg; - } + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well + for attr in hir_attr_lists(attrs, sym::target_feature) { + if attr.has_name(sym::enable) { + if attr.value_str().is_some() { + // Clone `enable = "feat"`, change to `target_feature = "feat"`. + // Unwrap is safe because `value_str` succeeded above. + let mut meta = attr.meta_item().unwrap().clone(); + meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); + + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { + cfg &= feat_cfg; } } } - - if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } - } -} - -impl AttributesExt for [hir::Attribute] { - type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; - type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a; - - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { - self.iter() - .filter(move |attr| attr.has_name(name)) - .filter_map(ast::attr::AttributeExt::meta_item_list) - .flatten() } - fn iter(&self) -> Self::Attributes<'_> { - self.iter() - } -} - -impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] { - type AttributeIterator<'a> - = impl Iterator<Item = ast::MetaItemInner> + 'a - where - Self: 'a; - type Attributes<'a> - = impl Iterator<Item = &'a hir::Attribute> + 'a - where - Self: 'a; - - fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { - AttributesExt::iter(self) - .filter(move |attr| attr.has_name(name)) - .filter_map(hir::Attribute::meta_item_list) - .flatten() - } - - fn iter(&self) -> Self::Attributes<'_> { - self.iter().map(move |(attr, _)| match attr { - Cow::Borrowed(attr) => *attr, - Cow::Owned(attr) => attr, - }) - } + if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } } pub(crate) trait NestedAttributesExt { @@ -1185,7 +1161,7 @@ pub(crate) struct Attributes { impl Attributes { pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ { - self.other_attrs.lists(name) + hir_attr_lists(&self.other_attrs[..], name) } pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool { @@ -1252,7 +1228,9 @@ impl Attributes { pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { let mut aliases = FxIndexSet::default(); - for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { + for attr in + hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias)) + { if let Some(values) = attr.meta_item_list() { for l in values { if let Some(lit) = l.lit() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 1fb35750c15..80dc6b7250c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -314,13 +314,13 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { PatKind::Box(p) => return name_from_pat(p), PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)), PatKind::Ref(p, _) => return name_from_pat(p), - PatKind::Lit(..) => { + PatKind::Expr(..) => { warn!( - "tried to get argument name from PatKind::Lit, which is silly in function arguments" + "tried to get argument name from PatKind::Expr, which is silly in function arguments" ); return Symbol::intern("()"); } - PatKind::Guard(p, _) => return name_from_pat(&*p), + PatKind::Guard(p, _) => return name_from_pat(p), PatKind::Range(..) => return kw::Underscore, PatKind::Slice(begin, ref mid, end) => { let begin = begin.iter().map(|p| name_from_pat(p).to_string()); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index af3c7cc7be3..80bc6cebd2a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -303,6 +303,8 @@ pub(crate) struct RenderOptions { pub(crate) include_parts_dir: Vec<PathToParts>, /// Where to write crate-info pub(crate) parts_out_dir: Option<PathToParts>, + /// disable minification of CSS/JS + pub(crate) disable_minification: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -781,6 +783,9 @@ impl Options { let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); + + let disable_minification = matches.opt_present("disable-minification"); + let options = Options { bin_crate, proc_macro_crate, @@ -857,6 +862,7 @@ impl Options { should_merge, include_parts_dir, parts_out_dir, + disable_minification, }; Some((input, options, render_options)) } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 0903baddabe..bd292efeb7e 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -13,8 +13,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; use super::{DocTestVisitor, ScrapedDocTest}; -use crate::clean::Attributes; -use crate::clean::types::AttributesExt; +use crate::clean::{Attributes, extract_cfg_from_attrs}; use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine}; struct RustCollector { @@ -97,7 +96,9 @@ impl HirCollector<'_> { nested: F, ) { let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { + if let Some(ref cfg) = + extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default()) + { if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) { return; } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 7a95d33723e..4760e579199 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -140,6 +140,7 @@ struct CacheBuilder<'a, 'tcx> { /// This field is used to prevent duplicated impl blocks. impl_ids: DefIdMap<DefIdSet>, tcx: TyCtxt<'tcx>, + is_json_output: bool, } impl Cache { @@ -184,8 +185,13 @@ impl Cache { } let (krate, mut impl_ids) = { - let mut cache_builder = - CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: Default::default() }; + let is_json_output = cx.is_json_output(); + let mut cache_builder = CacheBuilder { + tcx, + cache: &mut cx.cache, + impl_ids: Default::default(), + is_json_output, + }; krate = cache_builder.fold_crate(krate); (krate, cache_builder.impl_ids) }; @@ -307,12 +313,13 @@ impl DocFolder for CacheBuilder<'_, '_> { | clean::ProcMacroItem(..) | clean::VariantItem(..) => { use rustc_data_structures::fx::IndexEntry as Entry; - if !self.cache.stripped_mod - && !matches!( - item.stability.map(|stab| stab.level), - Some(StabilityLevel::Stable { allowed_through_unstable_modules: true, .. }) - ) - { + + let skip_because_unstable = matches!( + item.stability.map(|stab| stab.level), + Some(StabilityLevel::Stable { allowed_through_unstable_modules: Some(_), .. }) + ); + + if (!self.cache.stripped_mod && !skip_because_unstable) || self.is_json_output { // Re-exported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, // however, that a re-exported item doesn't show up in the diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 621abd53501..92935c72b47 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1637,6 +1637,15 @@ impl PrintWithSpace for hir::Safety { } } +impl PrintWithSpace for hir::HeaderSafety { + fn print_with_space(&self) -> &str { + match self { + hir::HeaderSafety::SafeTargetFeatures => "", + hir::HeaderSafety::Normal(safety) => safety.print_with_space(), + } + } +} + impl PrintWithSpace for hir::IsAsync { fn print_with_space(&self) -> &str { match self { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 48a537ad5e7..62cf2b63f7f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -337,7 +337,7 @@ enum Class { Ident(Span), Lifetime, PreludeTy(Span), - PreludeVal, + PreludeVal(Span), QuestionMark, Decoration(&'static str), } @@ -385,7 +385,7 @@ impl Class { Class::Ident(_) => "", Class::Lifetime => "lifetime", Class::PreludeTy(_) => "prelude-ty", - Class::PreludeVal => "prelude-val", + Class::PreludeVal(_) => "prelude-val", Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, } @@ -395,7 +395,11 @@ impl Class { /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`). fn get_span(self) -> Option<Span> { match self { - Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) | Self::PreludeTy(sp) => Some(sp), + Self::Ident(sp) + | Self::Self_(sp) + | Self::Macro(sp) + | Self::PreludeTy(sp) + | Self::PreludeVal(sp) => Some(sp), Self::Comment | Self::DocComment | Self::Attribute @@ -406,7 +410,6 @@ impl Class { | Self::Number | Self::Bool | Self::Lifetime - | Self::PreludeVal | Self::QuestionMark | Self::Decoration(_) => None, } @@ -851,7 +854,9 @@ impl<'src> Classifier<'src> { TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { "Option" | "Result" => Class::PreludeTy(self.new_span(before, text)), - "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + "Some" | "None" | "Ok" | "Err" => { + Class::PreludeVal(self.new_span(before, text)) + } // "union" is a weak keyword and is only considered as a keyword when declaring // a union type. "union" if self.check_if_is_union_keyword() => Class::KeyWord, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e8230e63c0f..76a51cc64a8 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -140,10 +140,9 @@ macro_rules! item_template_methods { }; } -const ITEM_TABLE_OPEN: &str = "<ul class=\"item-table\">"; -const ITEM_TABLE_CLOSE: &str = "</ul>"; -const ITEM_TABLE_ROW_OPEN: &str = "<li>"; -const ITEM_TABLE_ROW_CLOSE: &str = "</li>"; +const ITEM_TABLE_OPEN: &str = "<dl class=\"item-table\">"; +const REEXPORTS_TABLE_OPEN: &str = "<dl class=\"item-table reexports\">"; +const ITEM_TABLE_CLOSE: &str = "</dl>"; // A component in a `use` path, like `string` in std::string::ToString struct PathComponent { @@ -400,37 +399,32 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str(ITEM_TABLE_CLOSE); } last_section = Some(my_section); - write_section_heading( - w, - my_section.name(), - &cx.derive_id(my_section.id()), - None, - ITEM_TABLE_OPEN, - ); + let section_id = my_section.id(); + let tag = + if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN }; + write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag); } match myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; - w.write_str(ITEM_TABLE_ROW_OPEN); match *src { Some(src) => write!( w, - "<div class=\"item-name\"><code>{}extern crate {} as {};", + "<dt><code>{}extern crate {} as {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), ), None => write!( w, - "<div class=\"item-name\"><code>{}extern crate {};", + "<dt><code>{}extern crate {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx), ), } - w.write_str("</code></div>"); - w.write_str(ITEM_TABLE_ROW_CLOSE); + w.write_str("</code></dt>"); } clean::ImportItem(ref import) => { @@ -438,28 +432,20 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() }); - w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { clean::ImportKind::Simple(s) => { format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) } clean::ImportKind::Glob => String::new(), }; - let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { - ("", "") - } else { - ("<div class=\"desc docblock-short\">", "</div>") - }; write!( w, - "<div class=\"item-name\"{id}>\ - <code>{vis}{imp}</code>\ - </div>\ - {stab_tags_before}{stab_tags}{stab_tags_after}", + "<dt{id}>\ + <code>{vis}{imp}</code>{stab_tags}\ + </dt>", vis = visibility_print_with_space(myitem, cx), imp = import.print(cx), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } _ => { @@ -469,7 +455,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let unsafety_flag = match myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(..) - if myitem.fn_header(tcx).unwrap().safety.is_unsafe() => + if myitem.fn_header(tcx).unwrap().is_unsafe() => { "<sup title=\"unsafe function\">⚠</sup>" } @@ -492,22 +478,18 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl _ => "", }; - w.write_str(ITEM_TABLE_ROW_OPEN); let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); - let (docs_before, docs_after) = if docs.is_empty() { - ("", "") - } else { - ("<div class=\"desc docblock-short\">", "</div>") - }; + let (docs_before, docs_after) = + if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") }; write!( w, - "<div class=\"item-name\">\ + "<dt>\ <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\ {visibility_and_hidden}\ {unsafety_flag}\ {stab_tags}\ - </div>\ + </dt>\ {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, @@ -521,7 +503,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl .collect::<Vec<_>>() .join(" "), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } } } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 66c52bec4ba..e4a9a2b512e 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -840,6 +840,22 @@ pub(crate) fn get_function_type_for_search( | clean::RequiredMethodItem(ref f) => { get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) } + clean::ConstantItem(ref c) => make_nullary_fn(&c.type_), + clean::StaticItem(ref s) => make_nullary_fn(&s.type_), + clean::StructFieldItem(ref t) => { + let Some(parent) = parent else { + return None; + }; + let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = + Default::default(); + let output = get_index_type(t, vec![], &mut rgen); + let input = RenderType { + id: Some(RenderTypeId::DefId(parent)), + generics: None, + bindings: None, + }; + (vec![input], vec![output], vec![], vec![]) + } _ => return None, }; @@ -1353,6 +1369,17 @@ fn simplify_fn_constraint<'a>( res.push((ty_constrained_assoc, ty_constraints)); } +/// Create a fake nullary function. +/// +/// Used to allow type-based search on constants and statics. +fn make_nullary_fn( + clean_type: &clean::Type, +) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) { + let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default(); + let output = get_index_type(clean_type, vec![], &mut rgen); + (vec![], vec![output], vec![], vec![]) +} + /// Return the full list of types when bounds have been resolved. /// /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 26f75fa241c..85f87f01afd 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node}; +use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; @@ -170,7 +170,7 @@ impl SpanMapVisitor<'_> { true } - fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) { + fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) { let hir = self.tcx.hir(); let body_id = hir.enclosing_body_owner(hir_id); // FIXME: this is showing error messages for parts of the code that are not @@ -189,6 +189,27 @@ impl SpanMapVisitor<'_> { self.matches.insert(span, link); } } + + fn handle_pat(&mut self, p: &Pat<'_>) { + match p.kind { + PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p), + PatKind::Struct(qpath, _, _) + | PatKind::TupleStruct(qpath, _, _) + | PatKind::Path(qpath) => match qpath { + QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => { + self.infer_id(path.hir_id, Some(p.hir_id), qpath.span()); + } + QPath::Resolved(_, path) => self.handle_path(path), + _ => {} + }, + PatKind::Or(pats) => { + for pat in pats { + self.handle_pat(pat); + } + } + _ => {} + } + } } impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { @@ -206,6 +227,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } + fn visit_pat(&mut self, p: &Pat<'tcx>) { + self.handle_pat(p); + } + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. @@ -228,9 +253,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { match expr.kind { ExprKind::MethodCall(segment, ..) => { - self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span) + self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span) } - ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span), + ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span), _ => { if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ce10e5ecc24..fb6f3bc2c76 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -207,7 +207,15 @@ fn write_static_files( if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) { static_files::for_each(|f: &static_files::StaticFile| { let filename = static_dir.join(f.output_filename()); - fs::write(&filename, f.minified()).map_err(|e| PathError::new(e, &filename)) + let contents: &[u8]; + let contents_vec: Vec<u8>; + if opt.disable_minification { + contents = f.bytes; + } else { + contents_vec = f.minified(); + contents = &contents_vec; + }; + fs::write(&filename, contents).map_err(|e| PathError::new(e, &filename)) })?; } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 27496381b2c..b994a43868c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -242,7 +242,7 @@ h1, h2, h3, h4, h5, h6, .mobile-topbar, .search-input, .search-results .result-name, -.item-name > a, +.item-table dt > a, .out-of-band, .sub-heading, span.since, @@ -385,11 +385,11 @@ details:not(.toggle) summary { code, pre, .code-header, .type-signature { font-family: "Source Code Pro", monospace; } -.docblock code, .docblock-short code { +.docblock code, .item-table dd code { border-radius: 3px; padding: 0 0.125em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .item-table dd pre code { padding: 0; } pre { @@ -887,13 +887,13 @@ both the code example and the line numbers, so we need to remove the radius in t text-align: center; } -.docblock-short { +.item-table dd { overflow-wrap: break-word; overflow-wrap: anywhere; } /* Wrap non-pre code blocks (`text`) but not (```text```). */ .docblock :not(pre) > code, -.docblock-short code { +.item-table dd code { white-space: pre-wrap; } @@ -938,10 +938,12 @@ rustdoc-toolbar { min-height: 60px; } -.docblock code, .docblock-short code, +.docblock code, .item-table dd code, pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background-color: var(--code-block-background-color); border-radius: var(--code-block-border-radius); + /* code blocks within links (such as in most intra-doc links) should be underlined */ + text-decoration: inherit; } #main-content { @@ -962,7 +964,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background: var(--table-alt-row-background-color); } -.docblock .stab, .docblock-short .stab, .docblock p code { +.docblock .stab, .item-table dd .stab, .docblock p code { display: inline-block; } @@ -1067,7 +1069,7 @@ because of the `[-]` element which would overlap with it. */ .example-wrap .rust a:hover, .all-items a:hover, .docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor), -.docblock-short a:not(.scrape-help):not(.tooltip):hover, +.item-table dd a:not(.scrape-help):not(.tooltip):hover, .item-info a { text-decoration: underline; } @@ -1100,20 +1102,17 @@ table, } .item-table { - display: table; padding: 0; margin: 0; width: 100%; } -.item-table > li { - display: table-row; -} -.item-table > li > div { - display: table-cell; -} -.item-table > li > .item-name { +.item-table > dt { padding-right: 1.25rem; } +.item-table > dd { + margin-inline-start: 0; + margin-left: 0; +} .search-results-title { margin-top: 0; @@ -1413,7 +1412,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ padding: 3px; margin-bottom: 5px; } -.item-name .stab { +.item-table dt .stab { margin-left: 0.3125em; } .stab { @@ -2474,7 +2473,6 @@ in src-script.js and main.js } /* Display an alternating layout on tablets and phones */ - .item-table, .item-row, .item-table > li, .item-table > li > div, .search-results > a, .search-results > a > div { display: block; } @@ -2483,7 +2481,7 @@ in src-script.js and main.js .search-results > a { padding: 5px 0px; } - .search-results > a > div.desc, .item-table > li > div.desc { + .search-results > a > div.desc, .item-table dd { padding-left: 2em; } .search-results .result-name { @@ -2544,12 +2542,20 @@ in src-script.js and main.js box-shadow: 0 0 4px var(--main-background-color); } - .item-table > li > .item-name { - width: 33%; + /* Since the screen is wide enough, we show items on their description on the same line. */ + .item-table:not(.reexports) { + display: grid; + grid-template-columns: 33% 67%; } - .item-table > li > div { + .item-table > dt, .item-table > dd { overflow-wrap: anywhere; } + .item-table > dt { + grid-column-start: 1; + } + .item-table > dd { + grid-column-start: 2; + } } @media print { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 5fd5eb14478..660484c133c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -63,6 +63,9 @@ const TY_PRIMITIVE = itemTypes.indexOf("primitive"); const TY_GENERIC = itemTypes.indexOf("generic"); const TY_IMPORT = itemTypes.indexOf("import"); const TY_TRAIT = itemTypes.indexOf("trait"); +const TY_FN = itemTypes.indexOf("fn"); +const TY_METHOD = itemTypes.indexOf("method"); +const TY_TYMETHOD = itemTypes.indexOf("tymethod"); const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; // Hard limit on how deep to recurse into generics when doing type-driven search. @@ -191,6 +194,10 @@ function isEndCharacter(c) { return "=,>-])".indexOf(c) !== -1; } +function isFnLikeTy(ty) { + return ty === TY_FN || ty === TY_METHOD || ty === TY_TYMETHOD; +} + /** * Returns `true` if the given `c` character is a separator. * @@ -2717,9 +2724,26 @@ class DocSearch { const normalizedUserQuery = parsedQuery.userQuery.toLowerCase(); const isMixedCase = normalizedUserQuery !== userQuery; const result_list = []; + const isReturnTypeQuery = parsedQuery.elems.length === 0 || + typeInfo === "returned"; for (const result of results.values()) { result.item = this.searchIndex[result.id]; result.word = this.searchIndex[result.id].word; + if (isReturnTypeQuery) { + // we are doing a return-type based search, + // deprioritize "clone-like" results, + // ie. functions that also take the queried type as an argument. + const hasType = result.item && result.item.type; + if (!hasType) { + continue; + } + const inputs = result.item.type.inputs; + const where_clause = result.item.type.where_clause; + if (containsTypeFromQuery(inputs, where_clause)) { + result.path_dist *= 100; + result.dist *= 100; + } + } result_list.push(result); } @@ -2749,6 +2773,15 @@ class DocSearch { return a - b; } + // in type based search, put functions first + if (parsedQuery.hasReturnArrow) { + a = !isFnLikeTy(aaa.item.ty); + b = !isFnLikeTy(bbb.item.ty); + if (a !== b) { + return a - b; + } + } + // Sort by distance in the path part, if specified // (less changes required to match means higher rankings) a = aaa.path_dist; @@ -3541,6 +3574,35 @@ class DocSearch { } /** + * This function checks if the given list contains any + * (non-generic) types mentioned in the query. + * + * @param {Array<FunctionType>} list - A list of function types. + * @param {[FunctionType]} where_clause - Trait bounds for generic items. + */ + function containsTypeFromQuery(list, where_clause) { + if (!list) return false; + for (const ty of parsedQuery.returned) { + // negative type ids are generics + if (ty.id < 0) { + continue; + } + if (checkIfInList(list, ty, where_clause, null, 0)) { + return true; + } + } + for (const ty of parsedQuery.elems) { + if (ty.id < 0) { + continue; + } + if (checkIfInList(list, ty, where_clause, null, 0)) { + return true; + } + } + return false; + } + + /** * This function checks if the object (`row`) matches the given type (`elem`) and its * generics (if any). * diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7fcdfe3fb22..33166a39574 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -622,7 +622,7 @@ impl FromClean<clean::Type> for Type { impl FromClean<clean::Path> for Path { fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { - name: path.whole_name(), + name: path.last_opt().map_or(String::from(""), |s| String::from(s.as_str())), id: renderer.id_from_item_default(path.def_id().into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 96ca96ee6bc..ba620b6cb6b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -651,8 +651,15 @@ fn opts() -> Vec<RustcOptGroup> { "", "add arguments to be used when compiling doctests", ), + opt( + Unstable, + FlagMulti, + "", + "disable-minification", + "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)", + "", + ), // deprecated / removed options - opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""), opt( Stable, Multi, diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index d892c585837..9c958710c42 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -36,7 +36,26 @@ impl DocFolder for StabilityPropagator<'_, '_> { let stability = match item.item_id { ItemId::DefId(def_id) => { - let own_stability = self.cx.tcx.lookup_stability(def_id); + let item_stability = self.cx.tcx.lookup_stability(def_id); + let inline_stability = + item.inline_stmt_id.and_then(|did| self.cx.tcx.lookup_stability(did)); + let own_stability = if let Some(item_stab) = item_stability + && let StabilityLevel::Stable { since: _, allowed_through_unstable_modules } = + item_stab.level + && let Some(mut inline_stab) = inline_stability + && let StabilityLevel::Stable { + since: inline_since, + allowed_through_unstable_modules: _, + } = inline_stab.level + { + inline_stab.level = StabilityLevel::Stable { + since: inline_since, + allowed_through_unstable_modules, + }; + Some(inline_stab) + } else { + item_stability + }; let (ItemKind::StrippedItem(box kind) | kind) = &item.kind; match kind { @@ -100,7 +119,7 @@ fn merge_stability( parent_stability: Option<Stability>, ) -> Option<Stability> { if let Some(own_stab) = own_stability - && let StabilityLevel::Stable { since: own_since, allowed_through_unstable_modules: false } = + && let StabilityLevel::Stable { since: own_since, allowed_through_unstable_modules: None } = own_stab.level && let Some(parent_stab) = parent_stability && (parent_stab.is_unstable() @@ -108,12 +127,12 @@ fn merge_stability( { parent_stability } else if let Some(mut own_stab) = own_stability - && let StabilityLevel::Stable { since, allowed_through_unstable_modules: true } = + && let StabilityLevel::Stable { since, allowed_through_unstable_modules: Some(_) } = own_stab.level && parent_stability.is_some_and(|stab| stab.is_stable()) { // this property does not apply transitively through re-exports - own_stab.level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; + own_stab.level = StabilityLevel::Stable { since, allowed_through_unstable_modules: None }; Some(own_stab) } else { own_stability diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 794ea54b3ef..d46b0dee36c 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -19,7 +19,7 @@ use tracing::debug; use crate::clean::cfg::Cfg; use crate::clean::utils::{inherits_doc_hidden, should_ignore_res}; -use crate::clean::{AttributesExt, NestedAttributesExt, reexport_chain}; +use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -247,8 +247,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let document_hidden = self.cx.render_options.document_hidden; let use_attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) - || (document_hidden && use_attrs.lists(sym::doc).has_word(sym::hidden)); + let is_no_inline = hir_attr_lists(use_attrs, sym::doc).has_word(sym::no_inline) + || (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden)); if is_no_inline { return false; |
