@@ -5,13 +5,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
55use rustc_hir as hir;
66use rustc_hir:: def:: CtorKind ;
77use rustc_hir:: def_id:: DefId ;
8+ use rustc_index:: vec:: IndexVec ;
89use rustc_middle:: middle:: stability;
910use rustc_middle:: span_bug;
10- use rustc_middle:: ty:: layout:: LayoutError ;
11+ use rustc_middle:: ty:: layout:: { LayoutError , TyAndLayout } ;
1112use rustc_middle:: ty:: { self , Adt , TyCtxt } ;
1213use rustc_span:: hygiene:: MacroKind ;
1314use rustc_span:: symbol:: { kw, sym, Symbol } ;
14- use rustc_target:: abi:: { LayoutS , Primitive , TagEncoding , Variants } ;
15+ use rustc_target:: abi:: { LayoutS , Primitive , TagEncoding , VariantIdx , Variants } ;
16+ use std:: borrow:: Borrow ;
1517use std:: cmp:: Ordering ;
1618use std:: fmt;
1719use std:: rc:: Rc ;
@@ -1936,111 +1938,77 @@ fn document_type_layout<'a, 'cx: 'a>(
19361938 cx : & ' a Context < ' cx > ,
19371939 ty_def_id : DefId ,
19381940) -> impl fmt:: Display + ' a + Captures < ' cx > {
1939- fn write_size_of_layout ( mut w : impl fmt:: Write , layout : & LayoutS , tag_size : u64 ) {
1940- if layout. abi . is_unsized ( ) {
1941- write ! ( w, "(unsized)" ) . unwrap ( ) ;
1942- } else {
1943- let size = layout. size . bytes ( ) - tag_size;
1944- write ! ( w, "{size} byte{pl}" , pl = if size == 1 { "" } else { "s" } ) . unwrap ( ) ;
1945- if layout. abi . is_uninhabited ( ) {
1946- write ! (
1947- w,
1948- " (<a href=\" https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\" >uninhabited</a>)"
1949- ) . unwrap ( ) ;
1950- }
1951- }
1941+ #[ derive( Template ) ]
1942+ #[ template( path = "type_layout.html" ) ]
1943+ struct TypeLayout < ' a , ' cx > {
1944+ cx : & ' a Context < ' cx > ,
1945+ ty_def_id : DefId ,
19521946 }
19531947
1954- display_fn ( move |mut f| {
1955- if !cx. shared . show_type_layout {
1956- return Ok ( ( ) ) ;
1948+ impl < ' a , ' cx : ' a > TypeLayout < ' a , ' cx > {
1949+ fn variants < ' b : ' a > ( & ' b self ) -> Option < & ' b IndexVec < VariantIdx , LayoutS > > {
1950+ if let Variants :: Multiple { variants, .. } =
1951+ self . type_layout ( ) . unwrap ( ) . layout . variants ( ) && !variants. is_empty ( ) {
1952+ Some ( & variants)
1953+ } else {
1954+ None
1955+ }
19571956 }
1958-
1959- writeln ! (
1960- f,
1961- "<h2 id=\" layout\" class=\" small-section-header\" > \
1962- Layout<a href=\" #layout\" class=\" anchor\" >§</a></h2>"
1963- ) ?;
1964- writeln ! ( f, "<div class=\" docblock\" >" ) ?;
1965-
1966- let tcx = cx. tcx ( ) ;
1967- let param_env = tcx. param_env ( ty_def_id) ;
1968- let ty = tcx. type_of ( ty_def_id) . subst_identity ( ) ;
1969- match tcx. layout_of ( param_env. and ( ty) ) {
1970- Ok ( ty_layout) => {
1971- writeln ! (
1972- f,
1973- "<div class=\" warning\" ><p><strong>Note:</strong> Most layout information is \
1974- <strong>completely unstable</strong> and may even differ between compilations. \
1975- The only exception is types with certain <code>repr(...)</code> attributes. \
1976- Please see the Rust Reference’s \
1977- <a href=\" https://doc.rust-lang.org/reference/type-layout.html\" >“Type Layout”</a> \
1978- chapter for details on type layout guarantees.</p></div>"
1979- ) ?;
1980- f. write_str ( "<p><strong>Size:</strong> " ) ?;
1981- write_size_of_layout ( & mut f, & ty_layout. layout . 0 , 0 ) ;
1982- writeln ! ( f, "</p>" ) ?;
1983- if let Variants :: Multiple { variants, tag, tag_encoding, .. } =
1984- & ty_layout. layout . variants ( )
1985- {
1986- if !variants. is_empty ( ) {
1987- f. write_str (
1988- "<p><strong>Size for each variant:</strong></p>\
1989- <ul>",
1957+ fn type_layout < ' b : ' a > ( & ' b self ) -> Result < TyAndLayout < ' cx > , LayoutError < ' cx > > {
1958+ let tcx = self . cx . tcx ( ) ;
1959+ let param_env = tcx. param_env ( self . ty_def_id ) ;
1960+ let ty = tcx. type_of ( self . ty_def_id ) . subst_identity ( ) ;
1961+ tcx. layout_of ( param_env. and ( ty) )
1962+ }
1963+ fn variant_name < ' b : ' a > ( & ' b self , index : VariantIdx ) -> Symbol {
1964+ let Adt ( adt, _) = self . type_layout ( ) . unwrap ( ) . ty . kind ( ) else {
1965+ span_bug ! ( self . cx. tcx( ) . def_span( self . ty_def_id) , "not an adt" )
1966+ } ;
1967+ adt. variant ( index) . name
1968+ }
1969+ fn tag_size < ' b : ' a > ( & ' b self ) -> u64 {
1970+ if let Variants :: Multiple { variants, tag, tag_encoding, .. } =
1971+ self . type_layout ( ) . unwrap ( ) . layout . variants ( ) && !variants. is_empty ( ) {
1972+ if let TagEncoding :: Niche { .. } = tag_encoding {
1973+ 0
1974+ } else if let Primitive :: Int ( i, _) = tag. primitive ( ) {
1975+ i. size ( ) . bytes ( )
1976+ } else {
1977+ span_bug ! ( self . cx. tcx( ) . def_span( self . ty_def_id) , "tag is neither niche nor int" )
1978+ }
1979+ } else {
1980+ 0
1981+ }
1982+ }
1983+ fn write_size < ' b : ' a > (
1984+ & ' b self ,
1985+ layout : & ' b LayoutS ,
1986+ tag_size : u64 ,
1987+ ) -> impl fmt:: Display + Captures < ' cx > + Captures < ' b > {
1988+ display_fn ( move |f| {
1989+ if layout. abi . is_unsized ( ) {
1990+ write ! ( f, "(unsized)" ) ?;
1991+ } else {
1992+ let size = layout. size . bytes ( ) - tag_size;
1993+ write ! ( f, "{size} byte{pl}" , pl = if size == 1 { "" } else { "s" } ) ?;
1994+ if layout. abi . is_uninhabited ( ) {
1995+ write ! (
1996+ f,
1997+ " (<a href=\" https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\" >uninhabited</a>)"
19901998 ) ?;
1991-
1992- let Adt ( adt, _) = ty_layout. ty . kind ( ) else {
1993- span_bug ! ( tcx. def_span( ty_def_id) , "not an adt" )
1994- } ;
1995-
1996- let tag_size = if let TagEncoding :: Niche { .. } = tag_encoding {
1997- 0
1998- } else if let Primitive :: Int ( i, _) = tag. primitive ( ) {
1999- i. size ( ) . bytes ( )
2000- } else {
2001- span_bug ! ( tcx. def_span( ty_def_id) , "tag is neither niche nor int" )
2002- } ;
2003-
2004- for ( index, layout) in variants. iter_enumerated ( ) {
2005- let name = adt. variant ( index) . name ;
2006- write ! ( & mut f, "<li><code>{name}</code>: " ) ?;
2007- write_size_of_layout ( & mut f, layout, tag_size) ;
2008- writeln ! ( & mut f, "</li>" ) ?;
2009- }
2010- f. write_str ( "</ul>" ) ?;
20111999 }
20122000 }
2013- }
2014- // This kind of layout error can occur with valid code, e.g. if you try to
2015- // get the layout of a generic type such as `Vec<T>`.
2016- Err ( LayoutError :: Unknown ( _) ) => {
2017- writeln ! (
2018- f,
2019- "<p><strong>Note:</strong> Unable to compute type layout, \
2020- possibly due to this type having generic parameters. \
2021- Layout can only be computed for concrete, fully-instantiated types.</p>"
2022- ) ?;
2023- }
2024- // This kind of error probably can't happen with valid code, but we don't
2025- // want to panic and prevent the docs from building, so we just let the
2026- // user know that we couldn't compute the layout.
2027- Err ( LayoutError :: SizeOverflow ( _) ) => {
2028- writeln ! (
2029- f,
2030- "<p><strong>Note:</strong> Encountered an error during type layout; \
2031- the type was too big.</p>"
2032- ) ?;
2033- }
2034- Err ( LayoutError :: NormalizationFailure ( _, _) ) => {
2035- writeln ! (
2036- f,
2037- "<p><strong>Note:</strong> Encountered an error during type layout; \
2038- the type failed to be normalized.</p>"
2039- ) ?;
2040- }
2001+ Ok ( ( ) )
2002+ } )
2003+ }
2004+ }
2005+
2006+ display_fn ( move |f| {
2007+ if !cx. shared . show_type_layout {
2008+ return Ok ( ( ) ) ;
20412009 }
20422010
2043- writeln ! ( f , "</div>" )
2011+ Ok ( TypeLayout { cx , ty_def_id } . render_into ( f ) . unwrap ( ) )
20442012 } )
20452013}
20462014
0 commit comments