diff options
| author | Yuki Okushi <jtitor@2k36.org> | 2021-05-12 07:17:59 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-12 07:17:59 +0900 |
| commit | 40be1d3152542470ec5955a1bd03de4e2c87053d (patch) | |
| tree | e849c74ba3b379ec0351dd98f25fd471a366105a | |
| parent | 5c029265465301fe9cb3960ce2a5da6c99b8dcf2 (diff) | |
| parent | d43701caa01003d9e0386fbd7a61d530e830564b (diff) | |
| download | rust-40be1d3152542470ec5955a1bd03de4e2c87053d.tar.gz rust-40be1d3152542470ec5955a1bd03de4e2c87053d.zip | |
Rollup merge of #83501 - camelid:rustdoc-layout, r=jyn514,GuillaumeGomez
rustdoc: Add unstable CLI option to show basic type layout information Closes #75988. Right now it just shows the size.
| -rw-r--r-- | src/bootstrap/doc.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/config.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/render/context.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/render/print_item.rs | 78 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 3 | ||||
| -rw-r--r-- | src/test/rustdoc/type-layout-flag-required.rs | 4 | ||||
| -rw-r--r-- | src/test/rustdoc/type-layout.rs | 54 |
7 files changed, 145 insertions, 4 deletions
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index a32b92ef1af..326a6fdaa80 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -549,6 +549,7 @@ impl Step for Rustc { cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("-Zunstable-options"); cargo.rustdocflag("-Znormalize-docs"); + cargo.rustdocflag("--show-type-layout"); compile::rustc_cargo(builder, &mut cargo, target); // Only include compiler crates, no dependencies of those, such as `libc`. @@ -648,6 +649,7 @@ impl Step for Rustdoc { cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); + cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 045b42d0dca..b75e98ae16c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -267,6 +267,8 @@ crate struct RenderOptions { crate document_hidden: bool, /// If `true`, generate a JSON file in the crate folder instead of HTML redirection files. crate generate_redirect_map: bool, + /// Show the memory layout of types in the docs. + crate show_type_layout: bool, crate unstable_features: rustc_feature::UnstableFeatures, crate emit: Vec<EmitType>, } @@ -636,6 +638,7 @@ impl Options { let document_hidden = matches.opt_present("document-hidden-items"); let run_check = matches.opt_present("check"); let generate_redirect_map = matches.opt_present("generate-redirect-map"); + let show_type_layout = matches.opt_present("show-type-layout"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -695,6 +698,7 @@ impl Options { document_private, document_hidden, generate_redirect_map, + show_type_layout, unstable_features: rustc_feature::UnstableFeatures::from_environment( crate_name.as_deref(), ), diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4e17dc8d3a7..666d9dfc3e9 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -91,6 +91,8 @@ crate struct SharedContext<'tcx> { crate include_sources: bool, /// The local file sources we've emitted and their respective url-paths. crate local_sources: FxHashMap<PathBuf, String>, + /// Show the memory layout of types in the docs. + pub(super) show_type_layout: bool, /// Whether the collapsed pass ran collapsed: bool, /// The base-URL of the issue tracker for when an item has been tagged with @@ -373,6 +375,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { generate_search_filter, unstable_features, generate_redirect_map, + show_type_layout, .. } = options; @@ -446,6 +449,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { all: RefCell::new(AllTypes::new()), errors: receiver, redirections: if generate_redirect_map { Some(Default::default()) } else { None }, + show_type_layout, }; // Add the default themes to the `Vec` of stylepaths diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 7ccc313cc59..f0ca24b8f02 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_middle::middle::stability; +use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -830,11 +831,12 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T document(w, cx, it, None); + let def_id = it.def_id.expect_real(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All) + render_assoc_items(w, cx, it, def_id, AssocItemRender::All); } fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) { @@ -846,6 +848,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni }); document(w, cx, it, None); + let mut fields = s .fields .iter() @@ -880,7 +883,9 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni document(w, cx, field, Some(it)); } } - render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All) + let def_id = it.def_id.expect_real(); + render_assoc_items(w, cx, it, def_id, AssocItemRender::All); + document_type_layout(w, cx, def_id); } fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) { @@ -940,6 +945,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum }); document(w, cx, it, None); + if !e.variants.is_empty() { write!( w, @@ -1014,7 +1020,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum render_stability_since(w, variant, it, cx.tcx()); } } - render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All) + let def_id = it.def_id.expect_real(); + render_assoc_items(w, cx, it, def_id, AssocItemRender::All); + document_type_layout(w, cx, def_id); } fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) { @@ -1114,6 +1122,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St }); document(w, cx, it, None); + let mut fields = s .fields .iter() @@ -1152,7 +1161,9 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St } } } - render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All) + let def_id = it.def_id.expect_real(); + render_assoc_items(w, cx, it, def_id, AssocItemRender::All); + document_type_layout(w, cx, def_id); } fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1522,3 +1533,62 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { w.write_str("</div></details>"); } } + +fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { + if !cx.shared.show_type_layout { + return; + } + + writeln!(w, "<h2 class=\"small-section-header\">Layout</h2>"); + writeln!(w, "<div class=\"docblock\">"); + + let tcx = cx.tcx(); + let param_env = tcx.param_env(ty_def_id); + let ty = tcx.type_of(ty_def_id); + match tcx.layout_of(param_env.and(ty)) { + Ok(ty_layout) => { + writeln!( + w, + "<div class=\"warning\"><p><strong>Note:</strong> Most layout information is \ + completely unstable and may be different between compiler versions and platforms. \ + The only exception is types with certain <code>repr(...)</code> attributes. \ + Please see the Rust Reference’s \ + <a href=\"https://doc.rust-lang.org/reference/type-layout.html\">“Type Layout”</a> \ + chapter for details on type layout guarantees.</p></div>" + ); + if ty_layout.layout.abi.is_unsized() { + writeln!(w, "<p><strong>Size:</strong> (unsized)</p>"); + } else { + let bytes = ty_layout.layout.size.bytes(); + writeln!( + w, + "<p><strong>Size:</strong> {size} byte{pl}</p>", + size = bytes, + pl = if bytes == 1 { "" } else { "s" }, + ); + } + } + // This kind of layout error can occur with valid code, e.g. if you try to + // get the layout of a generic type such as `Vec<T>`. + Err(LayoutError::Unknown(_)) => { + writeln!( + w, + "<p><strong>Note:</strong> Unable to compute type layout, \ + possibly due to this type having generic parameters. \ + Layout can only be computed for concrete, fully-instantiated types.</p>" + ); + } + // This kind of error probably can't happen with valid code, but we don't + // want to panic and prevent the docs from building, so we just let the + // user know that we couldn't compute the layout. + Err(LayoutError::SizeOverflow(_)) => { + writeln!( + w, + "<p><strong>Note:</strong> Encountered an error during type layout; \ + the type was too big.</p>" + ); + } + } + + writeln!(w, "</div>"); +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 169ef015fa8..5ede3780e87 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -594,6 +594,9 @@ fn opts() -> Vec<RustcOptGroup> { ) }), unstable("no-run", |o| o.optflag("", "no-run", "Compile doctests without running them")), + unstable("show-type-layout", |o| { + o.optflag("", "show-type-layout", "Include the memory layout of types in the docs") + }), ] } diff --git a/src/test/rustdoc/type-layout-flag-required.rs b/src/test/rustdoc/type-layout-flag-required.rs new file mode 100644 index 00000000000..a01fbd22950 --- /dev/null +++ b/src/test/rustdoc/type-layout-flag-required.rs @@ -0,0 +1,4 @@ +// Tests that `--show-type-layout` is required in order to show layout info. + +// @!has type_layout_flag_required/struct.Foo.html 'Size: ' +pub struct Foo(usize); diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs new file mode 100644 index 00000000000..272911de681 --- /dev/null +++ b/src/test/rustdoc/type-layout.rs @@ -0,0 +1,54 @@ +// compile-flags: --show-type-layout -Z unstable-options + +// @has type_layout/struct.Foo.html 'Size: ' +// @has - ' bytes' +pub struct Foo { + pub a: usize, + b: Vec<String>, +} + +// @has type_layout/enum.Bar.html 'Size: ' +// @has - ' bytes' +pub enum Bar<'a> { + A(String), + B(&'a str, (std::collections::HashMap<String, usize>, Foo)), +} + +// @has type_layout/union.Baz.html 'Size: ' +// @has - ' bytes' +pub union Baz { + a: &'static str, + b: usize, + c: &'static [u8], +} + +// @has type_layout/struct.X.html 'Size: ' +// @has - ' bytes' +pub struct X(usize); + +// @has type_layout/struct.Y.html 'Size: ' +// @has - '1 byte' +// @!has - ' bytes' +pub struct Y(u8); + +// @has type_layout/struct.Z.html 'Size: ' +// @has - '0 bytes' +pub struct Z; + +// We can't compute layout for generic types. +// @has type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters' +// @!has - 'Size: ' +pub struct Generic<T>(T); + +// We *can*, however, compute layout for types that are only generic over lifetimes, +// because lifetimes are a type-system construct. +// @has type_layout/struct.GenericLifetimes.html 'Size: ' +// @has - ' bytes' +pub struct GenericLifetimes<'a>(&'a str); + +// @has type_layout/struct.Unsized.html 'Size: ' +// @has - '(unsized)' +pub struct Unsized([u8]); + +// @!has type_layout/trait.MyTrait.html 'Size: ' +pub trait MyTrait {} |
