diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index ec538f11831b0..b681df3a99a67 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -221,9 +221,6 @@ crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Tra fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Function { let sig = cx.tcx.fn_sig(did); - let constness = - if cx.tcx.is_const_fn_raw(did) { hir::Constness::Const } else { hir::Constness::NotConst }; - let asyncness = cx.tcx.asyncness(did); let predicates = cx.tcx.predicates_of(did); let (generics, decl) = clean::enter_impl_trait(cx, |cx| { // NOTE: generics need to be cleaned before the decl! @@ -231,11 +228,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi let decl = clean_fn_decl_from_did_and_sig(cx, Some(did), sig); (generics, decl) }); - clean::Function { - decl, - generics, - header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }, - } + clean::Function { decl, generics } } fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1e3260ce9ae2b..37c24738a2a1b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,7 +12,6 @@ crate mod utils; use rustc_ast as ast; use rustc_attr as attr; -use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -26,8 +25,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; -use rustc_target::spec::abi::Abi; -use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety; use rustc_typeck::hir_ty_to_ty; use std::assert_matches::assert_matches; @@ -813,13 +810,6 @@ fn clean_fn_or_proc_macro( } None => { let mut func = clean_function(cx, sig, generics, body_id); - let def_id = item.def_id.to_def_id(); - func.header.constness = - if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -869,7 +859,7 @@ fn clean_function( let decl = clean_fn_decl_with_args(cx, sig.decl, args); (generics, decl) }); - Function { decl, generics, header: sig.header } + Function { decl, generics } } fn clean_args_from_types_and_names( @@ -998,12 +988,7 @@ impl Clean for hir::TraitItem<'_> { AssocConstItem(ty.clean(cx), default) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let mut m = clean_function(cx, sig, &self.generics, body); - if m.header.constness == hir::Constness::Const - && is_unstable_const_fn(cx.tcx, local_did).is_some() - { - m.header.constness = hir::Constness::NotConst; - } + let m = clean_function(cx, sig, &self.generics, body); MethodItem(m, None) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { @@ -1014,13 +999,7 @@ impl Clean for hir::TraitItem<'_> { let decl = clean_fn_decl_with_args(cx, sig.decl, args); (generics, decl) }); - let mut t = Function { header: sig.header, decl, generics }; - if t.header.constness == hir::Constness::Const - && is_unstable_const_fn(cx.tcx, local_did).is_some() - { - t.header.constness = hir::Constness::NotConst; - } - TyMethodItem(t) + TyMethodItem(Function { decl, generics }) } hir::TraitItemKind::Type(bounds, ref default) => { let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); @@ -1047,12 +1026,7 @@ impl Clean for hir::ImplItem<'_> { AssocConstItem(ty.clean(cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { - let mut m = clean_function(cx, sig, &self.generics, body); - if m.header.constness == hir::Constness::Const - && is_unstable_const_fn(cx.tcx, local_did).is_some() - { - m.header.constness = hir::Constness::NotConst; - } + let m = clean_function(cx, sig, &self.generics, body); let defaultness = cx.tcx.associated_item(self.def_id).defaultness; MethodItem(m, Some(defaultness)) } @@ -1127,40 +1101,13 @@ impl Clean for ty::AssocItem { ty::TraitContainer(_) => self.defaultness.has_value(), }; if provided { - let constness = if tcx.is_const_fn_raw(self.def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - let asyncness = tcx.asyncness(self.def_id); let defaultness = match self.container { ty::ImplContainer(_) => Some(self.defaultness), ty::TraitContainer(_) => None, }; - MethodItem( - Function { - generics, - decl, - header: hir::FnHeader { - unsafety: sig.unsafety(), - abi: sig.abi(), - constness, - asyncness, - }, - }, - defaultness, - ) + MethodItem(Function { generics, decl }, defaultness) } else { - TyMethodItem(Function { - generics, - decl, - header: hir::FnHeader { - unsafety: sig.unsafety(), - abi: sig.abi(), - constness: hir::Constness::NotConst, - asyncness: hir::IsAsync::NotAsync, - }, - }) + TyMethodItem(Function { generics, decl }) } } ty::AssocKind::Type => { @@ -2192,7 +2139,6 @@ fn clean_maybe_renamed_foreign_item( cx.with_param_env(def_id, |cx| { let kind = match item.kind { hir::ForeignItemKind::Fn(decl, names, ref generics) => { - let abi = cx.tcx.hir().get_foreign_abi(item.hir_id()); let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = generics.clean(cx); @@ -2200,20 +2146,7 @@ fn clean_maybe_renamed_foreign_item( let decl = clean_fn_decl_with_args(cx, decl, args); (generics, decl) }); - ForeignFunctionItem(Function { - decl, - generics, - header: hir::FnHeader { - unsafety: if abi == Abi::RustIntrinsic { - intrinsic_operation_unsafety(item.ident.name) - } else { - hir::Unsafety::Unsafe - }, - abi, - constness: hir::Constness::NotConst, - asyncness: hir::IsAsync::NotAsync, - }, - }) + ForeignFunctionItem(Function { decl, generics }) } hir::ForeignItemKind::Static(ref ty, mutability) => { ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None }) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 47289eb8978b9..957faec30e1fc 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -13,6 +13,7 @@ use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; +use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; @@ -29,6 +30,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, FileName, Loc}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; +use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety; use crate::clean::cfg::Cfg; use crate::clean::external_path; @@ -641,6 +643,48 @@ impl Item { _ => false, } } + + /// Returns a `FnHeader` if `self` is a function item, otherwise returns `None`. + crate fn fn_header(&self, tcx: TyCtxt<'_>) -> Option { + fn build_fn_header( + def_id: DefId, + tcx: TyCtxt<'_>, + asyncness: hir::IsAsync, + ) -> hir::FnHeader { + let sig = tcx.fn_sig(def_id); + let constness = + if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; + hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness } + } + let header = match *self.kind { + ItemKind::ForeignFunctionItem(_) => { + let abi = tcx.fn_sig(self.def_id.as_def_id().unwrap()).abi(); + hir::FnHeader { + unsafety: if abi == Abi::RustIntrinsic { + intrinsic_operation_unsafety(self.name.unwrap()) + } else { + hir::Unsafety::Unsafe + }, + abi, + constness: hir::Constness::NotConst, + asyncness: hir::IsAsync::NotAsync, + } + } + ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) => { + let def_id = self.def_id.as_def_id().unwrap(); + build_fn_header(def_id, tcx, tcx.asyncness(def_id)) + } + ItemKind::TyMethodItem(_) => { + build_fn_header(self.def_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync) + } + _ => return None, + }; + Some(header) + } } #[derive(Clone, Debug)] @@ -1253,7 +1297,6 @@ crate struct Generics { crate struct Function { crate decl: FnDecl, crate generics: Generics, - crate header: hir::FnHeader, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3666767a9d9cb..93b33b0d60912 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,7 +48,6 @@ use std::string::ToString; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::Mutability; @@ -806,7 +805,6 @@ fn assoc_type( fn assoc_method( w: &mut Buffer, meth: &clean::Item, - header: hir::FnHeader, g: &clean::Generics, d: &clean::FnDecl, link: AssocItemLink<'_>, @@ -814,6 +812,7 @@ fn assoc_method( cx: &Context<'_>, render_mode: RenderMode, ) { + let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); let href = match link { AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)), @@ -972,10 +971,10 @@ fn render_assoc_item( match *item.kind { clean::StrippedItem(..) => {} clean::TyMethodItem(ref m) => { - assoc_method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode) + assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } clean::MethodItem(ref m, _) => { - assoc_method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode) + assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } clean::AssocConstItem(ref ty, _) => { assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e6c7745c6e10f..1fc1dc28fcb6a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -365,8 +365,9 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl } let unsafety_flag = match *myitem.kind { - clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) - if func.header.unsafety == hir::Unsafety::Unsafe => + clean::FunctionItem(_) | clean::ForeignFunctionItem(_) + if myitem.fn_header(cx.tcx()).unwrap().unsafety + == hir::Unsafety::Unsafe => { "" } @@ -453,16 +454,17 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> } fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { - let vis = it.visibility.print_with_space(it.def_id, cx).to_string(); - let constness = print_constness_with_space(&f.header.constness, it.const_stability(cx.tcx())); - let asyncness = f.header.asyncness.print_with_space(); - let unsafety = f.header.unsafety.print_with_space(); - let abi = print_abi_with_space(f.header.abi).to_string(); + let header = it.fn_header(cx.tcx()).expect("printing a function which isn't a function"); + let constness = print_constness_with_space(&header.constness, it.const_stability(cx.tcx())); + let unsafety = header.unsafety.print_with_space().to_string(); + let abi = print_abi_with_space(header.abi).to_string(); + let asyncness = header.asyncness.print_with_space(); + let visibility = it.visibility.print_with_space(it.def_id, cx).to_string(); let name = it.name.unwrap(); let generics_len = format!("{:#}", f.generics.print(cx)).len(); let header_len = "fn ".len() - + vis.len() + + visibility.len() + constness.len() + asyncness.len() + unsafety.len() @@ -478,7 +480,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", - vis = vis, + vis = visibility, constness = constness, asyncness = asyncness, unsafety = unsafety, @@ -486,7 +488,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: name = name, generics = f.generics.print(cx), where_clause = print_where_clause(&f.generics, cx, 0, true), - decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx), + decl = f.decl.full_print(header_len, 0, header.asyncness, cx), notable_traits = notable_traits_decl(&f.decl, cx), ); }); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7cf5d02f9f891..bc638200533fd 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -199,6 +199,8 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { use clean::ItemKind::*; let name = item.name; let is_crate = item.is_crate(); + let header = item.fn_header(tcx); + match *item.kind { ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items) }), ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)), @@ -207,12 +209,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)), EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)), VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)), - FunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)), - ForeignFunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)), + FunctionItem(f) => ItemEnum::Function(from_function(f, header.unwrap(), tcx)), + ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, header.unwrap(), tcx)), TraitItem(t) => ItemEnum::Trait(t.into_tcx(tcx)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), - MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, tcx)), - TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, tcx)), + MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)), + TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)), ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), @@ -300,17 +302,6 @@ fn convert_abi(a: RustcAbi) -> Abi { } } -impl FromWithTcx for Function { - fn from_tcx(function: clean::Function, tcx: TyCtxt<'_>) -> Self { - let clean::Function { decl, generics, header } = function; - Function { - decl: decl.into_tcx(tcx), - generics: generics.into_tcx(tcx), - header: from_fn_header(&header), - } - } -} - impl FromWithTcx for Generics { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { @@ -555,12 +546,26 @@ impl FromWithTcx for Impl { } } +crate fn from_function( + function: clean::Function, + header: rustc_hir::FnHeader, + tcx: TyCtxt<'_>, +) -> Function { + let clean::Function { decl, generics } = function; + Function { + decl: decl.into_tcx(tcx), + generics: generics.into_tcx(tcx), + header: from_fn_header(&header), + } +} + crate fn from_function_method( function: clean::Function, has_body: bool, + header: rustc_hir::FnHeader, tcx: TyCtxt<'_>, ) -> Method { - let clean::Function { header, decl, generics } = function; + let clean::Function { decl, generics } = function; Method { decl: decl.into_tcx(tcx), generics: generics.into_tcx(tcx), diff --git a/src/test/rustdoc/reexport-dep-foreign-fn.rs b/src/test/rustdoc/reexport-dep-foreign-fn.rs new file mode 100644 index 0000000000000..6e1dc453982d9 --- /dev/null +++ b/src/test/rustdoc/reexport-dep-foreign-fn.rs @@ -0,0 +1,12 @@ +// aux-build:all-item-types.rs + +// This test is to ensure there is no problem on handling foreign functions +// coming from a dependency. + +#![crate_name = "foo"] + +extern crate all_item_types; + +// @has 'foo/fn.foo_ffn.html' +// @has - '//*[@class="docblock item-decl"]//code' 'pub unsafe extern "C" fn foo_ffn()' +pub use all_item_types::foo_ffn;