From b6ad420a20ab7e024298c62de2336dfea23098e2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jan 2025 17:20:35 +0100 Subject: [PATCH 1/9] Replace ul/li list with dl/dd/dt elements --- src/librustdoc/html/render/print_item.rs | 30 ++++++++------------ src/librustdoc/html/static/css/rustdoc.css | 32 ++++++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 1376bdb2e90f4..62b1917dfa402 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -140,10 +140,8 @@ macro_rules! item_template_methods { }; } -const ITEM_TABLE_OPEN: &str = ""; -const ITEM_TABLE_ROW_OPEN: &str = "
  • "; -const ITEM_TABLE_ROW_CLOSE: &str = "
  • "; +const ITEM_TABLE_OPEN: &str = "
    "; +const ITEM_TABLE_CLOSE: &str = "
    "; // A component in a `use` path, like `string` in std::string::ToString struct PathComponent { @@ -413,24 +411,22 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; - w.write_str(ITEM_TABLE_ROW_OPEN); match *src { Some(src) => write!( w, - "
    {}extern crate {} as {};", + "
    {}extern crate {} as {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), ), None => write!( w, - "
    {}extern crate {};", + "
    {}extern crate {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx), ), } - w.write_str("
    "); - w.write_str(ITEM_TABLE_ROW_CLOSE); + w.write_str(""); } clean::ImportItem(ref import) => { @@ -438,7 +434,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() }); - w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { clean::ImportKind::Simple(s) => { format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) @@ -448,18 +443,17 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { ("", "") } else { - ("
    ", "
    ") + ("
    ", "
    ") }; write!( w, - "
    \ + "
    \ {vis}{imp}\ -
    \ + \ {stab_tags_before}{stab_tags}{stab_tags_after}", vis = visibility_print_with_space(myitem, cx), imp = import.print(cx), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } _ => { @@ -492,22 +486,21 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl _ => "", }; - w.write_str(ITEM_TABLE_ROW_OPEN); let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); let (docs_before, docs_after) = if docs.is_empty() { ("", "") } else { - ("
    ", "
    ") + ("
    ", "
    ") }; write!( w, - "
    \ + "
    \ {name}\ {visibility_and_hidden}\ {unsafety_flag}\ {stab_tags}\ -
    \ + \ {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, @@ -521,7 +514,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl .collect::>() .join(" "), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a1ab258ff304a..5c41832d440f2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1102,20 +1102,17 @@ table, } .item-table { - display: table; padding: 0; margin: 0; width: 100%; } -.item-table > li { - display: table-row; -} -.item-table > li > div { - display: table-cell; -} -.item-table > li > .item-name { +.item-table > .item-name { padding-right: 1.25rem; } +.item-table > dd { + margin-inline-start: 0; + margin-left: 0; +} .search-results-title { margin-top: 0; @@ -2476,8 +2473,7 @@ in src-script.js and main.js } /* Display an alternating layout on tablets and phones */ - .item-table, .item-row, .item-table > li, .item-table > li > div, - .search-results > a, .search-results > a > div { + .item-row, .search-results > a, .search-results > a > div { display: block; } @@ -2485,7 +2481,7 @@ in src-script.js and main.js .search-results > a { padding: 5px 0px; } - .search-results > a > div.desc, .item-table > li > div.desc { + .search-results > a > div.desc, .item-table dd.desc { padding-left: 2em; } .search-results .result-name { @@ -2546,12 +2542,20 @@ in src-script.js and main.js box-shadow: 0 0 4px var(--main-background-color); } - .item-table > li > .item-name { - width: 33%; + /* Since the screen is wide enough, we show items on their description on the same line. */ + .item-table { + display: grid; + grid-template-columns: 33% 67%; } - .item-table > li > div { + .item-table > dt, .item-table > dd { overflow-wrap: anywhere; } + .item-table > dt { + grid-column-start: 1; + } + .item-table > dd { + grid-column-start: 2; + } } @media print { From 42f9c797768f63643fb1ddd29a7fdc33486f69de Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jan 2025 18:35:56 +0100 Subject: [PATCH 2/9] Handle reexports items list a bit differently since they cannot have documentation --- src/librustdoc/html/render/print_item.rs | 12 +++++------- src/librustdoc/html/static/css/rustdoc.css | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 62b1917dfa402..e7700d853443c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -141,6 +141,7 @@ macro_rules! item_template_methods { } const ITEM_TABLE_OPEN: &str = "
    "; +const REEXPORTS_TABLE_OPEN: &str = "
    "; const ITEM_TABLE_CLOSE: &str = "
    "; // A component in a `use` path, like `string` in std::string::ToString @@ -398,13 +399,10 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str(ITEM_TABLE_CLOSE); } last_section = Some(my_section); - write_section_heading( - w, - my_section.name(), - &cx.derive_id(my_section.id()), - None, - ITEM_TABLE_OPEN, - ); + let section_id = my_section.id(); + let tag = + if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN }; + write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag); } match myitem.kind { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 5c41832d440f2..f47df5bbcea90 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2543,7 +2543,7 @@ in src-script.js and main.js } /* Since the screen is wide enough, we show items on their description on the same line. */ - .item-table { + .item-table:not(.reexports) { display: grid; grid-template-columns: 33% 67%; } From 3c62ccdff5cf4dc27be4faff91a5874032ae861a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jan 2025 18:36:11 +0100 Subject: [PATCH 3/9] Update rustdoc tests --- .../huge-collection-of-constants.goml | 4 ++-- tests/rustdoc-gui/item-name-wrap.goml | 6 +++--- tests/rustdoc/anonymous-reexport-108931.rs | 4 ++-- tests/rustdoc/anonymous-reexport.rs | 2 +- .../glob-reexport-attribute-merge-120487.rs | 4 ++-- ...ob-reexport-attribute-merge-doc-auto-cfg.rs | 4 ++-- tests/rustdoc/glob-shadowing-const.rs | 4 ++-- tests/rustdoc/glob-shadowing.rs | 18 +++++++++--------- .../module-scope-name-resolution-55364.rs | 8 ++++---- .../item-desc-list-at-start.item-table.html | 2 +- tests/rustdoc/item-desc-list-at-start.rs | 7 ++++--- .../macro-rules-broken-intra-doc-106142.rs | 17 ----------------- tests/rustdoc/reexport-cfg.rs | 6 ++++-- tests/rustdoc/reexport-check.rs | 4 ++-- .../reexport-doc-hidden-inside-private.rs | 2 +- tests/rustdoc/stability.rs | 6 +++--- 16 files changed, 42 insertions(+), 56 deletions(-) delete mode 100644 tests/rustdoc/macro-rules-broken-intra-doc-106142.rs diff --git a/tests/rustdoc-gui/huge-collection-of-constants.goml b/tests/rustdoc-gui/huge-collection-of-constants.goml index 387aca6f66cc4..643f0f51ac177 100644 --- a/tests/rustdoc-gui/huge-collection-of-constants.goml +++ b/tests/rustdoc-gui/huge-collection-of-constants.goml @@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/huge_amount_of_consts/index.html" compare-elements-position-near-false: ( - "//ul[@class='item-table']/li[last()-1]", - "//ul[@class='item-table']/li[last()-3]", + "//dl[@class='item-table']/dt[last()-1]", + "//dl[@class='item-table']/dt[last()-3]", {"y": 12}, ) diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml index 825c16ac5b8ce..39f48687d9a28 100644 --- a/tests/rustdoc-gui/item-name-wrap.goml +++ b/tests/rustdoc-gui/item-name-wrap.goml @@ -3,9 +3,9 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/short_docs/index.html" set-window-size: (1000, 600) // First we ensure that there is only one `item-table`... -assert-count: ("ul.item-table", 1) +assert-count: ("dl.item-table", 1) // And only two items in it. -assert-count: ("ul.item-table li", 2) +assert-count: ("dl.item-table dt", 2) // If they don't have the same height, then it means one of the two is on two lines whereas it // shouldn't! @@ -18,6 +18,6 @@ compare-elements-size: ( // We also check that the `item-table` is taking the full width. compare-elements-size: ( "#functions", - "ul.item-table", + "dl.item-table", ["width"], ) diff --git a/tests/rustdoc/anonymous-reexport-108931.rs b/tests/rustdoc/anonymous-reexport-108931.rs index f4cc7f1239628..b995c89b61407 100644 --- a/tests/rustdoc/anonymous-reexport-108931.rs +++ b/tests/rustdoc/anonymous-reexport-108931.rs @@ -16,7 +16,7 @@ mod bar { //@ count - '//*[@id="main-content"]/h2' 2 //@ has - '//*[@id="main-content"]/h2' 'Re-exports' //@ has - '//*[@id="main-content"]/h2' 'Modules' -//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use foo::Foo as _;' -//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use bar::Bar as _;' +//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use foo::Foo as _;' +//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use bar::Bar as _;' pub use foo::Foo as _; pub use bar::Bar as _; diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport.rs index 8021008dc6684..360a0a0cc6965 100644 --- a/tests/rustdoc/anonymous-reexport.rs +++ b/tests/rustdoc/anonymous-reexport.rs @@ -9,7 +9,7 @@ //@ has - '//*[@id="main-content"]/h2' 'Structs' //@ has - '//*[@id="main-content"]/h2' 'Re-exports' // The 3 re-exports. -//@ count - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 3 +//@ count - '//*[@id="main-content"]//*[@class="item-table"]/dt//code' 3 // The public struct. //@ count - '//*[@id="main-content"]//a[@class="struct"]' 1 diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs index 2fa10f546d577..30cb75f0e898d 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs @@ -7,9 +7,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt[@class="item-name"]' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt[@class="item-name"]/*[@class="stab portability"]' 1 mod a { #[doc(cfg(not(feature = "a")))] diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs index 314b457c2ad7f..3d49d3fd05da3 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs @@ -6,9 +6,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt[@class="item-name"]' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt[@class="item-name"]/*[@class="stab portability"]' 1 mod a { #[cfg(not(feature = "a"))] diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/glob-shadowing-const.rs index 1eb5596cd9ccf..8d8d54ffe32f0 100644 --- a/tests/rustdoc/glob-shadowing-const.rs +++ b/tests/rustdoc/glob-shadowing-const.rs @@ -15,6 +15,6 @@ mod sub4 { pub use sub4::inner::*; //@ has 'foo/index.html' -//@ has - '//div[@class="desc docblock-short"]' '1' -//@ !has - '//div[@class="desc docblock-short"]' '0' +//@ has - '//dd[@class="desc docblock-short"]' '1' +//@ !has - '//dd[@class="desc docblock-short"]' '0' fn main() { assert_eq!(X, 1); } diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc/glob-shadowing.rs index a051bd407d5b1..d150afcb1cc69 100644 --- a/tests/rustdoc/glob-shadowing.rs +++ b/tests/rustdoc/glob-shadowing.rs @@ -1,17 +1,17 @@ //@ has 'glob_shadowing/index.html' -//@ count - '//div[@class="item-name"]' 6 -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe' -//@ has - '//div[@class="desc docblock-short"]' 'sub2::describe' +//@ count - '//dt[@class="item-name"]' 6 +//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::describe' +//@ has - '//dd[@class="desc docblock-short"]' 'sub2::describe' -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe2' +//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::describe2' -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::prelude' -//@ has - '//div[@class="desc docblock-short"]' 'mod::prelude' +//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::prelude' +//@ has - '//dd[@class="desc docblock-short"]' 'mod::prelude' -//@ has - '//div[@class="desc docblock-short"]' 'sub1::Foo (struct)' -//@ has - '//div[@class="desc docblock-short"]' 'mod::Foo (function)' +//@ has - '//dd[@class="desc docblock-short"]' 'sub1::Foo (struct)' +//@ has - '//dd[@class="desc docblock-short"]' 'mod::Foo (function)' -//@ has - '//div[@class="desc docblock-short"]' 'sub4::inner::X' +//@ has - '//dd[@class="desc docblock-short"]' 'sub4::inner::X' //@ has 'glob_shadowing/fn.describe.html' //@ has - '//div[@class="docblock"]' 'sub2::describe' diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs index 06cb764423e14..44c820bfdd25b 100644 --- a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs +++ b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs @@ -32,8 +32,8 @@ pub mod subone { //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' // Though there should be such links later -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt[@class="item-name"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt[@class="item-name"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' /// See either [foo] or [bar]. pub mod subtwo { @@ -71,8 +71,8 @@ pub mod subthree { // Next we go *deeper* - In order to ensure it's not just "this or parent" // we test `crate::` and a `super::super::...` chain //@ has foo/subfour/subfive/subsix/subseven/subeight/index.html -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd[@class="desc docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd[@class="desc docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' pub mod subfour { pub mod subfive { pub mod subsix { diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html index cff4f816529c3..b6de929bc3bc2 100644 --- a/tests/rustdoc/item-desc-list-at-start.item-table.html +++ b/tests/rustdoc/item-desc-list-at-start.item-table.html @@ -1 +1 @@ - \ No newline at end of file +
    MY_CONSTANT
    Groups: SamplePatternSGIS, SamplePatternEXT
    \ No newline at end of file diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc/item-desc-list-at-start.rs index fbcc36066f154..7c2b31c9460a3 100644 --- a/tests/rustdoc/item-desc-list-at-start.rs +++ b/tests/rustdoc/item-desc-list-at-start.rs @@ -1,7 +1,8 @@ //@ has item_desc_list_at_start/index.html -//@ count - '//ul[@class="item-table"]/li/div/li' 0 -//@ count - '//ul[@class="item-table"]/li' 1 -//@ snapshot item-table - '//ul[@class="item-table"]' +//@ count - '//dl[@class="item-table"]/dd//ul' 0 +//@ count - '//dl[@class="item-table"]/dd//li' 0 +//@ count - '//dl[@class="item-table"]/dd' 1 +//@ snapshot item-table - '//dl[@class="item-table"]' // based on https://docs.rs/gl_constants/0.1.1/src/gl_constants/lib.rs.html#16 diff --git a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs deleted file mode 100644 index 0d146a3c5cd0c..0000000000000 --- a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs +++ /dev/null @@ -1,17 +0,0 @@ -// https://github.com/rust-lang/rust/issues/106142 -#![crate_name="foo"] - -//@ has 'foo/a/index.html' -//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1 - -#![allow(rustdoc::broken_intra_doc_links)] - -pub mod a { - /// [`m`] - pub fn f() {} - - #[macro_export] - macro_rules! m { - () => {}; - } -} diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport-cfg.rs index 7270da3d678f8..fec5abc8290c7 100644 --- a/tests/rustdoc/reexport-cfg.rs +++ b/tests/rustdoc/reexport-cfg.rs @@ -21,10 +21,12 @@ pub use crate::foo::Bar as Babar; #[doc(cfg(not(feature = "cake")))] pub use crate::foo::Bar2 as Babar2; -//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar as Elephant;Non-robot' +//@ has - '//*[@class="item-table"]/dt' 'pub use crate::Babar as Elephant;' +//@ has - '//*[@class="item-table"]/dd' 'Non-robot' #[cfg(not(feature = "robot"))] pub use crate::Babar as Elephant; -//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar2 as Elephant2;Non-cat' +//@ has - '//*[@class="item-table"]/dt' 'pub use crate::Babar2 as Elephant2;' +//@ has - '//*[@class="item-table"]/dd' 'Non-cat' #[doc(cfg(not(feature = "cat")))] pub use crate::Babar2 as Elephant2; diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport-check.rs index 0f4e203d1d3b7..aacf4d1130f63 100644 --- a/tests/rustdoc/reexport-check.rs +++ b/tests/rustdoc/reexport-check.rs @@ -8,13 +8,13 @@ extern crate reexport_check; #[allow(deprecated, deprecated_in_future)] pub use std::i32; //@ !has 'foo/index.html' '//code' 'pub use self::string::String;' -//@ has 'foo/index.html' '//div[@class="item-name"]' 'String' +//@ has 'foo/index.html' '//dt[@class="item-name"]' 'String' pub use std::string::String; // i32 is deprecated, String is not //@ count 'foo/index.html' '//span[@class="stab deprecated"]' 1 -//@ has 'foo/index.html' '//div[@class="desc docblock-short"]' 'Docs in original' +//@ has 'foo/index.html' '//dd[@class="desc docblock-short"]' 'Docs in original' // this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment #[doc(inline)] pub use reexport_check::S; diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs index fac928fc2a391..e13f300d38cc7 100644 --- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -12,5 +12,5 @@ mod private_module { //@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' pub use crate::private_module::Public as Foo; // Glob re-exports with no visible items should not be displayed. -//@ count - '//*[@class="item-table"]/li' 1 +//@ count - '//*[@class="item-table"]/dt' 1 pub use crate::private_module::*; diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index 550eb0bc13776..b74abb0e0ba4c 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -5,9 +5,9 @@ #![stable(feature = "core", since = "1.6.0")] //@ has stability/index.html -//@ has - '//ul[@class="item-table"]/li[1]//a' AaStable -//@ has - '//ul[@class="item-table"]/li[2]//a' ZzStable -//@ has - '//ul[@class="item-table"]/li[3]//a' Unstable +//@ has - '//dl[@class="item-table"]/dt[1]//a' AaStable +//@ has - '//dl[@class="item-table"]/dt[2]//a' ZzStable +//@ has - '//dl[@class="item-table"]/dt[3]//a' Unstable #[stable(feature = "rust2", since = "2.2.2")] pub struct AaStable; From b3865d1832ff1e08e159f327b3b26d73f079f7b3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jan 2025 21:41:51 +0100 Subject: [PATCH 4/9] Remove more CSS classes --- src/librustdoc/html/render/print_item.rs | 25 +++++-------- src/librustdoc/html/static/css/rustdoc.css | 22 ++++++------ tests/rustdoc-gui/item-name-wrap.goml | 4 +-- tests/rustdoc-gui/item-summary-table.goml | 4 +-- tests/rustdoc-gui/label-next-to-symbol.goml | 36 +++++++++---------- tests/rustdoc-gui/links-color.goml | 4 +-- tests/rustdoc-gui/module-items-font.goml | 28 +++++++-------- tests/rustdoc-gui/sidebar.goml | 10 +++--- tests/rustdoc-gui/unsafe-fn.goml | 2 +- tests/rustdoc/anonymous-reexport.rs | 2 +- tests/rustdoc/attributes-inlining-108281.rs | 6 ++-- tests/rustdoc/cfg_doc_reexport.rs | 4 +-- tests/rustdoc/deprecated.rs | 7 ++-- tests/rustdoc/display-hidden-items.rs | 16 ++++----- tests/rustdoc/doc-cfg.rs | 6 ++-- tests/rustdoc/doc-hidden-reexports-109449.rs | 6 ++-- tests/rustdoc/double-hyphen-to-dash.rs | 2 +- tests/rustdoc/duplicate-cfg.rs | 4 +-- tests/rustdoc/footnote-in-summary.rs | 4 +-- .../glob-reexport-attribute-merge-120487.rs | 4 +-- ...b-reexport-attribute-merge-doc-auto-cfg.rs | 4 +-- tests/rustdoc/glob-shadowing-const.rs | 4 +-- tests/rustdoc/glob-shadowing.rs | 18 +++++----- .../rustdoc/impl-on-ty-alias-issue-119015.rs | 4 +-- ...ne-private-with-intermediate-doc-hidden.rs | 2 +- tests/rustdoc/inline_cross/inline_hidden.rs | 8 ++--- tests/rustdoc/inline_cross/macros.rs | 6 ++-- tests/rustdoc/internal.rs | 2 +- .../module-scope-name-resolution-55364.rs | 8 ++--- .../item-desc-list-at-start.item-table.html | 2 +- tests/rustdoc/nested-items-issue-111415.rs | 2 +- .../rustdoc/overlapping-reexport-105735-2.rs | 4 +-- tests/rustdoc/overlapping-reexport-105735.rs | 4 +-- tests/rustdoc/pub-use-root-path-95873.rs | 2 +- tests/rustdoc/reexport-cfg.rs | 10 +++--- tests/rustdoc/reexport-check.rs | 4 +-- .../reexport-doc-hidden-inside-private.rs | 2 +- tests/rustdoc/reexport-of-reexport-108679.rs | 3 +- .../reexport-trait-from-hidden-111064.rs | 2 +- tests/rustdoc/short-docblock.rs | 11 +++--- .../staged-api-deprecated-unstable-32374.rs | 8 ++--- tests/rustdoc/summary-header-46377.rs | 2 +- 42 files changed, 146 insertions(+), 162 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e7700d853443c..76a51cc64a88b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -412,14 +412,14 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl match *src { Some(src) => write!( w, - "
    {}extern crate {} as {};", + "
    {}extern crate {} as {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), ), None => write!( w, - "
    {}extern crate {};", + "
    {}extern crate {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx), ), @@ -438,17 +438,11 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl } clean::ImportKind::Glob => String::new(), }; - let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { - ("", "") - } else { - ("
    ", "
    ") - }; write!( w, - "
    \ - {vis}{imp}\ -
    \ - {stab_tags_before}{stab_tags}{stab_tags_after}", + "\ + {vis}{imp}{stab_tags}\ + ", vis = visibility_print_with_space(myitem, cx), imp = import.print(cx), ); @@ -486,14 +480,11 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); - let (docs_before, docs_after) = if docs.is_empty() { - ("", "") - } else { - ("
    ", "
    ") - }; + let (docs_before, docs_after) = + if docs.is_empty() { ("", "") } else { ("
    ", "
    ") }; write!( w, - "
    \ + "
    \ {name}\ {visibility_and_hidden}\ {unsafety_flag}\ diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f47df5bbcea90..4cb05b05be5da 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -242,7 +242,7 @@ h1, h2, h3, h4, h5, h6, .mobile-topbar, .search-input, .search-results .result-name, -.item-name > a, +.item-table dt > a, .out-of-band, .sub-heading, span.since, @@ -385,11 +385,11 @@ details:not(.toggle) summary { code, pre, .code-header, .type-signature { font-family: "Source Code Pro", monospace; } -.docblock code, .docblock-short code { +.docblock code, .item-table dd code { border-radius: 3px; padding: 0 0.125em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .item-table dd pre code { padding: 0; } pre { @@ -887,13 +887,13 @@ both the code example and the line numbers, so we need to remove the radius in t text-align: center; } -.docblock-short { +.item-table dd { overflow-wrap: break-word; overflow-wrap: anywhere; } /* Wrap non-pre code blocks (`text`) but not (```text```). */ .docblock :not(pre) > code, -.docblock-short code { +.item-table dd code { white-space: pre-wrap; } @@ -938,7 +938,7 @@ rustdoc-toolbar { min-height: 60px; } -.docblock code, .docblock-short code, +.docblock code, .item-table dd code, pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background-color: var(--code-block-background-color); border-radius: var(--code-block-border-radius); @@ -964,7 +964,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background: var(--table-alt-row-background-color); } -.docblock .stab, .docblock-short .stab, .docblock p code { +.docblock .stab, .item-table dd .stab, .docblock p code { display: inline-block; } @@ -1069,7 +1069,7 @@ because of the `[-]` element which would overlap with it. */ .example-wrap .rust a:hover, .all-items a:hover, .docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor), -.docblock-short a:not(.scrape-help):not(.tooltip):hover, +.item-table dd a:not(.scrape-help):not(.tooltip):hover, .item-info a { text-decoration: underline; } @@ -1106,7 +1106,7 @@ table, margin: 0; width: 100%; } -.item-table > .item-name { +.item-table > dt { padding-right: 1.25rem; } .item-table > dd { @@ -1412,7 +1412,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ padding: 3px; margin-bottom: 5px; } -.item-name .stab { +.item-table dt .stab { margin-left: 0.3125em; } .stab { @@ -2481,7 +2481,7 @@ in src-script.js and main.js .search-results > a { padding: 5px 0px; } - .search-results > a > div.desc, .item-table dd.desc { + .search-results > a > div.desc, .item-table dd { padding-left: 2em; } .search-results .result-name { diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml index 39f48687d9a28..d4da5c2d60978 100644 --- a/tests/rustdoc-gui/item-name-wrap.goml +++ b/tests/rustdoc-gui/item-name-wrap.goml @@ -10,8 +10,8 @@ assert-count: ("dl.item-table dt", 2) // If they don't have the same height, then it means one of the two is on two lines whereas it // shouldn't! compare-elements-size: ( - ".item-table .item-name a[href='fn.mult_vec_num.html']", - ".item-table .item-name a[href='fn.subt_vec_num.html']", + ".item-table dt a[href='fn.mult_vec_num.html']", + ".item-table dt a[href='fn.subt_vec_num.html']", ["height"], ) diff --git a/tests/rustdoc-gui/item-summary-table.goml b/tests/rustdoc-gui/item-summary-table.goml index 8930603032937..7c0dfce30625c 100644 --- a/tests/rustdoc-gui/item-summary-table.goml +++ b/tests/rustdoc-gui/item-summary-table.goml @@ -1,6 +1,6 @@ // This test ensures that elements aren't display in items summary. go-to: "file://" + |DOC_PATH| + "/lib2/summary_table/index.html" // We check that we picked the right item first. -assert-text: (".item-table .item-name", "Foo") +assert-text: (".item-table dt", "Foo") // Then we check that its summary is empty. -assert-false: ".item-table .desc" +assert-false: ".item-table dd" diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index a8363f29dd5de..7960dac11b6d5 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -12,59 +12,59 @@ assert: (".stab.portability") // make sure that deprecated and portability have the right colors assert-css: ( - ".item-table .item-name .stab.deprecated", + ".item-table dt .stab.deprecated", { "background-color": "#fff5d6" }, ) assert-css: ( - ".item-table .item-name .stab.portability", + ".item-table dt .stab.portability", { "background-color": "#fff5d6" }, ) // table like view -assert-css: (".desc.docblock-short", { "padding-left": "0px" }) +assert-css: ("dd", { "padding-left": "0px" }) compare-elements-position-near: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']", - ".item-name .stab.deprecated", + "//dt//a[normalize-space()='replaced_function']", + "dt .stab.deprecated", {"y": 2}, ) // "Unix" part is on second line compare-elements-position-false: ( - ".item-name .stab.deprecated", - ".item-name .stab.portability", + "dt .stab.deprecated", + "dt .stab.portability", ["y"], ) // Ensure no wrap compare-elements-position: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']/..", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "//dt//a[normalize-space()='replaced_function']/..", + "//dd[normalize-space()='a thing with a label']", ["y"], ) // Mobile view set-window-size: (600, 600) // staggered layout with 2em spacing -assert-css: (".desc.docblock-short", { "padding-left": "32px" }) +assert-css: ("dd", { "padding-left": "32px" }) compare-elements-position-near: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']", - ".item-name .stab.deprecated", + "//dt//a[normalize-space()='replaced_function']", + "dt .stab.deprecated", {"y": 2}, ) compare-elements-position: ( - ".item-name .stab.deprecated", - ".item-name .stab.portability", + "dt .stab.deprecated", + "dt .stab.portability", ["y"], ) // Ensure wrap compare-elements-position-false: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']/..", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "//dt//a[normalize-space()='replaced_function']/..", + "//dd[normalize-space()='a thing with a label']", ["y"], ) compare-elements-position-false: ( - ".item-name .stab.deprecated", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "dt .stab.deprecated", + "//dd[normalize-space()='a thing with a label']", ["y"], ) diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index 8d26b826479dc..f11920cdd8c2d 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -37,9 +37,9 @@ define-function: ( }, ALL, ) - move-cursor-to: ".desc a[href='long_code_block_link/index.html']" + move-cursor-to: "dd a[href='long_code_block_link/index.html']" assert-css: ( - ".desc a[href='long_code_block_link/index.html']", + "dd a[href='long_code_block_link/index.html']", {"text-decoration": "underline solid " + |mod|}, ) }, diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index 54c8131c3b908..0e6dd81c05b8d 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -1,67 +1,67 @@ // This test checks that the correct font is used on module items (in index.html pages). go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: ( - ".item-table .item-name > a", + ".item-table dt > a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL, ) assert-css: ( - ".item-table .docblock-short", + ".item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL, ) // modules assert-css: ( - "#modules + .item-table .item-name a", + "#modules + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#modules + .item-table .desc.docblock-short", + "#modules + .item-table ", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // structs assert-css: ( - "#structs + .item-table .item-name a", + "#structs + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#structs + .item-table .desc.docblock-short", + "#structs + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // enums assert-css: ( - "#enums + .item-table .item-name a", + "#enums + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#enums + .item-table .desc.docblock-short", + "#enums + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // traits assert-css: ( - "#traits + .item-table .item-name a", + "#traits + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#traits + .item-table .desc.docblock-short", + "#traits + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // functions assert-css: ( - "#functions + .item-table .item-name a", + "#functions + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#functions + .item-table .desc.docblock-short", + "#functions + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // keywords assert-css: ( - "#keywords + .item-table .item-name a", + "#keywords + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#keywords + .item-table .desc.docblock-short", + "#keywords + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index bb7453fdeacf1..38160cc49d085 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -65,8 +65,8 @@ assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Functions") assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Type Aliases") assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Unions") assert-text: (".sidebar-elems section ul > li:nth-child(11)", "Keywords") -assert-text: ("#structs + .item-table .item-name > a", "Foo") -click: "#structs + .item-table .item-name > a" +assert-text: ("#structs + .item-table dt > a", "Foo") +click: "#structs + .item-table dt > a" // PAGE: struct.Foo.html assert-count: (".sidebar .sidebar-crate", 1) @@ -101,8 +101,8 @@ assert-text: (".sidebar-elems > section ul.block > li:nth-child(2)", "Structs") assert-text: (".sidebar-elems > section ul.block > li:nth-child(3)", "Traits") assert-text: (".sidebar-elems > section ul.block > li:nth-child(4)", "Functions") assert-text: (".sidebar-elems > section ul.block > li:nth-child(5)", "Type Aliases") -assert-text: ("#functions + .item-table .item-name > a", "foobar") -click: "#functions + .item-table .item-name > a" +assert-text: ("#functions + .item-table dt > a", "foobar") +click: "#functions + .item-table dt > a" // PAGE: fn.foobar.html // In items containing no items (like functions or constants) and in modules, we have no @@ -145,7 +145,7 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module") // We check that we don't have the crate list. assert-false: ".sidebar-elems .crate" assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") -assert-text: ("#functions + .item-table .item-name > a", "foo") +assert-text: ("#functions + .item-table dt > a", "foo") // Links to trait implementations in the sidebar should not wrap even if they are long. go-to: "file://" + |DOC_PATH| + "/lib2/struct.HasALongTraitWithParams.html" diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml index b8b2e1e27f52d..b857afeff1339 100644 --- a/tests/rustdoc-gui/unsafe-fn.goml +++ b/tests/rustdoc-gui/unsafe-fn.goml @@ -17,7 +17,7 @@ define-function: ( [theme, color], block { call-function: ("switch-theme", {"theme": |theme|}) - assert-css: (".item-name sup", {"color": |color|}) + assert-css: ("dt sup", {"color": |color|}) }, ) diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport.rs index 360a0a0cc6965..bf5fa93f953a6 100644 --- a/tests/rustdoc/anonymous-reexport.rs +++ b/tests/rustdoc/anonymous-reexport.rs @@ -9,7 +9,7 @@ //@ has - '//*[@id="main-content"]/h2' 'Structs' //@ has - '//*[@id="main-content"]/h2' 'Re-exports' // The 3 re-exports. -//@ count - '//*[@id="main-content"]//*[@class="item-table"]/dt//code' 3 +//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 3 // The public struct. //@ count - '//*[@id="main-content"]//a[@class="struct"]' 1 diff --git a/tests/rustdoc/attributes-inlining-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs index ba6c570b59bc8..9dfaf1a6846f3 100644 --- a/tests/rustdoc/attributes-inlining-108281.rs +++ b/tests/rustdoc/attributes-inlining-108281.rs @@ -11,15 +11,15 @@ mod sub { pub fn public() {} } -//@ matches - '//*[@class="desc docblock-short"]' '^Displayed$' +//@ matches - '//dd' '^Displayed$' /// Displayed #[doc(inline)] pub use crate::bar as Bar; -//@ matches - '//*[@class="desc docblock-short"]' '^Hello\sDisplayed$' +//@ matches - '//dd' '^Hello\sDisplayed$' #[doc(inline)] /// Hello pub use crate::Bar as Bar2; -//@ matches - '//*[@class="desc docblock-short"]' '^Public$' +//@ matches - '//dd' '^Public$' /// Public pub use crate::sub::public as Public; diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/cfg_doc_reexport.rs index a07e4fe2f0291..f8101e2a95807 100644 --- a/tests/rustdoc/cfg_doc_reexport.rs +++ b/tests/rustdoc/cfg_doc_reexport.rs @@ -5,8 +5,8 @@ #![no_core] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'foobar' -//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'bar' +//@ has - '//dt/*[@class="stab portability"]' 'foobar' +//@ has - '//dt/*[@class="stab portability"]' 'bar' #[doc(cfg(feature = "foobar"))] mod imp_priv { diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs index b39da9b440ab7..a84657a3df5aa 100644 --- a/tests/rustdoc/deprecated.rs +++ b/tests/rustdoc/deprecated.rs @@ -1,6 +1,5 @@ -//@ has deprecated/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// 'Deprecated' -//@ has - '//*[@class="desc docblock-short"]' 'Deprecated docs' +//@ has deprecated/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated' +//@ has - '//dd' 'Deprecated docs' //@ has deprecated/struct.S.html '//*[@class="stab deprecated"]' \ // 'Deprecated since 1.0.0: text' @@ -8,7 +7,7 @@ #[deprecated(since = "1.0.0", note = "text")] pub struct S; -//@ matches deprecated/index.html '//*[@class="desc docblock-short"]' '^Docs' +//@ matches deprecated/index.html '//dd' '^Docs' /// Docs pub struct T; diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc/display-hidden-items.rs index d9f53435e4635..40cd636e2fe29 100644 --- a/tests/rustdoc/display-hidden-items.rs +++ b/tests/rustdoc/display-hidden-items.rs @@ -5,19 +5,19 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/span[@title="Hidden item"]' '๐Ÿ‘ป' +//@ has - '//dt/span[@title="Hidden item"]' '๐Ÿ‘ป' //@ has - '//*[@id="reexport.hidden_reexport"]/code' '#[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport;' #[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport; -//@ has - '//*[@class="item-name"]/a[@class="trait"]' 'TraitHidden' +//@ has - '//dt/a[@class="trait"]' 'TraitHidden' //@ has 'foo/trait.TraitHidden.html' //@ has - '//code' '#[doc(hidden)] pub trait TraitHidden' #[doc(hidden)] pub trait TraitHidden {} -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="trait"]' 'Trait' +//@ has 'foo/index.html' '//dt/a[@class="trait"]' 'Trait' pub trait Trait { //@ has 'foo/trait.Trait.html' //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32' @@ -29,7 +29,7 @@ pub trait Trait { fn foo() {} } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="struct"]' 'Struct' +//@ has 'foo/index.html' '//dt/a[@class="struct"]' 'Struct' //@ has 'foo/struct.Struct.html' pub struct Struct { //@ has - '//*[@id="structfield.a"]/code' 'a: u32' @@ -50,7 +50,7 @@ impl Trait for Struct { //@ has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct' impl TraitHidden for Struct {} -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'HiddenEnum' +//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'HiddenEnum' //@ has 'foo/enum.HiddenEnum.html' //@ has - '//code' '#[doc(hidden)] pub enum HiddenEnum' #[doc(hidden)] @@ -58,18 +58,18 @@ pub enum HiddenEnum { A, } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'Enum' +//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'Enum' pub enum Enum { //@ has 'foo/enum.Enum.html' '//*[@id="variant.A"]/*[@class="code-header"]' 'A' #[doc(hidden)] A, } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="mod"]' 'hidden' +//@ has 'foo/index.html' '//dt/a[@class="mod"]' 'hidden' #[doc(hidden)] pub mod hidden { //@ has 'foo/hidden/index.html' - //@ has - '//*[@class="item-name"]/a[@class="fn"]' 'inside_hidden' + //@ has - '//dt/a[@class="fn"]' 'inside_hidden' //@ has 'foo/hidden/fn.inside_hidden.html' pub fn inside_hidden() {} } diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg.rs index 6c973b5666b43..652c8419b4fb8 100644 --- a/tests/rustdoc/doc-cfg.rs +++ b/tests/rustdoc/doc-cfg.rs @@ -12,7 +12,7 @@ pub struct Portable; //@ has doc_cfg/unix_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on Unix only.' -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AARM\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\AARM\Z' //@ count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { @@ -42,7 +42,7 @@ pub mod unix_only { //@ has doc_cfg/wasi_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on WASI only.' -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AWebAssembly\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\AWebAssembly\Z' //@ count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_os = "wasi"))] pub mod wasi_only { @@ -74,7 +74,7 @@ pub mod wasi_only { // the portability header is different on the module view versus the full view //@ has doc_cfg/index.html -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\Aavx\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\Aavx\Z' //@ has doc_cfg/fn.uses_target_feature.html //@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/doc-hidden-reexports-109449.rs index cc3679f6196af..8f195544120af 100644 --- a/tests/rustdoc/doc-hidden-reexports-109449.rs +++ b/tests/rustdoc/doc-hidden-reexports-109449.rs @@ -26,7 +26,7 @@ pub mod single_reexport { //@ has 'foo/single_reexport/index.html' // First we check that we have 4 type aliases. - //@ count - '//*[@id="main-content"]/*[@class="item-table"]//code' 4 + //@ count - '//*[@id="main-content"]/*[@class="item-table reexports"]//code' 4 // Then we check that we have the correct link for each re-export. @@ -131,10 +131,10 @@ mod private { pub mod doc_hidden_reexport { //@ has 'foo/doc_hidden_reexport/index.html' // Ensure there is only one item in this page and that it's a struct. - //@ count - '//*[@class="item-name"]' 1 + //@ count - '//dt' 1 //@ has - '//a[@class="struct"]' 'Reexport' // Check that the `#[doc(hidden)]` re-export's attributes are not taken into account. - //@ has - '//*[@class="desc docblock-short"]' 'Visible. Original.' + //@ has - '//dd' 'Visible. Original.' /// Visible. pub use self::Bar3 as Reexport; /// Hidden. diff --git a/tests/rustdoc/double-hyphen-to-dash.rs b/tests/rustdoc/double-hyphen-to-dash.rs index 009de4faf41b6..c14acd065cde0 100644 --- a/tests/rustdoc/double-hyphen-to-dash.rs +++ b/tests/rustdoc/double-hyphen-to-dash.rs @@ -2,7 +2,7 @@ #![crate_name = "foo"] -//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' 'โ€“' +//@ has 'foo/index.html' '//dd' 'โ€“' //@ has 'foo/struct.Bar.html' '//*[@class="docblock"]' 'โ€“' /// -- diff --git a/tests/rustdoc/duplicate-cfg.rs b/tests/rustdoc/duplicate-cfg.rs index 87c089e9735b3..93f26ab944d34 100644 --- a/tests/rustdoc/duplicate-cfg.rs +++ b/tests/rustdoc/duplicate-cfg.rs @@ -2,8 +2,8 @@ #![feature(doc_cfg)] //@ has 'foo/index.html' -//@ matches '-' '//*[@class="item-name"]//*[@class="stab portability"]' '^sync$' -//@ has '-' '//*[@class="item-name"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' +//@ matches '-' '//dt//*[@class="stab portability"]' '^sync$' +//@ has '-' '//dt//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' //@ has 'foo/struct.Foo.html' //@ has '-' '//*[@class="stab portability"]' 'sync' diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc/footnote-in-summary.rs index d69282f104165..2a9668a9963b0 100644 --- a/tests/rustdoc/footnote-in-summary.rs +++ b/tests/rustdoc/footnote-in-summary.rs @@ -4,8 +4,8 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@class="desc docblock-short"]' 'hello bla' -//@ !has - '//*[@class="desc docblock-short"]/sup' '1' +//@ has - '//dd' 'hello bla' +//@ !has - '//dd/sup' '1' //@ has 'foo/struct.S.html' //@ has - '//*[@class="docblock"]//sup' '1' diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs index 30cb75f0e898d..5b918e0ffd9f2 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs @@ -7,9 +7,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]/dt[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]/dt[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1 mod a { #[doc(cfg(not(feature = "a")))] diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs index 3d49d3fd05da3..d0a2165ec8abb 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs @@ -6,9 +6,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]/dt[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]/dt[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1 mod a { #[cfg(not(feature = "a"))] diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/glob-shadowing-const.rs index 8d8d54ffe32f0..fbc22dbccaa77 100644 --- a/tests/rustdoc/glob-shadowing-const.rs +++ b/tests/rustdoc/glob-shadowing-const.rs @@ -15,6 +15,6 @@ mod sub4 { pub use sub4::inner::*; //@ has 'foo/index.html' -//@ has - '//dd[@class="desc docblock-short"]' '1' -//@ !has - '//dd[@class="desc docblock-short"]' '0' +//@ has - '//dd' '1' +//@ !has - '//dd' '0' fn main() { assert_eq!(X, 1); } diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc/glob-shadowing.rs index d150afcb1cc69..d9e9ead3f9a90 100644 --- a/tests/rustdoc/glob-shadowing.rs +++ b/tests/rustdoc/glob-shadowing.rs @@ -1,17 +1,17 @@ //@ has 'glob_shadowing/index.html' -//@ count - '//dt[@class="item-name"]' 6 -//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::describe' -//@ has - '//dd[@class="desc docblock-short"]' 'sub2::describe' +//@ count - '//dt' 6 +//@ !has - '//dd' 'sub1::describe' +//@ has - '//dd' 'sub2::describe' -//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::describe2' +//@ !has - '//dd' 'sub1::describe2' -//@ !has - '//dd[@class="desc docblock-short"]' 'sub1::prelude' -//@ has - '//dd[@class="desc docblock-short"]' 'mod::prelude' +//@ !has - '//dd' 'sub1::prelude' +//@ has - '//dd' 'mod::prelude' -//@ has - '//dd[@class="desc docblock-short"]' 'sub1::Foo (struct)' -//@ has - '//dd[@class="desc docblock-short"]' 'mod::Foo (function)' +//@ has - '//dd' 'sub1::Foo (struct)' +//@ has - '//dd' 'mod::Foo (function)' -//@ has - '//dd[@class="desc docblock-short"]' 'sub4::inner::X' +//@ has - '//dd' 'sub4::inner::X' //@ has 'glob_shadowing/fn.describe.html' //@ has - '//div[@class="docblock"]' 'sub2::describe' diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs index cea0f5565a20e..a514bc35bfc41 100644 --- a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs +++ b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs @@ -2,8 +2,8 @@ //@ has 'foo/index.html' // There should be only `type A`. -//@ count - '//*[@class="item-table"]//*[@class="item-name"]' 1 -//@ has - '//*[@class="item-name"]/a[@href="type.A.html"]' 'A' +//@ count - '//*[@class="item-table"]//dt' 1 +//@ has - '//dt/a[@href="type.A.html"]' 'A' mod foo { pub struct S; diff --git a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs index 752f3843eeae0..d27ecbad1690e 100644 --- a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs +++ b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs @@ -9,7 +9,7 @@ //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 1 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs' //@ has - '//*[@id="main-content"]//a[@href="struct.Reexport.html"]' 'Reexport' -//@ has - '//*[@id="main-content"]//*[@class="desc docblock-short"]' 'Visible. Original.' +//@ has - '//*[@id="main-content"]//dd' 'Visible. Original.' mod private { /// Original. diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs index 095cd2d3c55f1..49ca2db6a2245 100644 --- a/tests/rustdoc/inline_cross/inline_hidden.rs +++ b/tests/rustdoc/inline_cross/inline_hidden.rs @@ -11,14 +11,14 @@ extern crate rustdoc_hidden; pub use rustdoc_hidden::Foo; // Even if the foreign item has `doc(hidden)`, we should be able to inline it. -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined' +//@ has - '//dt/a[@class="struct"]' 'Inlined' #[doc(inline)] pub use rustdoc_hidden::Foo as Inlined; // Even with this import, we should not see `Foo`. -//@ count - '//*[@class="item-name"]' 4 -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar' -//@ has - '//*[@class="item-name"]/a[@class="fn"]' 'foo' +//@ count - '//dt' 4 +//@ has - '//dt/a[@class="struct"]' 'Bar' +//@ has - '//dt/a[@class="fn"]' 'foo' pub use rustdoc_hidden::*; //@ has inline_hidden/fn.foo.html diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc/inline_cross/macros.rs index aab7a3650b107..57eec77899e0b 100644 --- a/tests/rustdoc/inline_cross/macros.rs +++ b/tests/rustdoc/inline_cross/macros.rs @@ -6,10 +6,8 @@ extern crate macros; -//@ has foo/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// Deprecated -//@ has - '//*[@class="item-name"]/span[@class="stab unstable"]' \ -// Experimental +//@ has foo/index.html '//dt/span[@class="stab deprecated"]' Deprecated +//@ has - '//dt/span[@class="stab unstable"]' Experimental //@ has foo/macro.my_macro.html //@ has - '//*[@class="docblock"]' 'docs for my_macro' diff --git a/tests/rustdoc/internal.rs b/tests/rustdoc/internal.rs index e0bccefda1d1c..244e9138f2ba0 100644 --- a/tests/rustdoc/internal.rs +++ b/tests/rustdoc/internal.rs @@ -8,7 +8,7 @@ //@ !matches internal/index.html \ // '//*[@class="desc docblock-short"]/span[@class="stab internal"]' \ // '' -//@ matches - '//*[@class="desc docblock-short"]' 'Docs' +//@ matches - '//dd' 'Docs' //@ !has internal/struct.S.html '//*[@class="stab unstable"]' '' //@ !has internal/struct.S.html '//*[@class="stab internal"]' '' diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs index 44c820bfdd25b..f0362f684ad00 100644 --- a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs +++ b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs @@ -32,8 +32,8 @@ pub mod subone { //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' // Though there should be such links later -//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt[@class="item-name"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' -//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt[@class="item-name"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.foo.html"]' 'foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.bar.html"]' 'bar' /// See either [foo] or [bar]. pub mod subtwo { @@ -71,8 +71,8 @@ pub mod subthree { // Next we go *deeper* - In order to ensure it's not just "this or parent" // we test `crate::` and a `super::super::...` chain //@ has foo/subfour/subfive/subsix/subseven/subeight/index.html -//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd[@class="desc docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' -//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd[@class="desc docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' pub mod subfour { pub mod subfive { pub mod subsix { diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html index b6de929bc3bc2..89b4ac640f246 100644 --- a/tests/rustdoc/item-desc-list-at-start.item-table.html +++ b/tests/rustdoc/item-desc-list-at-start.item-table.html @@ -1 +1 @@ -
    MY_CONSTANT
    Groups: SamplePatternSGIS, SamplePatternEXT
    \ No newline at end of file +
    MY_CONSTANT
    Groups: SamplePatternSGIS, SamplePatternEXT
    \ No newline at end of file diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc/nested-items-issue-111415.rs index a5cd3ca0b1ae0..79dc2b0378ff7 100644 --- a/tests/rustdoc/nested-items-issue-111415.rs +++ b/tests/rustdoc/nested-items-issue-111415.rs @@ -10,7 +10,7 @@ //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Functions' //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Traits' // Checking that there are only three items. -//@ count - '//*[@id="main-content"]//*[@class="item-name"]' 3 +//@ count - '//*[@id="main-content"]//dt' 3 //@ has - '//*[@id="main-content"]//a[@href="struct.Bar.html"]' 'Bar' //@ has - '//*[@id="main-content"]//a[@href="fn.foo.html"]' 'foo' //@ has - '//*[@id="main-content"]//a[@href="trait.Foo.html"]' 'Foo' diff --git a/tests/rustdoc/overlapping-reexport-105735-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs index 9f823ec5923cd..fa43924ff4ebf 100644 --- a/tests/rustdoc/overlapping-reexport-105735-2.rs +++ b/tests/rustdoc/overlapping-reexport-105735-2.rs @@ -5,8 +5,8 @@ #![no_std] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/a[@class="type"]' 'AtomicU8' -//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8' +//@ has - '//dt/a[@class="type"]' 'AtomicU8' +//@ has - '//dt/a[@class="constant"]' 'AtomicU8' // We also ensure we don't have another item displayed. //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Type Aliases' diff --git a/tests/rustdoc/overlapping-reexport-105735.rs b/tests/rustdoc/overlapping-reexport-105735.rs index 2a2d0fa98309e..d1b5c0b6749ad 100644 --- a/tests/rustdoc/overlapping-reexport-105735.rs +++ b/tests/rustdoc/overlapping-reexport-105735.rs @@ -5,8 +5,8 @@ #![no_std] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'AtomicU8' -//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8' +//@ has - '//dt/a[@class="struct"]' 'AtomicU8' +//@ has - '//dt/a[@class="constant"]' 'AtomicU8' // We also ensure we don't have another item displayed. //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs' diff --git a/tests/rustdoc/pub-use-root-path-95873.rs b/tests/rustdoc/pub-use-root-path-95873.rs index e3d5ee6e31581..8e4fd9e8d5081 100644 --- a/tests/rustdoc/pub-use-root-path-95873.rs +++ b/tests/rustdoc/pub-use-root-path-95873.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/issues/95873 #![crate_name = "foo"] -//@ has foo/index.html "//*[@class='item-name']" "pub use ::std as x;" +//@ has foo/index.html "//dt" "pub use ::std as x;" pub use ::std as x; diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport-cfg.rs index fec5abc8290c7..73b6682431663 100644 --- a/tests/rustdoc/reexport-cfg.rs +++ b/tests/rustdoc/reexport-cfg.rs @@ -13,20 +13,18 @@ mod foo { } //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]' 'BabarNon-lie' +//@ has - '//dt' 'BabarNon-lie' #[cfg(not(feature = "lie"))] pub use crate::foo::Bar as Babar; -//@ has - '//*[@class="item-name"]' 'Babar2Non-cake' +//@ has - '//dt' 'Babar2Non-cake' #[doc(cfg(not(feature = "cake")))] pub use crate::foo::Bar2 as Babar2; -//@ has - '//*[@class="item-table"]/dt' 'pub use crate::Babar as Elephant;' -//@ has - '//*[@class="item-table"]/dd' 'Non-robot' +//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar as Elephant;Non-robot' #[cfg(not(feature = "robot"))] pub use crate::Babar as Elephant; -//@ has - '//*[@class="item-table"]/dt' 'pub use crate::Babar2 as Elephant2;' -//@ has - '//*[@class="item-table"]/dd' 'Non-cat' +//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar2 as Elephant2;Non-cat' #[doc(cfg(not(feature = "cat")))] pub use crate::Babar2 as Elephant2; diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport-check.rs index aacf4d1130f63..fc10e3aadd02b 100644 --- a/tests/rustdoc/reexport-check.rs +++ b/tests/rustdoc/reexport-check.rs @@ -8,13 +8,13 @@ extern crate reexport_check; #[allow(deprecated, deprecated_in_future)] pub use std::i32; //@ !has 'foo/index.html' '//code' 'pub use self::string::String;' -//@ has 'foo/index.html' '//dt[@class="item-name"]' 'String' +//@ has 'foo/index.html' '//dt' 'String' pub use std::string::String; // i32 is deprecated, String is not //@ count 'foo/index.html' '//span[@class="stab deprecated"]' 1 -//@ has 'foo/index.html' '//dd[@class="desc docblock-short"]' 'Docs in original' +//@ has 'foo/index.html' '//dd' 'Docs in original' // this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment #[doc(inline)] pub use reexport_check::S; diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs index e13f300d38cc7..8e194ef74fb82 100644 --- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -12,5 +12,5 @@ mod private_module { //@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' pub use crate::private_module::Public as Foo; // Glob re-exports with no visible items should not be displayed. -//@ count - '//*[@class="item-table"]/dt' 1 +//@ count - '//*[@class="item-table reexports"]/dt' 1 pub use crate::private_module::*; diff --git a/tests/rustdoc/reexport-of-reexport-108679.rs b/tests/rustdoc/reexport-of-reexport-108679.rs index 5c1b4bcbd8384..0d2faf71d3267 100644 --- a/tests/rustdoc/reexport-of-reexport-108679.rs +++ b/tests/rustdoc/reexport-of-reexport-108679.rs @@ -25,5 +25,6 @@ pub mod a { //@ has - '//*[@id="main-content"]//*[@id="reexport.A"]' 'pub use self::a::A;' //@ has - '//*[@id="main-content"]//*[@id="reexport.B"]' 'pub use self::a::B;' // Should only contain "Modules" and "Re-exports". -//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 2 +//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 1 +//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]' 1 pub use self::a::{A, B}; diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064.rs b/tests/rustdoc/reexport-trait-from-hidden-111064.rs index 84ec818ef338f..8b9ad7616ea20 100644 --- a/tests/rustdoc/reexport-trait-from-hidden-111064.rs +++ b/tests/rustdoc/reexport-trait-from-hidden-111064.rs @@ -5,7 +5,7 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@id="main-content"]//*[@class="item-name"]/a[@href="trait.Foo.html"]' 'Foo' +//@ has - '//*[@id="main-content"]//dt/a[@href="trait.Foo.html"]' 'Foo' //@ has 'foo/trait.Foo.html' //@ has - '//*[@id="main-content"]//*[@class="code-header"]' 'fn test()' diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc/short-docblock.rs index c80a5025ebecc..fa0af85696ac4 100644 --- a/tests/rustdoc/short-docblock.rs +++ b/tests/rustdoc/short-docblock.rs @@ -1,7 +1,7 @@ #![crate_name = "foo"] -//@ has foo/index.html '//*[@class="desc docblock-short"]' 'fooo' -//@ !has foo/index.html '//*[@class="desc docblock-short"]/h1' 'fooo' +//@ has foo/index.html '//dd' 'fooo' +//@ !has foo/index.html '//dd//h1' 'fooo' //@ has foo/fn.foo.html '//h2[@id="fooo"]' 'fooo' //@ has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'ยง' @@ -10,8 +10,8 @@ /// foo pub fn foo() {} -//@ has foo/index.html '//*[@class="desc docblock-short"]' 'mooood' -//@ !has foo/index.html '//*[@class="desc docblock-short"]/h2' 'mooood' +//@ has foo/index.html '//dd' 'mooood' +//@ !has foo/index.html '//dd//h2' 'mooood' //@ has foo/foo/index.html '//h3[@id="mooood"]' 'mooood' //@ has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'ยง' @@ -20,8 +20,7 @@ pub fn foo() {} /// foo mod pub mod foo {} -//@ has foo/index.html '//*[@class="desc docblock-short"]/a[@href=\ -// "https://nougat.world"]/code' 'nougat' +//@ has foo/index.html '//dd/a[@href="https://nougat.world"]/code' 'nougat' /// [`nougat`](https://nougat.world) pub struct Bar; diff --git a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs index 556b6fb61acd5..1021ce86df08f 100644 --- a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs +++ b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs @@ -4,11 +4,9 @@ #![unstable(feature = "test", issue = "32374")] #![crate_name="issue_32374"] -//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// 'Deprecated' -//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab unstable"]' \ -// 'Experimental' -//@ matches issue_32374/index.html '//*[@class="desc docblock-short"]/text()' 'Docs' +//@ matches issue_32374/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated' +//@ matches issue_32374/index.html '//dt/span[@class="stab unstable"]' 'Experimental' +//@ matches issue_32374/index.html '//dd/text()' 'Docs' //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' '๐Ÿ‘Ž' //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' \ diff --git a/tests/rustdoc/summary-header-46377.rs b/tests/rustdoc/summary-header-46377.rs index 11445f0dad6e1..c84f3a65cfbf7 100644 --- a/tests/rustdoc/summary-header-46377.rs +++ b/tests/rustdoc/summary-header-46377.rs @@ -1,6 +1,6 @@ // https://github.com/rust-lang/rust/issues/46377 #![crate_name="foo"] -//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' 'Check out this struct!' +//@ has 'foo/index.html' '//dd' 'Check out this struct!' /// # Check out this struct! pub struct SomeStruct; From 27f079ae24175a60edae59afdc34099d80e898c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 18 Jan 2025 21:04:52 +0000 Subject: [PATCH 5/9] Disallow `A { .. }` if `A` has no fields ``` error: `A` has no fields, `..` needs at least one default field in the struct definition --> $DIR/empty-struct.rs:16:17 | LL | let _ = A { .. }; | - ^^ | | | this type has no fields ``` --- compiler/rustc_hir_typeck/src/expr.rs | 33 ++++++++++++++----- .../default-field-values/empty-struct.rs | 21 ++++++++++++ .../default-field-values/empty-struct.stderr | 26 +++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 tests/ui/structs/default-field-values/empty-struct.rs create mode 100644 tests/ui/structs/default-field-values/empty-struct.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bb518e7f9711..dc6a2adf6220c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1991,18 +1991,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt_ty: Ty<'tcx>, expected: Expectation<'tcx>, expr: &hir::Expr<'_>, - span: Span, + path_span: Span, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], base_expr: &'tcx hir::StructTailExpr<'tcx>, ) { let tcx = self.tcx; - let adt_ty = self.try_structurally_resolve_type(span, adt_ty); + let adt_ty = self.try_structurally_resolve_type(path_span, adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); - ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?; + ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?; if !ocx.select_where_possible().is_empty() { return Err(TypeError::Mismatch); } @@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some(adt_ty_hint) = adt_ty_hint { // re-link the variables that the fudging above can create. - self.demand_eqtype(span, adt_ty_hint, adt_ty); + self.demand_eqtype(path_span, adt_ty_hint, adt_ty); } let ty::Adt(adt, args) = adt_ty.kind() else { - span_bug!(span, "non-ADT passed to check_expr_struct_fields"); + span_bug!(path_span, "non-ADT passed to check_expr_struct_fields"); }; let adt_kind = adt.adt_kind(); @@ -2107,7 +2107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if adt_kind == AdtKind::Union && hir_fields.len() != 1 { struct_span_code_err!( self.dcx(), - span, + path_span, E0784, "union expressions should have exactly one field", ) @@ -2167,6 +2167,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); return; } + if variant.fields.is_empty() { + let mut err = self.dcx().struct_span_err( + span, + format!( + "`{adt_ty}` has no fields, `..` needs at least one default field in the \ + struct definition", + ), + ); + err.span_label(path_span, "this type has no fields"); + err.emit(); + } if !missing_mandatory_fields.is_empty() { let s = pluralize!(missing_mandatory_fields.len()); let fields: Vec<_> = @@ -2316,11 +2327,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); if !private_fields.is_empty() { - self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields); + self.report_private_fields( + adt_ty, + path_span, + expr.span, + private_fields, + hir_fields, + ); } else { self.report_missing_fields( adt_ty, - span, + path_span, remaining_fields, variant, hir_fields, diff --git a/tests/ui/structs/default-field-values/empty-struct.rs b/tests/ui/structs/default-field-values/empty-struct.rs new file mode 100644 index 0000000000000..c9cb861ae27cb --- /dev/null +++ b/tests/ui/structs/default-field-values/empty-struct.rs @@ -0,0 +1,21 @@ +#![feature(default_field_values)] + +// If an API wants users to always use `..` even if they specify all the fields, they should use a +// sentinel field. As of now, that field can't be made private so it is only constructable with this +// syntax, but this might change in the future. + +struct A {} +struct B(); +struct C; +struct D { + x: i32, +} +struct E(i32); + +fn main() { + let _ = A { .. }; //~ ERROR has no fields + let _ = B { .. }; //~ ERROR has no fields + let _ = C { .. }; //~ ERROR has no fields + let _ = D { x: 0, .. }; + let _ = E { 0: 0, .. }; +} diff --git a/tests/ui/structs/default-field-values/empty-struct.stderr b/tests/ui/structs/default-field-values/empty-struct.stderr new file mode 100644 index 0000000000000..079e83415b4b8 --- /dev/null +++ b/tests/ui/structs/default-field-values/empty-struct.stderr @@ -0,0 +1,26 @@ +error: `A` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:16:17 + | +LL | let _ = A { .. }; + | - ^^ + | | + | this type has no fields + +error: `B` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:17:17 + | +LL | let _ = B { .. }; + | - ^^ + | | + | this type has no fields + +error: `C` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:18:17 + | +LL | let _ = C { .. }; + | - ^^ + | | + | this type has no fields + +error: aborting due to 3 previous errors + From b08f3d5bdb264aba8d81e6e13ebe498bd6a6bb12 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 Jan 2025 21:25:31 +0000 Subject: [PATCH 6/9] Consolidate ad-hoc MIR lints into real pass-manager-based MIR lints --- compiler/rustc_mir_build/messages.ftl | 12 --- compiler/rustc_mir_build/src/builder/mod.rs | 7 +- compiler/rustc_mir_build/src/errors.rs | 22 ----- compiler/rustc_mir_build/src/lib.rs | 4 +- compiler/rustc_mir_transform/messages.ftl | 12 +++ .../src/check_call_recursion.rs} | 81 ++++++++++--------- .../src/check_inline.rs | 52 +++++++----- compiler/rustc_mir_transform/src/errors.rs | 22 +++++ compiler/rustc_mir_transform/src/inline.rs | 6 +- compiler/rustc_mir_transform/src/lib.rs | 10 ++- tests/ui/mir/lint/storage-live.stderr | 2 +- 11 files changed, 120 insertions(+), 110 deletions(-) rename compiler/{rustc_mir_build/src/lints.rs => rustc_mir_transform/src/check_call_recursion.rs} (84%) rename compiler/{rustc_mir_build => rustc_mir_transform}/src/check_inline.rs (62%) diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 5203c33c968fb..ffdb721fb18b4 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -118,12 +118,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior .label = use of extern static -mir_build_force_inline = - `{$callee}` is incompatible with `#[rustc_force_inline]` - .attr = annotation here - .callee = `{$callee}` defined here - .note = incompatible due to: {$reason} - mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant mir_build_initializing_type_with_requires_unsafe = @@ -330,12 +324,6 @@ mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/s mir_build_type_not_structural_tip = the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -mir_build_unconditional_recursion = function cannot return without recursing - .label = cannot return without recursing - .help = a `loop` may express intention better if this is on purpose - -mir_build_unconditional_recursion_call_site_label = recursive call site - mir_build_union_field_requires_unsafe = access to union field is unsafe and requires unsafe block .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8b01ec0d06af1..9fa431f7d5fdf 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -26,10 +26,8 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; -use super::lints; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::scope::DropKind; -use crate::check_inline; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, @@ -48,7 +46,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( } /// Construct the MIR for a given `DefId`. -pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { +pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { let tcx = tcx.tcx; tcx.ensure_with_value().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { @@ -80,9 +78,6 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx } }; - lints::check(tcx, &body); - check_inline::check_force_inline(tcx, &body); - // The borrow checker will replace all the regions here with its own // inference variables. There's no point having non-erased regions here. // The exception is `body.user_type_annotations`, which is used unmodified diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 90c31a2caa326..83aec9ccdefc6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -11,16 +11,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; -#[derive(LintDiagnostic)] -#[diag(mir_build_unconditional_recursion)] -#[help] -pub(crate) struct UnconditionalRecursion { - #[label] - pub(crate) span: Span, - #[label(mir_build_unconditional_recursion_call_site_label)] - pub(crate) call_sites: Vec, -} - #[derive(LintDiagnostic)] #[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { @@ -1107,15 +1097,3 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> { ); } } - -#[derive(Diagnostic)] -#[diag(mir_build_force_inline)] -#[note] -pub(crate) struct InvalidForceInline { - #[primary_span] - pub attr_span: Span, - #[label(mir_build_callee)] - pub callee_span: Span, - pub callee: String, - pub reason: &'static str, -} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 76a35355de72a..8e786733ee03d 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -15,11 +15,9 @@ // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. mod builder; -pub mod check_inline; mod check_tail_calls; mod check_unsafety; mod errors; -pub mod lints; mod thir; use rustc_middle::util::Providers; @@ -29,7 +27,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; - providers.hooks.build_mir = builder::mir_build; + providers.hooks.build_mir = builder::build_mir; providers.closure_saved_names_of_captured_variables = builder::closure_saved_names_of_captured_variables; providers.check_unsafety = check_unsafety::check_unsafety; diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index b0c023cca8242..5628f4c9381b3 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -27,6 +27,12 @@ mir_transform_force_inline = .callee = `{$callee}` defined here .note = could not be inlined due to: {$reason} +mir_transform_force_inline_attr = + `{$callee}` is incompatible with `#[rustc_force_inline]` + .attr = annotation here + .callee = `{$callee}` defined here + .note = incompatible due to: {$reason} + mir_transform_force_inline_justification = `{$callee}` is required to be inlined to: {$sym} @@ -66,6 +72,12 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) +mir_transform_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_transform_unconditional_recursion_call_site_label = recursive call site + mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval .note = at compile-time, pointers do not have an integer value .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs similarity index 84% rename from compiler/rustc_mir_build/src/lints.rs rename to compiler/rustc_mir_transform/src/check_call_recursion.rs index 5cf33868adeee..51fd3c6512e4d 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -10,25 +10,54 @@ use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_span::Span; use crate::errors::UnconditionalRecursion; +use crate::pass_manager::MirLint; -pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - check_call_recursion(tcx, body); +pub(super) struct CheckCallRecursion; + +impl<'tcx> MirLint<'tcx> for CheckCallRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); + + if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { + // If this is trait/impl method, extract the trait's args. + let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { + Some(trait_def_id) => { + let trait_args_count = tcx.generics_of(trait_def_id).count(); + &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] + } + _ => &[], + }; + + check_recursion(tcx, body, CallRecursion { trait_args }) + } + } } -fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); +/// Requires drop elaboration to have been performed. +pub(super) struct CheckDropRecursion; - if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { - // If this is trait/impl method, extract the trait's args. - let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { - Some(trait_def_id) => { - let trait_args_count = tcx.generics_of(trait_def_id).count(); - &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] - } - _ => &[], - }; +impl<'tcx> MirLint<'tcx> for CheckDropRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); - check_recursion(tcx, body, CallRecursion { trait_args }) + // First check if `body` is an `fn drop()` of `Drop` + if let DefKind::AssocFn = tcx.def_kind(def_id) + && let Some(trait_ref) = + tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) + && let Some(drop_trait) = tcx.lang_items().drop_trait() + && drop_trait == trait_ref.instantiate_identity().def_id + // avoid erroneous `Drop` impls from causing ICEs below + && let sig = tcx.fn_sig(def_id).instantiate_identity() + && sig.inputs().skip_binder().len() == 1 + { + // It was. Now figure out for what type `Drop` is implemented and then + // check for recursion. + if let ty::Ref(_, dropped_ty, _) = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() + { + check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); + } + } } } @@ -61,30 +90,6 @@ fn check_recursion<'tcx>( } } -/// Requires drop elaboration to have been performed first. -pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - - // First check if `body` is an `fn drop()` of `Drop` - if let DefKind::AssocFn = tcx.def_kind(def_id) - && let Some(trait_ref) = - tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) - && let Some(drop_trait) = tcx.lang_items().drop_trait() - && drop_trait == trait_ref.instantiate_identity().def_id - // avoid erroneous `Drop` impls from causing ICEs below - && let sig = tcx.fn_sig(def_id).instantiate_identity() - && sig.inputs().skip_binder().len() == 1 - { - // It was. Now figure out for what type `Drop` is implemented and then - // check for recursion. - if let ty::Ref(_, dropped_ty, _) = - tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() - { - check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); - } - } -} - trait TerminatorClassifier<'tcx> { fn is_recursive_terminator( &self, diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs similarity index 62% rename from compiler/rustc_mir_build/src/check_inline.rs rename to compiler/rustc_mir_transform/src/check_inline.rs index 1af3b3e2c1353..497f4a660eaae 100644 --- a/compiler/rustc_mir_build/src/check_inline.rs +++ b/compiler/rustc_mir_transform/src/check_inline.rs @@ -1,3 +1,6 @@ +//! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its +//! definition alone (irrespective of any specific caller). + use rustc_attr_parsing::InlineAttr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -6,30 +9,37 @@ use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_span::sym; -/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its -/// definition alone (irrespective of any specific caller). -pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id(); - if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { - return; - } - let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { - return; - }; +use crate::pass_manager::MirLint; - if let Err(reason) = - is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) - { - tcx.dcx().emit_err(crate::errors::InvalidForceInline { - attr_span, - callee_span: tcx.def_span(def_id), - callee: tcx.def_path_str(def_id), - reason, - }); +pub(super) struct CheckForceInline; + +impl<'tcx> MirLint<'tcx> for CheckForceInline { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id(); + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { + return; + } + let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { + return; + }; + + if let Err(reason) = + is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) + { + tcx.dcx().emit_err(crate::errors::InvalidForceInline { + attr_span, + callee_span: tcx.def_span(def_id), + callee: tcx.def_path_str(def_id), + reason, + }); + } } } -pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> { +pub(super) fn is_inline_valid_on_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Result<(), &'static str> { let codegen_attrs = tcx.codegen_fn_attrs(def_id); if tcx.has_attr(def_id, sym::rustc_no_mir_inline) { return Err("#[rustc_no_mir_inline]"); @@ -65,7 +75,7 @@ pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<( Ok(()) } -pub fn is_inline_valid_on_body<'tcx>( +pub(super) fn is_inline_valid_on_body<'tcx>( _: TyCtxt<'tcx>, body: &Body<'tcx>, ) -> Result<(), &'static str> { diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 015633d145f15..a2fd46043ca0f 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -9,6 +9,28 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; +#[derive(LintDiagnostic)] +#[diag(mir_transform_unconditional_recursion)] +#[help] +pub(crate) struct UnconditionalRecursion { + #[label] + pub(crate) span: Span, + #[label(mir_transform_unconditional_recursion_call_site_label)] + pub(crate) call_sites: Vec, +} + +#[derive(Diagnostic)] +#[diag(mir_transform_force_inline_attr)] +#[note] +pub(crate) struct InvalidForceInline { + #[primary_span] + pub attr_span: Span, + #[label(mir_transform_callee)] + pub callee_span: Span, + pub callee: String, + pub reason: &'static str, +} + #[derive(LintDiagnostic)] pub(crate) enum ConstMutate { #[diag(mir_transform_const_modify)] diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 470393c9ae1b7..2052e28325c90 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -21,8 +21,8 @@ use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::CostChecker; use crate::deref_separator::deref_finder; use crate::simplify::simplify_cfg; -use crate::util; use crate::validate::validate_types; +use crate::{check_inline, util}; pub(crate) mod cycle; @@ -575,7 +575,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( check_mir_is_available(inliner, caller_body, callsite.callee)?; let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); - rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; + check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; check_codegen_attributes(inliner, callsite, callee_attrs)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); @@ -590,7 +590,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( } let callee_body = try_instance_mir(tcx, callsite.callee.def)?; - rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?; + check_inline::is_inline_valid_on_body(tcx, callee_body)?; inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?; let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index db999bea98692..d1bacf1f5985a 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -114,6 +114,8 @@ declare_passes! { mod add_moves_for_packed_drops : AddMovesForPackedDrops; mod add_retag : AddRetag; mod add_subtyping_projections : Subtyper; + mod check_inline : CheckForceInline; + mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; mod check_alignment : CheckAlignment; mod check_const_item_mutation : CheckConstItemMutation; mod check_packed_ref : CheckPackedRef; @@ -375,6 +377,8 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &mut body, &[ // MIR-level lints. + &Lint(check_inline::CheckForceInline), + &Lint(check_call_recursion::CheckCallRecursion), &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), @@ -505,10 +509,6 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & run_analysis_to_runtime_passes(tcx, &mut body); - // Now that drop elaboration has been performed, we can check for - // unconditional drop recursion. - rustc_mir_build::lints::check_drop_recursion(tcx, &body); - tcx.alloc_steal_mir(body) } @@ -570,6 +570,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Calling this after `PostAnalysisNormalize` ensures that we don't deal with opaque types. &add_subtyping_projections::Subtyper, &elaborate_drops::ElaborateDrops, + // Needs to happen after drop elaboration. + &Lint(check_call_recursion::CheckDropRecursion), // This will remove extraneous landing pads which are no longer // necessary as well as forcing any call in a non-unwinding // function calling a possibly-unwinding function to abort the process. diff --git a/tests/ui/mir/lint/storage-live.stderr b/tests/ui/mir/lint/storage-live.stderr index c701231951223..651b8e2327ee6 100644 --- a/tests/ui/mir/lint/storage-live.stderr +++ b/tests/ui/mir/lint/storage-live.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckPackedRef) at bb0[1]: +error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckForceInline) at bb0[1]: StorageLive(_1) which already has storage here --> $DIR/storage-live.rs:23:13 | From bd5f0178bc84edda9f7e9238fbd1a610b7ff3055 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 Jan 2025 18:05:41 +0000 Subject: [PATCH 7/9] Rename typeck_with_fallback --- compiler/rustc_hir_typeck/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index cb21961f36b2d..9cd9ca040ce7f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -87,7 +87,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, None) + typeck_with_inspect(tcx, def_id, None) } /// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation. @@ -99,11 +99,11 @@ pub fn inspect_typeck<'tcx>( def_id: LocalDefId, inspect: ObligationInspector<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, Some(inspect)) + typeck_with_inspect(tcx, def_id, Some(inspect)) } #[instrument(level = "debug", skip(tcx, inspector), ret)] -fn typeck_with_fallback<'tcx>( +fn typeck_with_inspect<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, inspector: Option>, From f3bd95d43c21b562d7e8faf6424ce0efad64fe84 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 Jan 2025 18:14:04 +0000 Subject: [PATCH 8/9] Use par_body_owners in coroutine check --- compiler/rustc_interface/src/passes.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aff66e48fbbee..241bc35857a4f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -875,6 +875,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); // Freeze definitions as we don't add new ones at this point. // We need to wait until now since we synthesize a by-move body + // for all coroutine-closures. + // // This improves performance by allowing lock-free access to them. tcx.untracked().definitions.freeze(); @@ -887,7 +889,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); }); sess.time("MIR_effect_checking", || { - for def_id in tcx.hir().body_owners() { + tcx.hir().par_body_owners(|def_id| { tcx.ensure().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from @@ -898,15 +900,17 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { { tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); } - } + }); }); - tcx.hir().par_body_owners(|def_id| { - if tcx.is_coroutine(def_id.to_def_id()) { - tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations( - tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), - ); - } + sess.time("coroutine_obligations", || { + tcx.hir().par_body_owners(|def_id| { + if tcx.is_coroutine(def_id.to_def_id()) { + tcx.ensure().mir_coroutine_witnesses(def_id); + tcx.ensure().check_coroutine_obligations( + tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), + ); + } + }); }); sess.time("layout_testing", || layout_test::test_layout(tcx)); From 0e98d9a3f78205a8135093ef3caa93ac604561de Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 Jan 2025 21:50:03 +0000 Subject: [PATCH 9/9] Fix comment --- compiler/rustc_middle/src/query/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bfbcb0532c10e..65e93c3a1cc75 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1164,8 +1164,7 @@ rustc_queries! { } /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the - /// current function, just all intermediate functions. + /// a cycle. query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { fatal_cycle desc { |tcx|