diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2024-12-23 10:12:23 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-23 10:12:23 +0000 |
| commit | 8dbdcc03ebfd5d3c21671d8a021669dc79d93038 (patch) | |
| tree | e61d058d30fdd35c4a306fde5be669b08092a4fd /src/librustdoc | |
| parent | 63a3c394617b114a8fa6e54401700b3adee65a7d (diff) | |
| parent | 0180d2d16f5f5d60384a594568a98a6e6f8eea59 (diff) | |
Merge pull request #18746 from lnicola/sync-from-rust
minor: Sync from downstream
Diffstat (limited to 'src/librustdoc')
26 files changed, 497 insertions, 286 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d81c47886d2..019a888bd2f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -4,6 +4,7 @@ use std::iter::once; use std::sync::Arc; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::Mutability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId}; @@ -15,7 +16,6 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; -use {rustc_ast as ast, rustc_hir as hir}; use super::Item; use crate::clean::{ @@ -43,7 +43,7 @@ pub(crate) fn try_inline( cx: &mut DocContext<'_>, res: Res, name: Symbol, - attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, + attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, visited: &mut DefIdSet, ) -> Option<Vec<clean::Item>> { let did = res.opt_def_id()?; @@ -206,7 +206,7 @@ pub(crate) fn try_inline_glob( } } -pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [ast::Attribute] { +pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [hir::Attribute] { cx.tcx.get_attrs_unchecked(did) } @@ -360,7 +360,7 @@ fn build_type_alias( pub(crate) fn build_impls( cx: &mut DocContext<'_>, did: DefId, - attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, + attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, ret: &mut Vec<clean::Item>, ) { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); @@ -392,8 +392,8 @@ pub(crate) fn build_impls( pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, - old_attrs: &[ast::Attribute], - new_attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, + old_attrs: &[hir::Attribute], + new_attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export @@ -404,14 +404,14 @@ pub(crate) fn merge_attrs( both.extend_from_slice(old_attrs); ( if let Some(item_id) = item_id { - Attributes::from_ast_with_additional(old_attrs, (inner, item_id.to_def_id())) + Attributes::from_hir_with_additional(old_attrs, (inner, item_id.to_def_id())) } else { - Attributes::from_ast(&both) + Attributes::from_hir(&both) }, both.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } else { - (Attributes::from_ast(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) + (Attributes::from_hir(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) } } @@ -419,7 +419,7 @@ pub(crate) fn merge_attrs( pub(crate) fn build_impl( cx: &mut DocContext<'_>, did: DefId, - attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, + attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, ret: &mut Vec<clean::Item>, ) { if !cx.inlined.insert(did.into()) { @@ -629,7 +629,7 @@ fn build_module_items( visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, allowed_def_ids: Option<&DefIdSet>, - attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, + attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, ) -> Vec<clean::Item> { let mut items = Vec::new(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 34141c47cf3..9d0c0f687c7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -55,7 +55,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds; use thin_vec::ThinVec; use tracing::{debug, instrument}; use utils::*; -use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; pub(crate) use self::types::*; pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls}; @@ -201,7 +201,7 @@ fn generate_item_with_correct_attrs( }; let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); - let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); + let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); let name = renamed.or(Some(name)); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg); @@ -1036,7 +1036,7 @@ fn clean_fn_or_proc_macro<'tcx>( /// This is needed to make it more "readable" when documenting functions using /// `rustc_legacy_const_generics`. More information in /// <https://github.com/rust-lang/rust/issues/83167>. -fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) { +fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attribute]) { for meta_item_list in attrs .iter() .filter(|a| a.has_name(sym::rustc_legacy_const_generics)) @@ -1222,14 +1222,16 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext let local_did = trait_item.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match trait_item.kind { - hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(Box::new(Constant { - generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), - kind: ConstantKind::Local { def_id: local_did, body: default }, - type_: clean_ty(ty, cx), - })), + hir::TraitItemKind::Const(ty, Some(default)) => { + ProvidedAssocConstItem(Box::new(Constant { + generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), + kind: ConstantKind::Local { def_id: local_did, body: default }, + type_: clean_ty(ty, cx), + })) + } hir::TraitItemKind::Const(ty, None) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); - TyAssocConstItem(generics, Box::new(clean_ty(ty, cx))) + RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); @@ -1237,7 +1239,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names)); - TyMethodItem(m) + RequiredMethodItem(m) } hir::TraitItemKind::Type(bounds, Some(default)) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); @@ -1257,7 +1259,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitItemKind::Type(bounds, None) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); - TyAssocTypeItem(generics, bounds) + RequiredAssocTypeItem(generics, bounds) } }; Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx) @@ -1271,7 +1273,7 @@ pub(crate) fn clean_impl_item<'tcx>( let local_did = impl_.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match impl_.kind { - hir::ImplItemKind::Const(ty, expr) => AssocConstItem(Box::new(Constant { + hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant { generics: clean_generics(impl_.generics, cx), kind: ConstantKind::Local { def_id: local_did, body: expr }, type_: clean_ty(ty, cx), @@ -1320,18 +1322,23 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo ); simplify::move_bounds_to_generic_parameters(&mut generics); - let provided = match assoc_item.container { - ty::AssocItemContainer::Impl => true, - ty::AssocItemContainer::Trait => tcx.defaultness(assoc_item.def_id).has_value(), - }; - if provided { - AssocConstItem(Box::new(Constant { + match assoc_item.container { + ty::AssocItemContainer::Impl => ImplAssocConstItem(Box::new(Constant { generics, kind: ConstantKind::Extern { def_id: assoc_item.def_id }, type_: ty, - })) - } else { - TyAssocConstItem(generics, Box::new(ty)) + })), + ty::AssocItemContainer::Trait => { + if tcx.defaultness(assoc_item.def_id).has_value() { + ProvidedAssocConstItem(Box::new(Constant { + generics, + kind: ConstantKind::Extern { def_id: assoc_item.def_id }, + type_: ty, + })) + } else { + RequiredAssocConstItem(generics, Box::new(ty)) + } + } } } ty::AssocKind::Fn => { @@ -1369,7 +1376,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo }; MethodItem(item, defaultness) } else { - TyMethodItem(item) + RequiredMethodItem(item) } } ty::AssocKind::Type => { @@ -1486,7 +1493,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo bounds, ) } else { - TyAssocTypeItem(generics, bounds) + RequiredAssocTypeItem(generics, bounds) } } else { AssocTypeItem( @@ -1839,11 +1846,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T DynTrait(bounds, lifetime) } TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), - // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. - TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, - TyKind::AnonAdt(..) => { - unimplemented!("Anonymous structs or unions are not supported yet") + TyKind::UnsafeBinder(..) => { + unimplemented!("unsafe binders are not supported yet") } + // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. + TyKind::Infer + | TyKind::Err(_) + | TyKind::Typeof(..) + | TyKind::InferDelegation(..) + | TyKind::TraitAscription(_) => Infer, } } @@ -2574,7 +2585,7 @@ fn get_all_import_attributes<'hir>( import_def_id: LocalDefId, target_def_id: DefId, is_inline: bool, -) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> { +) -> Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)> { let mut attrs = Vec::new(); let mut first = true; for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id) @@ -2600,7 +2611,7 @@ fn filter_tokens_from_list( ) -> Vec<TokenTree> { let mut tokens = Vec::with_capacity(args_tokens.len()); let mut skip_next_comma = false; - for token in args_tokens.trees() { + for token in args_tokens.iter() { match token { TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => { skip_next_comma = false; @@ -2627,9 +2638,9 @@ fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { /// Remove attributes from `normal` that should not be inherited by `use` re-export. /// Before calling this function, make sure `normal` is a `#[doc]` attribute. -fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { - match normal.item.args { - ast::AttrArgs::Delimited(ref mut args) => { +fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) { + match args { + hir::AttrArgs::Delimited(ref mut args) => { let tokens = filter_tokens_from_list(&args.tokens, |token| { !matches!( token, @@ -2647,7 +2658,7 @@ fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { }); args.tokens = TokenStream::new(tokens); } - ast::AttrArgs::Empty | ast::AttrArgs::Eq { .. } => {} + hir::AttrArgs::Empty | hir::AttrArgs::Eq { .. } => {} } } @@ -2672,23 +2683,23 @@ fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { /// * `doc(no_inline)` /// * `doc(hidden)` fn add_without_unwanted_attributes<'hir>( - attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>, - new_attrs: &'hir [ast::Attribute], + attrs: &mut Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)>, + new_attrs: &'hir [hir::Attribute], is_inline: bool, import_parent: Option<DefId>, ) { for attr in new_attrs { - if matches!(attr.kind, ast::AttrKind::DocComment(..)) { + if matches!(attr.kind, hir::AttrKind::DocComment(..)) { attrs.push((Cow::Borrowed(attr), import_parent)); continue; } let mut attr = attr.clone(); match attr.kind { - ast::AttrKind::Normal(ref mut normal) => { - if let [ident] = &*normal.item.path.segments { - let ident = ident.ident.name; + hir::AttrKind::Normal(ref mut normal) => { + if let [ident] = &*normal.path.segments { + let ident = ident.name; if ident == sym::doc { - filter_doc_attr(normal, is_inline); + filter_doc_attr(&mut normal.args, is_inline); attrs.push((Cow::Owned(attr), import_parent)); } else if is_inline || ident != sym::cfg { // If it's not a `cfg()` attribute, we keep it. @@ -2891,7 +2902,7 @@ fn clean_extern_crate<'tcx>( && attrs.iter().any(|a| { a.has_name(sym::doc) && match a.meta_item_list() { - Some(l) => attr::list_contains_name(&l, sym::inline), + Some(l) => ast::attr::list_contains_name(&l, sym::inline), None => false, } }) @@ -2996,8 +3007,8 @@ fn clean_use_statement_inner<'tcx>( a.has_name(sym::doc) && match a.meta_item_list() { Some(l) => { - attr::list_contains_name(&l, sym::no_inline) - || attr::list_contains_name(&l, sym::hidden) + ast::attr::list_contains_name(&l, sym::no_inline) + || ast::attr::list_contains_name(&l, sym::hidden) } None => false, } diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index d39ecf83ac0..3cc5f8d615a 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -131,7 +131,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) { use State::*; let mut state = Start; - for tt in tts.trees() { + for tt in tts.iter() { let (needs_space, next_state) = match &tt { TokenTree::Token(tt, _) => match (state, &tt.kind) { (Dollar, token::Ident(..)) => (false, DollarIdent), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cba947eb833..8c7ab925577 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,9 +6,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_ast::MetaItemInner; -use rustc_ast_pretty::pprust; -use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; +use rustc_attr_parsing::{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}; @@ -454,14 +452,14 @@ impl Item { kind: ItemKind, cx: &mut DocContext<'_>, ) -> Item { - let ast_attrs = cx.tcx.get_attrs_unchecked(def_id); + let hir_attrs = cx.tcx.get_attrs_unchecked(def_id); Self::from_def_id_and_attrs_and_parts( def_id, name, kind, - Attributes::from_ast(ast_attrs), - ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), + Attributes::from_hir(hir_attrs), + hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } @@ -547,14 +545,14 @@ impl Item { pub(crate) fn is_associated_type(&self) -> bool { matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..))) } - pub(crate) fn is_ty_associated_type(&self) -> bool { - matches!(self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..))) + pub(crate) fn is_required_associated_type(&self) -> bool { + matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..))) } pub(crate) fn is_associated_const(&self) -> bool { - matches!(self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..))) + matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..)))) } - pub(crate) fn is_ty_associated_const(&self) -> bool { - matches!(self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..))) + pub(crate) fn is_required_associated_const(&self) -> bool { + matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..))) } pub(crate) fn is_method(&self) -> bool { self.type_() == ItemType::Method @@ -671,7 +669,9 @@ impl Item { asyncness: hir::IsAsync::NotAsync, } } - ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => { + ItemKind::FunctionItem(_) + | ItemKind::MethodItem(_, _) + | ItemKind::RequiredMethodItem(_) => { let def_id = self.def_id().unwrap(); build_fn_header(def_id, tcx, tcx.asyncness(def_id)) } @@ -701,8 +701,13 @@ impl Item { // Variants always inherit visibility VariantItem(..) | ImplItem(..) => return None, // Trait items inherit the trait's visibility - AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..) - | TyMethodItem(..) | MethodItem(..) => { + RequiredAssocConstItem(..) + | ProvidedAssocConstItem(..) + | ImplAssocConstItem(..) + | AssocTypeItem(..) + | RequiredAssocTypeItem(..) + | RequiredMethodItem(..) + | MethodItem(..) => { let assoc_item = tcx.associated_item(def_id); let is_trait_item = match assoc_item.container { ty::AssocItemContainer::Trait => true, @@ -742,10 +747,10 @@ impl Item { .iter() .filter_map(|attr| { if keep_as_is { - Some(pprust::attribute_to_string(attr)) + Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { Some( - pprust::attribute_to_string(attr) + rustc_hir_pretty::attribute_to_string(&tcx, attr) .replace("\\\n", "") .replace('\n', "") .replace(" ", " "), @@ -847,10 +852,10 @@ pub(crate) enum ItemKind { TraitAliasItem(TraitAlias), ImplItem(Box<Impl>), /// A required method in a trait declaration meaning it's only a function signature. - TyMethodItem(Box<Function>), + RequiredMethodItem(Box<Function>), /// A method in a trait impl or a provided method in a trait declaration. /// - /// Compared to [TyMethodItem], it also contains a method body. + /// Compared to [RequiredMethodItem], it also contains a method body. MethodItem(Box<Function>, Option<hir::Defaultness>), StructFieldItem(Type), VariantItem(Variant), @@ -864,14 +869,16 @@ pub(crate) enum ItemKind { ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), /// A required associated constant in a trait declaration. - TyAssocConstItem(Generics, Box<Type>), + RequiredAssocConstItem(Generics, Box<Type>), ConstantItem(Box<Constant>), - /// An associated constant in a trait impl or a provided one in a trait declaration. - AssocConstItem(Box<Constant>), + /// An associated constant in a trait declaration with provided default value. + ProvidedAssocConstItem(Box<Constant>), + /// An associated constant in an inherent impl or trait impl. + ImplAssocConstItem(Box<Constant>), /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. - TyAssocTypeItem(Generics, Vec<GenericBound>), + RequiredAssocTypeItem(Generics, Vec<GenericBound>), /// An associated type in a trait impl or a provided one in a trait declaration. AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>), /// An item that has been stripped by a rustdoc pass @@ -902,7 +909,7 @@ impl ItemKind { | StaticItem(_) | ConstantItem(_) | TraitAliasItem(_) - | TyMethodItem(_) + | RequiredMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) | ForeignFunctionItem(_, _) @@ -911,9 +918,10 @@ impl ItemKind { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | TyAssocConstItem(..) - | AssocConstItem(..) - | TyAssocTypeItem(..) + | RequiredAssocConstItem(..) + | ProvidedAssocConstItem(..) + | ImplAssocConstItem(..) + | RequiredAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) | KeywordItem => [].iter(), @@ -955,7 +963,7 @@ pub(crate) trait AttributesExt { type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> where Self: 'a; - type Attributes<'a>: Iterator<Item = &'a ast::Attribute> + type Attributes<'a>: Iterator<Item = &'a hir::Attribute> where Self: 'a; @@ -1009,7 +1017,7 @@ pub(crate) trait AttributesExt { // #[doc] if attr.doc_str().is_none() && attr.has_name(sym::doc) { // #[doc(...)] - if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) { + if let Some(list) = attr.meta_item_list() { for item in list { // #[doc(hidden)] if !item.has_name(sym::cfg) { @@ -1042,7 +1050,7 @@ pub(crate) trait AttributesExt { 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(&MetaItemInner::MetaItem(meta)) { + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { cfg &= feat_cfg; } } @@ -1053,14 +1061,14 @@ pub(crate) trait AttributesExt { } } -impl AttributesExt for [ast::Attribute] { +impl AttributesExt for [hir::Attribute] { type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; - type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + '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::Attribute::meta_item_list) + .filter_map(ast::attr::AttributeExt::meta_item_list) .flatten() } @@ -1069,20 +1077,20 @@ impl AttributesExt for [ast::Attribute] { } } -impl AttributesExt for [(Cow<'_, ast::Attribute>, Option<DefId>)] { +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 ast::Attribute> + '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(ast::Attribute::meta_item_list) + .filter_map(hir::Attribute::meta_item_list) .flatten() } @@ -1152,7 +1160,7 @@ pub struct RenderedLink { #[derive(Clone, Debug, Default)] pub(crate) struct Attributes { pub(crate) doc_strings: Vec<DocFragment>, - pub(crate) other_attrs: ast::AttrVec, + pub(crate) other_attrs: ThinVec<hir::Attribute>, } impl Attributes { @@ -1180,22 +1188,22 @@ impl Attributes { self.has_doc_flag(sym::hidden) } - pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes { - Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false) + pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes { + Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false) } - pub(crate) fn from_ast_with_additional( - attrs: &[ast::Attribute], - (additional_attrs, def_id): (&[ast::Attribute], DefId), + pub(crate) fn from_hir_with_additional( + attrs: &[hir::Attribute], + (additional_attrs, def_id): (&[hir::Attribute], DefId), ) -> Attributes { // Additional documentation should be shown before the original documentation. let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id))); let attrs2 = attrs.iter().map(|attr| (attr, None)); - Attributes::from_ast_iter(attrs1.chain(attrs2), false) + Attributes::from_hir_iter(attrs1.chain(attrs2), false) } - pub(crate) fn from_ast_iter<'a>( - attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>, + pub(crate) fn from_hir_iter<'a>( + attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>, doc_only: bool, ) -> Attributes { let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index d59b4e4081c..8aeebdde7bb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -578,11 +578,10 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { } pub(crate) fn attrs_have_doc_flag<'a>( - mut attrs: impl Iterator<Item = &'a ast::Attribute>, + mut attrs: impl Iterator<Item = &'a hir::Attribute>, flag: Symbol, ) -> bool { - attrs - .any(|attr| attr.meta_item_list().is_some_and(|l| rustc_attr::list_contains_name(&l, flag))) + attrs.any(|attr| attr.meta_item_list().is_some_and(|l| ast::attr::list_contains_name(&l, flag))) } /// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 34c91e33db7..af3c7cc7be3 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -172,6 +172,9 @@ pub(crate) struct Options { /// This is mainly useful for other tools that reads that debuginfo to figure out /// how to call the compiler with the same arguments. pub(crate) expanded_args: Vec<String>, + + /// Arguments to be used when compiling doctests. + pub(crate) doctest_compilation_args: Vec<String>, } impl fmt::Debug for Options { @@ -774,6 +777,7 @@ impl Options { let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); + let doctest_compilation_args = matches.opt_strs("doctest-compilation-args"); let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); @@ -819,6 +823,7 @@ impl Options { scrape_examples_options, unstable_features, expanded_args: args, + doctest_compilation_args, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 70d9269ae5c..e6e5123d0bb 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -13,10 +13,10 @@ use std::{panic, str}; pub(crate) use make::DocTestBuilder; pub(crate) use markdown::test as test_markdown; -use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; +use rustc_hir as hir; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::interface; @@ -50,6 +50,46 @@ pub(crate) struct GlobalTestOptions { pub(crate) args_file: PathBuf, } +/// Function used to split command line arguments just like a shell would. +fn split_args(args: &str) -> Vec<String> { + let mut out = Vec::new(); + let mut iter = args.chars(); + let mut current = String::new(); + + while let Some(c) = iter.next() { + if c == '\\' { + if let Some(c) = iter.next() { + // If it's escaped, even a quote or a whitespace will be ignored. + current.push(c); + } + } else if c == '"' || c == '\'' { + while let Some(new_c) = iter.next() { + if new_c == c { + break; + } else if new_c == '\\' { + if let Some(c) = iter.next() { + // If it's escaped, even a quote will be ignored. + current.push(c); + } + } else { + current.push(new_c); + } + } + } else if " \n\t\r".contains(c) { + if !current.is_empty() { + out.push(current.clone()); + current.clear(); + } + } else { + current.push(c); + } + } + if !current.is_empty() { + out.push(current); + } + out +} + pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> { let mut file = File::create(file_path) .map_err(|error| format!("failed to create args file: {error:?}"))?; @@ -78,6 +118,10 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> content.push(format!("-Z{unstable_option_str}")); } + for compilation_args in &options.doctest_compilation_args { + content.extend(split_args(compilation_args)); + } + let content = content.join("\n"); file.write_all(content.as_bytes()) @@ -174,28 +218,28 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions compiling_test_count, .. } = interface::run_compiler(config, |compiler| { - compiler.enter(|queries| { - let collector = queries.global_ctxt().enter(|tcx| { - let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); - let opts = scrape_test_config(crate_name, crate_attrs, args_path); - let enable_per_target_ignores = options.enable_per_target_ignores; - - let mut collector = CreateRunnableDocTests::new(options, opts); - let hir_collector = HirCollector::new( - ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), - enable_per_target_ignores, - tcx, - ); - let tests = hir_collector.collect_crate(); - tests.into_iter().for_each(|t| collector.add_test(t)); - - collector - }); - compiler.sess.dcx().abort_if_errors(); + let krate = rustc_interface::passes::parse(&compiler.sess); + + let collector = rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); + let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); + let opts = scrape_test_config(crate_name, crate_attrs, args_path); + let enable_per_target_ignores = options.enable_per_target_ignores; + + let mut collector = CreateRunnableDocTests::new(options, opts); + let hir_collector = HirCollector::new( + ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), + enable_per_target_ignores, + tcx, + ); + let tests = hir_collector.collect_crate(); + tests.into_iter().for_each(|t| collector.add_test(t)); collector - }) + }); + compiler.sess.dcx().abort_if_errors(); + + collector }); run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests); @@ -325,7 +369,7 @@ pub(crate) fn run_tests( // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. fn scrape_test_config( crate_name: String, - attrs: &[ast::Attribute], + attrs: &[hir::Attribute], args_file: PathBuf, ) -> GlobalTestOptions { use rustc_ast_pretty::pprust; diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 3ae60938749..a188bc8ebd9 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -51,8 +51,17 @@ impl DocTestBuilder { !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate }); - let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } = - partition_source(source, edition); + let Some(SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else }) = + partition_source(source, edition) + else { + return Self::invalid( + String::new(), + String::new(), + String::new(), + source.to_string(), + test_id, + ); + }; // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern // crate already is included. @@ -77,18 +86,7 @@ impl DocTestBuilder { else { // If the parser panicked due to a fatal error, pass the test code through unchanged. // The error will be reported during compilation. - return Self { - supports_color: false, - has_main_fn: false, - crate_attrs, - maybe_crate_attrs, - crates, - everything_else, - already_has_extern_crate: false, - test_id, - failed_ast: true, - can_be_merged: false, - }; + return Self::invalid(crate_attrs, maybe_crate_attrs, crates, everything_else, test_id); }; // If the AST returned an error, we don't want this doctest to be merged with the // others. Same if it contains `#[feature]` or `#[no_std]`. @@ -113,6 +111,27 @@ impl DocTestBuilder { } } + fn invalid( + crate_attrs: String, + maybe_crate_attrs: String, + crates: String, + everything_else: String, + test_id: Option<String>, + ) -> Self { + Self { + supports_color: false, + has_main_fn: false, + crate_attrs, + maybe_crate_attrs, + crates, + everything_else, + already_has_extern_crate: false, + test_id, + failed_ast: true, + can_be_merged: false, + } + } + /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of /// lines before the test code begins. pub(crate) fn generate_unique_doctest( @@ -518,8 +537,8 @@ fn handle_attr(mod_attr_pending: &mut String, source_info: &mut SourceInfo, edit push_to.push('\n'); // If it's complete, then we can clear the pending content. mod_attr_pending.clear(); - } else if mod_attr_pending.ends_with('\\') { - mod_attr_pending.push('n'); + } else { + mod_attr_pending.push_str("\n"); } } @@ -531,7 +550,7 @@ struct SourceInfo { everything_else: String, } -fn partition_source(s: &str, edition: Edition) -> SourceInfo { +fn partition_source(s: &str, edition: Edition) -> Option<SourceInfo> { #[derive(Copy, Clone, PartialEq)] enum PartitionState { Attrs, @@ -606,11 +625,16 @@ fn partition_source(s: &str, edition: Edition) -> SourceInfo { } } + if !mod_attr_pending.is_empty() { + debug!("invalid doctest code: {s:?}"); + return None; + } + source_info.everything_else = source_info.everything_else.trim().to_string(); debug!("crate_attrs:\n{}{}", source_info.crate_attrs, source_info.maybe_crate_attrs); debug!("crates:\n{}", source_info.crates); debug!("after:\n{}", source_info.everything_else); - source_info + Some(source_info) } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index dc68f48f635..0903baddabe 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -110,7 +110,7 @@ impl HirCollector<'_> { // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with // anything else, this will combine them for us. - let attrs = Attributes::from_ast(ast_attrs); + let attrs = Attributes::from_hir(ast_attrs); if let Some(doc) = attrs.opt_doc_value() { let span = span_of_fragments(&attrs.doc_strings).unwrap_or(sp); self.collector.position = if span.edition().at_least_rust_2024() { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 160d0f222b4..fa6cca3681b 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -379,3 +379,25 @@ fn main() { let (output, len) = make_test(input, None, false, &opts, None); assert_eq!((output, len), (expected, 1)); } + +#[test] +fn check_split_args() { + fn compare(input: &str, expected: &[&str]) { + let output = super::split_args(input); + let expected = expected.iter().map(|s| s.to_string()).collect::<Vec<_>>(); + assert_eq!(expected, output, "test failed for {input:?}"); + } + + compare("'a' \"b\"c", &["a", "bc"]); + compare("'a' \"b \"c d", &["a", "b c", "d"]); + compare("'a' \"b\\\"c\"", &["a", "b\"c"]); + compare("'a\"'", &["a\""]); + compare("\"a'\"", &["a'"]); + compare("\\ a", &[" a"]); + compare("\\\\", &["\\"]); + compare("a'", &["a"]); + compare("a ", &["a"]); + compare("a b", &["a", "b"]); + compare("a\n\t \rb", &["a", "b"]); + compare("a\n\t1 \rb", &["a", "1", "b"]); +} diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 95e495205ae..c03d16ad081 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -82,7 +82,7 @@ pub(crate) trait DocFolder: Sized { | StaticItem(_) | ConstantItem(..) | TraitAliasItem(_) - | TyMethodItem(_) + | RequiredMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) | ForeignFunctionItem(..) @@ -91,9 +91,10 @@ pub(crate) trait DocFolder: Sized { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | TyAssocConstItem(..) - | AssocConstItem(..) - | TyAssocTypeItem(..) + | RequiredAssocConstItem(..) + | ProvidedAssocConstItem(..) + | ImplAssocConstItem(..) + | RequiredAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem => kind, } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e387eb010be..b63122565c4 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -334,12 +334,13 @@ impl DocFolder for CacheBuilder<'_, '_> { clean::ExternCrateItem { .. } | clean::ImportItem(..) | clean::ImplItem(..) - | clean::TyMethodItem(..) + | clean::RequiredMethodItem(..) | clean::MethodItem(..) | clean::StructFieldItem(..) - | clean::TyAssocConstItem(..) - | clean::AssocConstItem(..) - | clean::TyAssocTypeItem(..) + | clean::RequiredAssocConstItem(..) + | clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) + | clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) | clean::StrippedItem(..) | clean::KeywordItem => { @@ -443,15 +444,17 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It let item_def_id = item.item_id.as_def_id().unwrap(); let (parent_did, parent_path) = match item.kind { clean::StrippedItem(..) => return, - clean::AssocConstItem(..) | clean::AssocTypeItem(..) + clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) + | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => { // skip associated items in trait impls return; } - clean::TyMethodItem(..) - | clean::TyAssocConstItem(..) - | clean::TyAssocTypeItem(..) + clean::RequiredMethodItem(..) + | clean::RequiredAssocConstItem(..) + | clean::RequiredAssocTypeItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => { // Don't index if containing module is stripped (i.e., private), @@ -467,7 +470,10 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It let parent_path = &cache.stack[..cache.stack.len() - 1]; (Some(parent_did), parent_path) } - clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { + clean::MethodItem(..) + | clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) + | clean::AssocTypeItem(..) => { let last = cache.parent_stack.last().expect("parent_stack is empty 2"); let parent_did = match last { // impl Trait for &T { fn method(self); } diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 383e3135faa..de6537e992f 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -88,7 +88,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ConstantItem(..) => ItemType::Constant, clean::TraitItem(..) => ItemType::Trait, clean::ImplItem(..) => ItemType::Impl, - clean::TyMethodItem(..) => ItemType::TyMethod, + clean::RequiredMethodItem(..) => ItemType::TyMethod, clean::MethodItem(..) => ItemType::Method, clean::StructFieldItem(..) => ItemType::StructField, clean::VariantItem(..) => ItemType::Variant, @@ -96,8 +96,10 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic clean::MacroItem(..) => ItemType::Macro, clean::PrimitiveItem(..) => ItemType::Primitive, - clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst, - clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, + clean::RequiredAssocConstItem(..) + | clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) => ItemType::AssocConst, + clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0a563b1df26..136002b8e15 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,7 +15,7 @@ use std::iter::{self, once}; use itertools::Itertools; use rustc_abi::ExternAbi; -use rustc_attr::{ConstStability, StabilityLevel, StableSince}; +use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -1626,10 +1626,7 @@ pub(crate) trait PrintWithSpace { impl PrintWithSpace for hir::Safety { fn print_with_space(&self) -> &str { - match self { - hir::Safety::Unsafe => "unsafe ", - hir::Safety::Safe => "", - } + self.prefix_str() } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 90c49270566..aa8fdaaee4c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -344,35 +344,48 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, I: Iterator<Item = Event<'a>>> { - inner: I, +struct LinkReplacerInner<'a> { links: &'a [RenderedLink], shortcut_link: Option<&'a RenderedLink>, } +struct LinkReplacer<'a, I: Iterator<Item = Event<'a>>> { + iter: I, + inner: LinkReplacerInner<'a>, +} + impl<'a, I: Iterator<Item = Event<'a>>> LinkReplacer<'a, I> { fn new(iter: I, links: &'a [RenderedLink]) -> Self { - LinkReplacer { inner: iter, links, shortcut_link: None } + LinkReplacer { iter, inner: { LinkReplacerInner { links, shortcut_link: None } } } } } -impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { - type Item = Event<'a>; +// FIXME: Once we have specialized trait impl (for `Iterator` impl on `LinkReplacer`), +// we can remove this type and move back `LinkReplacerInner` fields into `LinkReplacer`. +struct SpannedLinkReplacer<'a, I: Iterator<Item = SpannedEvent<'a>>> { + iter: I, + inner: LinkReplacerInner<'a>, +} - fn next(&mut self) -> Option<Self::Item> { - let mut event = self.inner.next(); +impl<'a, I: Iterator<Item = SpannedEvent<'a>>> SpannedLinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + SpannedLinkReplacer { iter, inner: { LinkReplacerInner { links, shortcut_link: None } } } + } +} +impl<'a> LinkReplacerInner<'a> { + fn handle_event(&mut self, event: &mut Event<'a>) { // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). - match &mut event { + match event { // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` // Remove any disambiguator. - Some(Event::Start(Tag::Link { + Event::Start(Tag::Link { // [fn@f] or [fn@f][] link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, dest_url, title, .. - })) => { + }) => { debug!("saw start of shortcut link to {dest_url} with title {title}"); // If this is a shortcut link, it was resolved by the broken_link_callback. // So the URL will already be updated properly. @@ -389,13 +402,13 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { } } // Now that we're done with the shortcut link, don't replace any more text. - Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => { + Event::End(TagEnd::Link) if self.shortcut_link.is_some() => { debug!("saw end of shortcut link"); self.shortcut_link = None; } // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. // [`fn@f`] - Some(Event::Code(text)) => { + Event::Code(text) => { trace!("saw code {text}"); if let Some(link) = self.shortcut_link { // NOTE: this only replaces if the code block is the *entire* text. @@ -418,7 +431,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { } // Replace plain text in links, but only in the middle of a shortcut link. // [fn@f] - Some(Event::Text(text)) => { + Event::Text(text) => { trace!("saw text {text}"); if let Some(link) = self.shortcut_link { // NOTE: same limitations as `Event::Code` @@ -434,7 +447,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { } // If this is a link, but not a shortcut link, // replace the URL, since the broken_link_callback was not called. - Some(Event::Start(Tag::Link { dest_url, title, .. })) => { + Event::Start(Tag::Link { dest_url, title, .. }) => { if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest_url) { @@ -447,12 +460,33 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { // Anything else couldn't have been a valid Rust path, so no need to replace the text. _ => {} } + } +} + +impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { + type Item = Event<'a>; + fn next(&mut self) -> Option<Self::Item> { + let mut event = self.iter.next(); + if let Some(ref mut event) = event { + self.inner.handle_event(event); + } // Yield the modified event event } } +impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for SpannedLinkReplacer<'a, I> { + type Item = SpannedEvent<'a>; + + fn next(&mut self) -> Option<Self::Item> { + let Some((mut event, range)) = self.iter.next() else { return None }; + self.inner.handle_event(&mut event); + // Yield the modified event + Some((event, range)) + } +} + /// Wrap HTML tables into `<div>` to prevent having the doc blocks width being too big. struct TableWrapper<'a, I: Iterator<Item = Event<'a>>> { inner: I, @@ -1339,9 +1373,9 @@ impl<'a> Markdown<'a> { ids.handle_footnotes(|ids, existing_footnotes| { let p = HeadingLinks::new(p, None, ids, heading_offset); + let p = SpannedLinkReplacer::new(p, links); let p = footnotes::Footnotes::new(p, existing_footnotes); - let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); - let p = TableWrapper::new(p); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); CodeBlocks::new(p, codes, edition, playground) }) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e013829e5e0..dfdf2cd6ec3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -44,14 +44,15 @@ use std::path::PathBuf; use std::{fs, str}; use rinja::Template; -use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince}; +use rustc_attr_parsing::{ + ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, +}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::Mutability; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::RustcVersion; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName}; use serde::ser::SerializeMap; @@ -835,12 +836,23 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default() } +#[derive(Debug)] +enum AssocConstValue<'a> { + // In trait definitions, it is relevant for the public API whether an + // associated constant comes with a default value, so even if we cannot + // render its value, the presence of a value must be shown using `= _`. + TraitDefault(&'a clean::ConstantKind), + // In impls, there is no need to show `= _`. + Impl(&'a clean::ConstantKind), + None, +} + fn assoc_const( w: &mut Buffer, it: &clean::Item, generics: &clean::Generics, ty: &clean::Type, - default: Option<&clean::ConstantKind>, + value: AssocConstValue<'_>, link: AssocItemLink<'_>, indent: usize, cx: &Context<'_>, @@ -856,15 +868,20 @@ fn assoc_const( generics = generics.print(cx), ty = ty.print(cx), ); - if let Some(default) = default { - w.write_str(" = "); - + if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value { // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the // hood which adds noisy underscores and a type suffix to number literals. // This hurts readability in this context especially when more complex expressions // are involved and it doesn't add much of value. // Find a way to print constants here without all that jazz. - write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); + let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx)); + if match value { + AssocConstValue::TraitDefault(_) => true, // always show + AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show + AssocConstValue::None => unreachable!(), + } { + write!(w, " = {}", Escape(&repr)); + } } write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); } @@ -1075,33 +1092,43 @@ fn render_assoc_item( ) { match &item.kind { clean::StrippedItem(..) => {} - clean::TyMethodItem(m) => { + clean::RequiredMethodItem(m) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } clean::MethodItem(m, _) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } - clean::TyAssocConstItem(generics, ty) => assoc_const( + clean::RequiredAssocConstItem(generics, ty) => assoc_const( w, item, generics, ty, - None, + AssocConstValue::None, link, if parent == ItemType::Trait { 4 } else { 0 }, cx, ), - clean::AssocConstItem(ci) => assoc_const( + clean::ProvidedAssocConstItem(ci) => assoc_const( w, item, &ci.generics, &ci.type_, - Some(&ci.kind), + AssocConstValue::TraitDefault(&ci.kind), link, if parent == ItemType::Trait { 4 } else { 0 }, cx, ), - clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type( + clean::ImplAssocConstItem(ci) => assoc_const( + w, + item, + &ci.generics, + &ci.type_, + AssocConstValue::Impl(&ci.kind), + link, + if parent == ItemType::Trait { 4 } else { 0 }, + cx, + ), + clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type( w, item, generics, @@ -1383,7 +1410,7 @@ fn render_deref_methods( fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { let self_type_opt = match item.kind { clean::MethodItem(ref method, _) => method.decl.receiver_type(), - clean::TyMethodItem(ref method) => method.decl.receiver_type(), + clean::RequiredMethodItem(ref method) => method.decl.receiver_type(), _ => None, }; @@ -1659,7 +1686,7 @@ fn render_impl( write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } match &item.kind { - clean::MethodItem(..) | clean::TyMethodItem(_) => { + clean::MethodItem(..) | clean::RequiredMethodItem(_) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{item_type}.{name}")); @@ -1689,7 +1716,7 @@ fn render_impl( w.write_str("</h4></section>"); } } - clean::TyAssocConstItem(ref generics, ref ty) => { + clean::RequiredAssocConstItem(ref generics, ref ty) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); @@ -1704,14 +1731,14 @@ fn render_impl( item, generics, ty, - None, + AssocConstValue::None, link.anchor(if trait_.is_some() { &source_id } else { &id }), 0, cx, ); w.write_str("</h4></section>"); } - clean::AssocConstItem(ci) => { + clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); @@ -1726,14 +1753,18 @@ fn render_impl( item, &ci.generics, &ci.type_, - Some(&ci.kind), + match item.kind { + clean::ProvidedAssocConstItem(_) => AssocConstValue::TraitDefault(&ci.kind), + clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), + _ => unreachable!(), + }, link.anchor(if trait_.is_some() { &source_id } else { &id }), 0, cx, ); w.write_str("</h4></section>"); } - clean::TyAssocTypeItem(ref generics, ref bounds) => { + clean::RequiredAssocTypeItem(ref generics, ref bounds) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); @@ -1808,11 +1839,13 @@ fn render_impl( if !impl_.is_negative_trait_impl() { for trait_item in &impl_.items { match trait_item.kind { - clean::MethodItem(..) | clean::TyMethodItem(_) => methods.push(trait_item), - clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => { + clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(trait_item), + clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => { assoc_types.push(trait_item) } - clean::TyAssocConstItem(..) | clean::AssocConstItem(_) => { + clean::RequiredAssocConstItem(..) + | clean::ProvidedAssocConstItem(_) + | clean::ImplAssocConstItem(_) => { // We render it directly since they're supposed to come first. doc_impl_item( &mut default_impl_items, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4c8d704e65b..0fb77d38f16 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -469,7 +469,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 == hir::Safety::Unsafe => + if myitem.fn_header(tcx).unwrap().safety.is_unsafe() => { "<sup title=\"unsafe function\">⚠</sup>" } @@ -651,9 +651,11 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { let tcx = cx.tcx(); let bounds = bounds(&t.bounds, false, cx); - let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>(); + let required_types = + t.items.iter().filter(|m| m.is_required_associated_type()).collect::<Vec<_>>(); let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); - let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::<Vec<_>>(); + let required_consts = + t.items.iter().filter(|m| m.is_required_associated_const()).collect::<Vec<_>>(); let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>(); let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>(); @@ -1926,9 +1928,7 @@ fn item_static( buffer, "{vis}{safe}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it, cx), - safe = safety - .map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" }) - .unwrap_or(""), + safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""), mutability = s.mutability.print_with_space(), name = it.name.unwrap(), typ = s.type_.print(cx) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index cfb62c3ca16..fe2e155c9ba 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -201,7 +201,7 @@ pub(crate) fn build_index( // exported from this same module). It's also likely to Do // What I Mean, since if a re-export changes the name, it might // also be a change in semantic meaning. - .filter(|fqp| fqp.last() == fqp.last()); + .filter(|this_fqp| this_fqp.last() == fqp.last()); Some(insert_into_map( itemid_to_pathid, ItemId::DefId(defid), @@ -423,6 +423,14 @@ pub(crate) fn build_index( } Some(path) }); + } else if let Some(parent_idx) = item.parent_idx { + let i = <isize as TryInto<usize>>::try_into(parent_idx).unwrap(); + item.path = { + let p = &crate_paths[i].1; + join_with_double_colon(&p[..p.len() - 1]) + }; + item.exact_path = + crate_paths[i].2.as_ref().map(|xp| join_with_double_colon(&xp[..xp.len() - 1])); } // Omit the parent path if it is same to that of the prior item. @@ -829,7 +837,7 @@ pub(crate) fn get_function_type_for_search( clean::ForeignFunctionItem(ref f, _) | clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) - | clean::TyMethodItem(ref f) => { + | clean::RequiredMethodItem(ref f) => { get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) } _ => return None, @@ -1199,10 +1207,11 @@ fn simplify_fn_type<'a, 'tcx>( && let Type::Path { path } = arg && let def_id = path.def_id() && let Some(trait_) = cache.traits.get(&def_id) - && trait_.items.iter().any(|at| at.is_ty_associated_type()) + && trait_.items.iter().any(|at| at.is_required_associated_type()) { for assoc_ty in &trait_.items { - if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &assoc_ty.kind + if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) = + &assoc_ty.kind && let Some(name) = assoc_ty.name { let idx = -isize::try_from(rgen.len() + 1).unwrap(); diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index e99e2f04b2c..af39d15f671 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -282,10 +282,10 @@ fn sidebar_trait<'a>( res } - let req_assoc = filter_items(&t.items, |m| m.is_ty_associated_type(), "associatedtype"); + let req_assoc = filter_items(&t.items, |m| m.is_required_associated_type(), "associatedtype"); let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype"); let req_assoc_const = - filter_items(&t.items, |m| m.is_ty_associated_const(), "associatedconstant"); + filter_items(&t.items, |m| m.is_required_associated_const(), "associatedconstant"); let prov_assoc_const = filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant"); let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod"); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 9e5cf497211..04eeee37fe8 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2592,7 +2592,12 @@ class DocSearch { const writeFn = (fnType, result) => { if (fnType.id < 0) { if (fnParamNames[-1 - fnType.id] === "") { - for (const nested of fnType.generics) { + // Normally, there's no need to shown an unhighlighted + // where clause, but if it's impl Trait, then we do. + const generics = fnType.generics.length > 0 ? + fnType.generics : + obj.type.where_clause[-1 - fnType.id]; + for (const nested of generics) { writeFn(nested, result); } return; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bb967b7f163..583d0214a46 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -6,7 +6,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; -use rustc_attr::DeprecatedSince; +use rustc_attr_parsing::DeprecatedSince; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; @@ -215,8 +215,8 @@ where } } -pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { - let rustc_attr::Deprecation { since, note, suggestion: _ } = deprecation; +pub(crate) fn from_deprecation(deprecation: rustc_attr_parsing::Deprecation) -> Deprecation { + let rustc_attr_parsing::Deprecation { since, note, suggestion: _ } = deprecation; let since = match since { DeprecatedSince::RustcVersion(version) => Some(version.to_string()), DeprecatedSince::Future => Some("TBD".to_owned()), @@ -319,7 +319,9 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), - TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)), + RequiredMethodItem(m) => { + ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)) + } ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)), StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)), ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)), @@ -339,15 +341,15 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { }) } // FIXME(generic_const_items): Add support for generic associated consts. - TyAssocConstItem(_generics, ty) => { + RequiredAssocConstItem(_generics, ty) => { ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None } } // FIXME(generic_const_items): Add support for generic associated consts. - AssocConstItem(ci) => ItemEnum::AssocConst { + ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst { type_: ci.type_.into_json(renderer), value: Some(ci.kind.expr(renderer.tcx)), }, - TyAssocTypeItem(g, b) => ItemEnum::AssocType { + RequiredAssocTypeItem(g, b) => ItemEnum::AssocType { generics: g.into_json(renderer), bounds: b.into_json(renderer), type_: None, @@ -639,7 +641,7 @@ impl FromClean<clean::BareFunctionDecl> for FunctionPointer { let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl; FunctionPointer { header: FunctionHeader { - is_unsafe: matches!(safety, rustc_hir::Safety::Unsafe), + is_unsafe: safety.is_unsafe(), is_const: false, is_async: false, abi: convert_abi(abi), @@ -669,7 +671,7 @@ impl FromClean<clean::Trait> for Trait { fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self { let tcx = renderer.tcx; let is_auto = trait_.is_auto(tcx); - let is_unsafe = trait_.safety(tcx) == rustc_hir::Safety::Unsafe; + let is_unsafe = trait_.safety(tcx).is_unsafe(); let is_dyn_compatible = trait_.is_dyn_compatible(tcx); let clean::Trait { items, generics, bounds, .. } = trait_; Trait { @@ -711,7 +713,7 @@ impl FromClean<clean::Impl> for Impl { ty::ImplPolarity::Negative => true, }; Impl { - is_unsafe: safety == rustc_hir::Safety::Unsafe, + is_unsafe: safety.is_unsafe(), generics: generics.into_json(renderer), provided_trait_methods: provided_trait_methods .into_iter() @@ -840,7 +842,7 @@ fn convert_static( Static { type_: (*stat.type_).into_json(renderer), is_mutable: stat.mutability == ast::Mutability::Mut, - is_unsafe: safety == rustc_hir::Safety::Unsafe, + is_unsafe: safety.is_unsafe(), expr: stat .expr .map(|e| rendered_const(tcx, tcx.hir().body(e), tcx.hir().body_owner_def_id(e))) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a384c286039..ff1c9c61720 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -36,7 +36,7 @@ extern crate pulldown_cmark; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr; +extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -642,6 +642,15 @@ fn opts() -> Vec<RustcOptGroup> { "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize", "path/to/doc.parts/<crate-name>", ), + opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""), + opt( + Unstable, + Multi, + "", + "doctest-compilation-args", + "", + "add arguments to be used when compiling doctests", + ), // deprecated / removed options opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""), opt( @@ -684,7 +693,6 @@ fn opts() -> Vec<RustcOptGroup> { "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information", "[rust]", ), - opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""), ] } @@ -846,58 +854,51 @@ fn main_args( let config = core::create_config(input, options, &render_options, using_internal_features); + let registered_lints = config.register_lints.is_some(); + interface::run_compiler(config, |compiler| { let sess = &compiler.sess; if sess.opts.describe_lints { - rustc_driver::describe_lints(sess); + rustc_driver::describe_lints(sess, registered_lints); return; } - compiler.enter(|queries| { - let mut gcx = queries.global_ctxt(); - if sess.dcx().has_errors().is_some() { - sess.dcx().fatal("Compilation failed, aborting rustdoc"); + let krate = rustc_interface::passes::parse(sess); + if sess.dcx().has_errors().is_some() { + sess.dcx().fatal("Compilation failed, aborting rustdoc"); + } + + rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { + core::run_global_ctxt(tcx, show_coverage, render_options, output_format) + }); + info!("finished with rustc"); + + if let Some(options) = scrape_examples_options { + return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); } - gcx.enter(|tcx| { - let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { - core::run_global_ctxt(tcx, show_coverage, render_options, output_format) - }); - info!("finished with rustc"); - - if let Some(options) = scrape_examples_options { - return scrape_examples::run( - krate, - render_opts, - cache, - tcx, - options, - bin_crate, - ); - } - - cache.crate_version = crate_version; - - if show_coverage { - // if we ran coverage, bail early, we don't need to also generate docs at this point - // (also we didn't load in any of the useful passes) - return; - } else if run_check { - // Since we're in "check" mode, no need to generate anything beyond this point. - return; - } - - info!("going to format"); - match output_format { - config::OutputFormat::Html => sess.time("render_html", || { - run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) - }), - config::OutputFormat::Json => sess.time("render_json", || { - run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) - }), - } - }) + cache.crate_version = crate_version; + + if show_coverage { + // if we ran coverage, bail early, we don't need to also generate docs at this point + // (also we didn't load in any of the useful passes) + return; + } else if run_check { + // Since we're in "check" mode, no need to generate anything beyond this point. + return; + } + + info!("going to format"); + match output_format { + config::OutputFormat::Html => sess.time("render_html", || { + run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) + }), + config::OutputFormat::Json => sess.time("render_json", || { + run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) + }), + } }) }) } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index c288a3cf2a4..0fefd13f763 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -72,10 +72,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | clean::ForeignTypeItem - | clean::AssocConstItem(..) | clean::AssocTypeItem(..) - | clean::TyAssocConstItem(..) - | clean::TyAssocTypeItem(..) + | clean::RequiredAssocConstItem(..) + | clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) + | clean::RequiredAssocTypeItem(..) // check for trait impl | clean::ImplItem(box clean::Impl { trait_: Some(_), .. }) ) diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index a81b130a218..4c682c3d4ca 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -6,7 +6,7 @@ //! [`core::error`] module is marked as stable since 1.81.0, so we want to show //! [`core::error::Error`] as stable since 1.81.0 as well. -use rustc_attr::{Stability, StabilityLevel}; +use rustc_attr_parsing::{Stability, StabilityLevel}; use rustc_hir::def_id::CRATE_DEF_ID; use crate::clean::{Crate, Item, ItemId, ItemKind}; @@ -67,11 +67,12 @@ impl DocFolder for StabilityPropagator<'_, '_> { // Don't inherit the parent's stability for these items, because they // are potentially accessible even if the parent is more unstable. ItemKind::ImplItem(..) - | ItemKind::TyMethodItem(..) + | ItemKind::RequiredMethodItem(..) | ItemKind::MethodItem(..) - | ItemKind::TyAssocConstItem(..) - | ItemKind::AssocConstItem(..) - | ItemKind::TyAssocTypeItem(..) + | ItemKind::RequiredAssocConstItem(..) + | ItemKind::ProvidedAssocConstItem(..) + | ItemKind::ImplAssocConstItem(..) + | ItemKind::RequiredAssocTypeItem(..) | ItemKind::AssocTypeItem(..) | ItemKind::PrimitiveItem(..) | ItemKind::KeywordItem => own_stability, diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 60909754b33..eedbbca0f8d 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -79,7 +79,10 @@ impl DocFolder for Stripper<'_, '_> { } } - clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { + clean::MethodItem(..) + | clean::ProvidedAssocConstItem(..) + | clean::ImplAssocConstItem(..) + | clean::AssocTypeItem(..) => { let item_id = i.item_id; if item_id.is_local() && !self.effective_visibilities.is_reachable(self.tcx, item_id.expect_def_id()) @@ -118,7 +121,9 @@ impl DocFolder for Stripper<'_, '_> { clean::ImplItem(..) => {} // tymethods etc. have no control over privacy - clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {} + clean::RequiredMethodItem(..) + | clean::RequiredAssocConstItem(..) + | clean::RequiredAssocTypeItem(..) => {} // Proc-macros are always public clean::ProcMacroItem(..) => {} diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index c2e8ffd7665..b8b619514aa 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -35,7 +35,7 @@ pub(crate) trait DocVisitor<'a>: Sized { | StaticItem(_) | ConstantItem(..) | TraitAliasItem(_) - | TyMethodItem(_) + | RequiredMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) | ForeignFunctionItem(..) @@ -44,9 +44,10 @@ pub(crate) trait DocVisitor<'a>: Sized { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | TyAssocConstItem(..) - | AssocConstItem(..) - | TyAssocTypeItem(..) + | RequiredAssocConstItem(..) + | ProvidedAssocConstItem(..) + | ImplAssocConstItem(..) + | RequiredAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem => {} } |
