summaryrefslogtreecommitdiffstats
path: root/src/test/rustdoc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/rustdoc
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/test/rustdoc-gui/README.md34
-rw-r--r--src/test/rustdoc-gui/anchor-navigable.goml11
-rw-r--r--src/test/rustdoc-gui/anchors.goml34
-rw-r--r--src/test/rustdoc-gui/auto-hide-trait-implementations.goml13
-rw-r--r--src/test/rustdoc-gui/basic-code.goml3
-rw-r--r--src/test/rustdoc-gui/basic.goml4
-rw-r--r--src/test/rustdoc-gui/check-code-blocks-margin.goml6
-rw-r--r--src/test/rustdoc-gui/check_info_sign_position.goml11
-rw-r--r--src/test/rustdoc-gui/code-blocks-overflow.goml8
-rw-r--r--src/test/rustdoc-gui/code-color.goml30
-rw-r--r--src/test/rustdoc-gui/code-sidebar-toggle.goml7
-rw-r--r--src/test/rustdoc-gui/code-tags.goml20
-rw-r--r--src/test/rustdoc-gui/default-settings.goml8
-rw-r--r--src/test/rustdoc-gui/docblock-big-code-mobile.goml9
-rw-r--r--src/test/rustdoc-gui/docblock-code-block-line-number.goml22
-rw-r--r--src/test/rustdoc-gui/docblock-details.goml23
-rw-r--r--src/test/rustdoc-gui/docblock-table-overflow.goml21
-rw-r--r--src/test/rustdoc-gui/duplicate-macro-reexport.goml14
-rw-r--r--src/test/rustdoc-gui/escape-key.goml35
-rw-r--r--src/test/rustdoc-gui/font-weight.goml44
-rw-r--r--src/test/rustdoc-gui/hash-item-expansion.goml11
-rw-r--r--src/test/rustdoc-gui/headers-color.goml117
-rw-r--r--src/test/rustdoc-gui/headings.goml258
-rw-r--r--src/test/rustdoc-gui/huge-collection-of-constants.goml9
-rw-r--r--src/test/rustdoc-gui/impl-default-expansion.goml3
-rw-r--r--src/test/rustdoc-gui/implementors.goml35
-rw-r--r--src/test/rustdoc-gui/item-info-overflow.goml31
-rw-r--r--src/test/rustdoc-gui/item-info.goml32
-rw-r--r--src/test/rustdoc-gui/item-summary-table.goml6
-rw-r--r--src/test/rustdoc-gui/javascript-disabled.goml6
-rw-r--r--src/test/rustdoc-gui/jump-to-def-background.goml43
-rw-r--r--src/test/rustdoc-gui/label-next-to-symbol.goml78
-rw-r--r--src/test/rustdoc-gui/list_code_block.goml4
-rw-r--r--src/test/rustdoc-gui/mobile.goml30
-rw-r--r--src/test/rustdoc-gui/module-items-font.goml67
-rw-r--r--src/test/rustdoc-gui/overflow-tooltip-information.goml8
-rw-r--r--src/test/rustdoc-gui/pocket-menu.goml77
-rw-r--r--src/test/rustdoc-gui/run-on-hover.goml7
-rw-r--r--src/test/rustdoc-gui/rust-logo.goml78
-rw-r--r--src/test/rustdoc-gui/search-filter.goml83
-rw-r--r--src/test/rustdoc-gui/search-input-mobile.goml11
-rw-r--r--src/test/rustdoc-gui/search-input.goml23
-rw-r--r--src/test/rustdoc-gui/search-reexport.goml33
-rw-r--r--src/test/rustdoc-gui/search-result-color.goml98
-rw-r--r--src/test/rustdoc-gui/search-result-description.goml5
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml42
-rw-r--r--src/test/rustdoc-gui/search-result-go-to-first.goml19
-rw-r--r--src/test/rustdoc-gui/search-result-keyword.goml13
-rw-r--r--src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml74
-rw-r--r--src/test/rustdoc-gui/settings.goml158
-rw-r--r--src/test/rustdoc-gui/shortcuts.goml13
-rw-r--r--src/test/rustdoc-gui/sidebar-macro-reexport.goml5
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml64
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml254
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code.goml45
-rw-r--r--src/test/rustdoc-gui/sidebar.goml88
-rw-r--r--src/test/rustdoc-gui/source-anchor-scroll.goml20
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml49
-rw-r--r--src/test/rustdoc-gui/src-font-size.goml11
-rw-r--r--src/test/rustdoc-gui/src/lib2/Cargo.lock14
-rw-r--r--src/test/rustdoc-gui/src/lib2/Cargo.toml10
-rw-r--r--src/test/rustdoc-gui/src/lib2/another_folder/mod.rs3
-rw-r--r--src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs1
-rw-r--r--src/test/rustdoc-gui/src/lib2/another_mod/mod.rs1
-rw-r--r--src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml7
-rw-r--r--src/test/rustdoc-gui/src/lib2/implementors/lib.rs20
-rw-r--r--src/test/rustdoc-gui/src/lib2/lib.rs145
-rw-r--r--src/test/rustdoc-gui/src/link_to_definition/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/link_to_definition/Cargo.toml7
-rw-r--r--src/test/rustdoc-gui/src/link_to_definition/lib.rs35
-rw-r--r--src/test/rustdoc-gui/src/settings/.cargo/config.toml2
-rw-r--r--src/test/rustdoc-gui/src/settings/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/settings/Cargo.toml7
-rw-r--r--src/test/rustdoc-gui/src/settings/lib.rs1
-rw-r--r--src/test/rustdoc-gui/src/staged_api/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/staged_api/Cargo.toml11
-rw-r--r--src/test/rustdoc-gui/src/staged_api/lib.rs10
-rw-r--r--src/test/rustdoc-gui/src/test_docs/Cargo.lock7
-rw-r--r--src/test/rustdoc-gui/src/test_docs/Cargo.toml13
-rw-r--r--src/test/rustdoc-gui/src/test_docs/build.rs15
-rw-r--r--src/test/rustdoc-gui/src/test_docs/lib.rs295
-rw-r--r--src/test/rustdoc-gui/src/test_docs/macros.rs4
-rw-r--r--src/test/rustdoc-gui/theme-change.goml32
-rw-r--r--src/test/rustdoc-gui/theme-in-history.goml28
-rw-r--r--src/test/rustdoc-gui/toggle-click-deadspace.goml12
-rw-r--r--src/test/rustdoc-gui/toggle-docs-mobile.goml33
-rw-r--r--src/test/rustdoc-gui/toggle-docs.goml42
-rw-r--r--src/test/rustdoc-gui/toggle-implementors.goml4
-rw-r--r--src/test/rustdoc-gui/toggled-open-implementations.goml5
-rw-r--r--src/test/rustdoc-gui/trait-sidebar-item-order.goml8
-rw-r--r--src/test/rustdoc-gui/type-declation-overflow.goml37
-rw-r--r--src/test/rustdoc-js-std/alias-1.js7
-rw-r--r--src/test/rustdoc-js-std/alias-2.js10
-rw-r--r--src/test/rustdoc-js-std/alias-3.js7
-rw-r--r--src/test/rustdoc-js-std/alias-4.js7
-rw-r--r--src/test/rustdoc-js-std/alias.js11
-rw-r--r--src/test/rustdoc-js-std/asrawfd.js14
-rw-r--r--src/test/rustdoc-js-std/basic.js15
-rw-r--r--src/test/rustdoc-js-std/deduplication.js11
-rw-r--r--src/test/rustdoc-js-std/enum-option.js7
-rw-r--r--src/test/rustdoc-js-std/filter-crate.js9
-rw-r--r--src/test/rustdoc-js-std/fn-forget.js8
-rw-r--r--src/test/rustdoc-js-std/from_u.js9
-rw-r--r--src/test/rustdoc-js-std/keyword.js10
-rw-r--r--src/test/rustdoc-js-std/macro-check.js10
-rw-r--r--src/test/rustdoc-js-std/macro-print.js10
-rw-r--r--src/test/rustdoc-js-std/never.js7
-rw-r--r--src/test/rustdoc-js-std/parser-errors.js385
-rw-r--r--src/test/rustdoc-js-std/parser-filter.js43
-rw-r--r--src/test/rustdoc-js-std/parser-generics.js62
-rw-r--r--src/test/rustdoc-js-std/parser-ident.js93
-rw-r--r--src/test/rustdoc-js-std/parser-literal.js27
-rw-r--r--src/test/rustdoc-js-std/parser-paths.js90
-rw-r--r--src/test/rustdoc-js-std/parser-quote.js87
-rw-r--r--src/test/rustdoc-js-std/parser-returned.js99
-rw-r--r--src/test/rustdoc-js-std/parser-separators.js206
-rw-r--r--src/test/rustdoc-js-std/parser-weird-queries.js123
-rw-r--r--src/test/rustdoc-js-std/path-ordering.js12
-rw-r--r--src/test/rustdoc-js-std/primitive.js75
-rw-r--r--src/test/rustdoc-js-std/quoted.js21
-rw-r--r--src/test/rustdoc-js-std/return-specific-literal.js10
-rw-r--r--src/test/rustdoc-js-std/return-specific.js10
-rw-r--r--src/test/rustdoc-js-std/should-fail.js9
-rw-r--r--src/test/rustdoc-js-std/string-from_ut.js11
-rw-r--r--src/test/rustdoc-js-std/struct-vec.js8
-rw-r--r--src/test/rustdoc-js-std/typed-query.js17
-rw-r--r--src/test/rustdoc-js-std/vec-new.js9
-rw-r--r--src/test/rustdoc-js/basic.js7
-rw-r--r--src/test/rustdoc-js/basic.rs2
-rw-r--r--src/test/rustdoc-js/doc-alias-filter-out.js9
-rw-r--r--src/test/rustdoc-js/doc-alias-filter-out.rs2
-rw-r--r--src/test/rustdoc-js/doc-alias-filter.js17
-rw-r--r--src/test/rustdoc-js/doc-alias-filter.rs5
-rw-r--r--src/test/rustdoc-js/doc-alias-whitespace.js19
-rw-r--r--src/test/rustdoc-js/doc-alias-whitespace.rs2
-rw-r--r--src/test/rustdoc-js/doc-alias.js295
-rw-r--r--src/test/rustdoc-js/doc-alias.rs75
-rw-r--r--src/test/rustdoc-js/exact-match.js9
-rw-r--r--src/test/rustdoc-js/exact-match.rs68
-rw-r--r--src/test/rustdoc-js/foreign-type-path.js9
-rw-r--r--src/test/rustdoc-js/foreign-type-path.rs13
-rw-r--r--src/test/rustdoc-js/generics-impl.js57
-rw-r--r--src/test/rustdoc-js/generics-impl.rs35
-rw-r--r--src/test/rustdoc-js/generics-multi-trait.js32
-rw-r--r--src/test/rustdoc-js/generics-multi-trait.rs12
-rw-r--r--src/test/rustdoc-js/generics-trait.js23
-rw-r--r--src/test/rustdoc-js/generics-trait.rs8
-rw-r--r--src/test/rustdoc-js/generics.js73
-rw-r--r--src/test/rustdoc-js/generics.rs28
-rw-r--r--src/test/rustdoc-js/impl-trait.js51
-rw-r--r--src/test/rustdoc-js/impl-trait.rs21
-rw-r--r--src/test/rustdoc-js/module-substring.js9
-rw-r--r--src/test/rustdoc-js/module-substring.rs68
-rw-r--r--src/test/rustdoc-js/path-ordering.js14
-rw-r--r--src/test/rustdoc-js/path-ordering.rs9
-rw-r--r--src/test/rustdoc-js/primitive.js25
-rw-r--r--src/test/rustdoc-js/primitive.rs5
-rw-r--r--src/test/rustdoc-js/prototype.js16
-rw-r--r--src/test/rustdoc-js/prototype.rs4
-rw-r--r--src/test/rustdoc-js/raw-pointer.js55
-rw-r--r--src/test/rustdoc-js/raw-pointer.rs24
-rw-r--r--src/test/rustdoc-js/search-short-types.js10
-rw-r--r--src/test/rustdoc-js/search-short-types.rs74
-rw-r--r--src/test/rustdoc-js/struct-like-variant.js7
-rw-r--r--src/test/rustdoc-js/struct-like-variant.rs8
-rw-r--r--src/test/rustdoc-js/substring.js8
-rw-r--r--src/test/rustdoc-js/substring.rs21
-rw-r--r--src/test/rustdoc-js/summaries.js21
-rw-r--r--src/test/rustdoc-js/summaries.rs22
-rw-r--r--src/test/rustdoc-json/assoc_items.rs29
-rw-r--r--src/test/rustdoc-json/assoc_type.rs22
-rw-r--r--src/test/rustdoc-json/blanket_impls.rs9
-rw-r--r--src/test/rustdoc-json/doc_hidden_failure.rs22
-rw-r--r--src/test/rustdoc-json/enums/variant_struct.rs11
-rw-r--r--src/test/rustdoc-json/enums/variant_tuple_struct.rs8
-rw-r--r--src/test/rustdoc-json/fn_pointer/abi.rs25
-rw-r--r--src/test/rustdoc-json/fn_pointer/generics.rs14
-rw-r--r--src/test/rustdoc-json/fn_pointer/qualifiers.rs9
-rw-r--r--src/test/rustdoc-json/fns/abi.rs25
-rw-r--r--src/test/rustdoc-json/fns/generic_args.rs71
-rw-r--r--src/test/rustdoc-json/fns/generic_returns.rs21
-rw-r--r--src/test/rustdoc-json/fns/generics.rs26
-rw-r--r--src/test/rustdoc-json/fns/qualifiers.rs33
-rw-r--r--src/test/rustdoc-json/generic-associated-types/gats.rs44
-rw-r--r--src/test/rustdoc-json/generic_impl.rs24
-rw-r--r--src/test/rustdoc-json/glob_import.rs24
-rw-r--r--src/test/rustdoc-json/impls/blanket_with_local.rs18
-rw-r--r--src/test/rustdoc-json/keyword.rs21
-rw-r--r--src/test/rustdoc-json/lifetime/longest.rs33
-rw-r--r--src/test/rustdoc-json/lifetime/outlives.rs23
-rw-r--r--src/test/rustdoc-json/methods/abi.rs55
-rw-r--r--src/test/rustdoc-json/methods/qualifiers.rs37
-rw-r--r--src/test/rustdoc-json/nested.rs30
-rw-r--r--src/test/rustdoc-json/output_generics.rs38
-rw-r--r--src/test/rustdoc-json/primitive.rs14
-rw-r--r--src/test/rustdoc-json/primitive_overloading.rs17
-rw-r--r--src/test/rustdoc-json/primitives.rs22
-rw-r--r--src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs1
-rw-r--r--src/test/rustdoc-json/reexport/glob_extern.rs18
-rw-r--r--src/test/rustdoc-json/reexport/glob_private.rs32
-rw-r--r--src/test/rustdoc-json/reexport/in_root_and_mod.rs17
-rw-r--r--src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs20
-rw-r--r--src/test/rustdoc-json/reexport/macro.rs17
-rw-r--r--src/test/rustdoc-json/reexport/private_twice_one_inline.rs18
-rw-r--r--src/test/rustdoc-json/reexport/private_two_names.rs17
-rw-r--r--src/test/rustdoc-json/reexport/rename_private.rs14
-rw-r--r--src/test/rustdoc-json/reexport/rename_public.rs17
-rw-r--r--src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs15
-rw-r--r--src/test/rustdoc-json/reexport/simple_private.rs15
-rw-r--r--src/test/rustdoc-json/reexport/simple_public.rs18
-rw-r--r--src/test/rustdoc-json/return_private.rs15
-rw-r--r--src/test/rustdoc-json/stripped_modules.rs21
-rw-r--r--src/test/rustdoc-json/structs/plain_empty.rs6
-rw-r--r--src/test/rustdoc-json/structs/tuple.rs5
-rw-r--r--src/test/rustdoc-json/structs/unit.rs5
-rw-r--r--src/test/rustdoc-json/structs/with_generics.rs14
-rw-r--r--src/test/rustdoc-json/structs/with_primitives.rs10
-rw-r--r--src/test/rustdoc-json/traits/has_body.rs21
-rw-r--r--src/test/rustdoc-json/traits/implementors.rs19
-rw-r--r--src/test/rustdoc-json/traits/supertrait.rs26
-rw-r--r--src/test/rustdoc-json/type/dyn.rs21
-rw-r--r--src/test/rustdoc-json/type/fn_lifetime.rs28
-rw-r--r--src/test/rustdoc-json/type/generic_default.rs33
-rw-r--r--src/test/rustdoc-json/unions/impl.rs15
-rw-r--r--src/test/rustdoc-json/unions/union.rs7
-rw-r--r--src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs16
-rw-r--r--src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr15
-rw-r--r--src/test/rustdoc-ui/assoc-item-not-in-scope.rs22
-rw-r--r--src/test/rustdoc-ui/assoc-item-not-in-scope.stderr14
-rw-r--r--src/test/rustdoc-ui/auxiliary/empty-fn.rs3
-rw-r--r--src/test/rustdoc-ui/auxiliary/extern_macros.rs7
-rw-r--r--src/test/rustdoc-ui/auxiliary/issue-61592.rs3
-rw-r--r--src/test/rustdoc-ui/auxiliary/module_macro_doc.rs1
-rw-r--r--src/test/rustdoc-ui/auxiliary/overflow.rs20
-rw-r--r--src/test/rustdoc-ui/auxiliary/panic-item.rs17
-rw-r--r--src/test/rustdoc-ui/bare-urls.fixed60
-rw-r--r--src/test/rustdoc-ui/bare-urls.rs60
-rw-r--r--src/test/rustdoc-ui/bare-urls.stderr143
-rw-r--r--src/test/rustdoc-ui/block-doc-comment.rs17
-rw-r--r--src/test/rustdoc-ui/block-doc-comment.stdout5
-rw-r--r--src/test/rustdoc-ui/bounded-hr-lifetime.rs9
-rw-r--r--src/test/rustdoc-ui/bounded-hr-lifetime.stderr10
-rw-r--r--src/test/rustdoc-ui/c-help.rs6
-rw-r--r--src/test/rustdoc-ui/c-help.stdout51
-rw-r--r--src/test/rustdoc-ui/cfg-test.rs31
-rw-r--r--src/test/rustdoc-ui/cfg-test.stdout7
-rw-r--r--src/test/rustdoc-ui/check-attr-test.rs31
-rw-r--r--src/test/rustdoc-ui/check-attr-test.stderr151
-rw-r--r--src/test/rustdoc-ui/check-attr.rs41
-rw-r--r--src/test/rustdoc-ui/check-attr.stderr175
-rw-r--r--src/test/rustdoc-ui/check-cfg-test.rs12
-rw-r--r--src/test/rustdoc-ui/check-cfg-test.stderr11
-rw-r--r--src/test/rustdoc-ui/check-cfg-test.stdout6
-rw-r--r--src/test/rustdoc-ui/check-cfg-unstable.rs2
-rw-r--r--src/test/rustdoc-ui/check-cfg-unstable.stderr2
-rw-r--r--src/test/rustdoc-ui/check-cfg.rs7
-rw-r--r--src/test/rustdoc-ui/check-cfg.stderr10
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr-location.rs23
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr-location.stderr26
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr.rs28
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr.stderr108
-rw-r--r--src/test/rustdoc-ui/check-fail.rs21
-rw-r--r--src/test/rustdoc-ui/check-fail.stderr52
-rw-r--r--src/test/rustdoc-ui/check.rs12
-rw-r--r--src/test/rustdoc-ui/check.stderr55
-rw-r--r--src/test/rustdoc-ui/commandline-argfile-badutf8.args2
-rw-r--r--src/test/rustdoc-ui/commandline-argfile-badutf8.rs12
-rw-r--r--src/test/rustdoc-ui/commandline-argfile-badutf8.stderr2
-rw-r--r--src/test/rustdoc-ui/commandline-argfile-missing.rs14
-rw-r--r--src/test/rustdoc-ui/commandline-argfile-missing.stderr2
-rw-r--r--src/test/rustdoc-ui/commandline-argfile.args2
-rw-r--r--src/test/rustdoc-ui/commandline-argfile.rs13
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.rs41
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stderr20
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/basic.rs50
-rw-r--r--src/test/rustdoc-ui/coverage/basic.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/doc-examples-json.rs13
-rw-r--r--src/test/rustdoc-ui/coverage/doc-examples-json.stdout1
-rw-r--r--src/test/rustdoc-ui/coverage/doc-examples.rs27
-rw-r--r--src/test/rustdoc-ui/coverage/doc-examples.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/empty.rs4
-rw-r--r--src/test/rustdoc-ui/coverage/empty.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/enum-tuple-documented.rs37
-rw-r--r--src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/enum-tuple.rs18
-rw-r--r--src/test/rustdoc-ui/coverage/enum-tuple.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/enums.rs22
-rw-r--r--src/test/rustdoc-ui/coverage/enums.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/exotic.rs15
-rw-r--r--src/test/rustdoc-ui/coverage/exotic.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/html.rs4
-rw-r--r--src/test/rustdoc-ui/coverage/html.stderr2
-rw-r--r--src/test/rustdoc-ui/coverage/json.rs65
-rw-r--r--src/test/rustdoc-ui/coverage/json.stdout1
-rw-r--r--src/test/rustdoc-ui/coverage/private.rs21
-rw-r--r--src/test/rustdoc-ui/coverage/private.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/statics-consts.rs23
-rw-r--r--src/test/rustdoc-ui/coverage/statics-consts.stdout7
-rw-r--r--src/test/rustdoc-ui/coverage/traits.rs38
-rw-r--r--src/test/rustdoc-ui/coverage/traits.stdout7
-rw-r--r--src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs4
-rw-r--r--src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr15
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-crate.rs3
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-crate.stderr22
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-macro.rs8
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-macro.stderr14
-rw-r--r--src/test/rustdoc-ui/deprecated-attrs.rs16
-rw-r--r--src/test/rustdoc-ui/deprecated-attrs.stderr34
-rw-r--r--src/test/rustdoc-ui/deref-generic.rs15
-rw-r--r--src/test/rustdoc-ui/diagnostic-width.rs5
-rw-r--r--src/test/rustdoc-ui/diagnostic-width.stderr15
-rw-r--r--src/test/rustdoc-ui/display-output.rs15
-rw-r--r--src/test/rustdoc-ui/display-output.stdout43
-rw-r--r--src/test/rustdoc-ui/doc-alias-assoc-const.rs21
-rw-r--r--src/test/rustdoc-ui/doc-alias-assoc-const.stderr8
-rw-r--r--src/test/rustdoc-ui/doc-alias-crate-level.rs4
-rw-r--r--src/test/rustdoc-ui/doc-alias-crate-level.stderr14
-rw-r--r--src/test/rustdoc-ui/doc-alias-same-name.rs4
-rw-r--r--src/test/rustdoc-ui/doc-alias-same-name.stderr8
-rw-r--r--src/test/rustdoc-ui/doc-attr.rs25
-rw-r--r--src/test/rustdoc-ui/doc-attr.stderr71
-rw-r--r--src/test/rustdoc-ui/doc-cfg.rs9
-rw-r--r--src/test/rustdoc-ui/doc-cfg.stderr26
-rw-r--r--src/test/rustdoc-ui/doc-comment-multi-line-attr.rs11
-rw-r--r--src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout6
-rw-r--r--src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs12
-rw-r--r--src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout6
-rw-r--r--src/test/rustdoc-ui/doc-include-suggestion.rs10
-rw-r--r--src/test/rustdoc-ui/doc-include-suggestion.stderr12
-rw-r--r--src/test/rustdoc-ui/doc-spotlight.fixed8
-rw-r--r--src/test/rustdoc-ui/doc-spotlight.rs8
-rw-r--r--src/test/rustdoc-ui/doc-spotlight.stderr19
-rw-r--r--src/test/rustdoc-ui/doc-test-attr-pass.rs8
-rw-r--r--src/test/rustdoc-ui/doc-test-attr.rs14
-rw-r--r--src/test/rustdoc-ui/doc-test-attr.stderr34
-rw-r--r--src/test/rustdoc-ui/doc-test-doctest-feature.rs13
-rw-r--r--src/test/rustdoc-ui/doc-test-doctest-feature.stdout6
-rw-r--r--src/test/rustdoc-ui/doc-test-rustdoc-feature.rs15
-rw-r--r--src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout6
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.rs22
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.stderr38
-rw-r--r--src/test/rustdoc-ui/doctest-edition.rs16
-rw-r--r--src/test/rustdoc-ui/doctest-edition.stderr22
-rw-r--r--src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs10
-rw-r--r--src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout6
-rw-r--r--src/test/rustdoc-ui/doctest-output.rs28
-rw-r--r--src/test/rustdoc-ui/doctest-output.stdout8
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/README.md7
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/async.rs7
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/closure.rs5
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs23
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs7
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs6
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs6
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs28
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs10
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs10
-rw-r--r--src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs157
-rw-r--r--src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr28
-rw-r--r--src/test/rustdoc-ui/failed-doctest-compile-fail.rs12
-rw-r--r--src/test/rustdoc-ui/failed-doctest-compile-fail.stdout14
-rw-r--r--src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs18
-rw-r--r--src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout24
-rw-r--r--src/test/rustdoc-ui/failed-doctest-missing-codes.rs12
-rw-r--r--src/test/rustdoc-ui/failed-doctest-missing-codes.stdout25
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output-windows.rs28
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output-windows.stdout39
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.rs28
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout39
-rw-r--r--src/test/rustdoc-ui/failed-doctest-should-panic.rs12
-rw-r--r--src/test/rustdoc-ui/failed-doctest-should-panic.stdout14
-rw-r--r--src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs7
-rw-r--r--src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr14
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr2
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt.stderr2
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt2.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr2
-rw-r--r--src/test/rustdoc-ui/ignore-block-help.rs10
-rw-r--r--src/test/rustdoc-ui/ignore-block-help.stderr19
-rw-r--r--src/test/rustdoc-ui/impl-fn-nesting.rs49
-rw-r--r--src/test/rustdoc-ui/impl-fn-nesting.stderr66
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs15
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr17
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs7
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr17
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type.rs4
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type.stderr17
-rw-r--r--src/test/rustdoc-ui/intra-doc/alias-ice.rs6
-rw-r--r--src/test/rustdoc-ui/intra-doc/alias-ice.stderr14
-rw-r--r--src/test/rustdoc-ui/intra-doc/ambiguity.rs40
-rw-r--r--src/test/rustdoc-ui/intra-doc/ambiguity.stderr101
-rw-r--r--src/test/rustdoc-ui/intra-doc/anchors.rs39
-rw-r--r--src/test/rustdoc-ui/intra-doc/anchors.stderr32
-rw-r--r--src/test/rustdoc-ui/intra-doc/assoc-field.rs26
-rw-r--r--src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs19
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs18
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs11
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs1
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs4
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs4
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs20
-rw-r--r--src/test/rustdoc-ui/intra-doc/broken-reexport.rs8
-rw-r--r--src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs5
-rw-r--r--src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr14
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs81
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr153
-rw-r--r--src/test/rustdoc-ui/intra-doc/double-anchor.rs7
-rw-r--r--src/test/rustdoc-ui/intra-doc/double-anchor.stderr12
-rw-r--r--src/test/rustdoc-ui/intra-doc/email-address-localhost.rs7
-rw-r--r--src/test/rustdoc-ui/intra-doc/errors.rs105
-rw-r--r--src/test/rustdoc-ui/intra-doc/errors.stderr157
-rw-r--r--src/test/rustdoc-ui/intra-doc/extern-crate-load.rs26
-rw-r--r--src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs6
-rw-r--r--src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr23
-rw-r--r--src/test/rustdoc-ui/intra-doc/field-ice.rs11
-rw-r--r--src/test/rustdoc-ui/intra-doc/field-ice.stderr18
-rw-r--r--src/test/rustdoc-ui/intra-doc/global-path.rs8
-rw-r--r--src/test/rustdoc-ui/intra-doc/global-path.stderr10
-rw-r--r--src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs25
-rw-r--r--src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr69
-rw-r--r--src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs3
-rw-r--r--src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr18
-rw-r--r--src/test/rustdoc-ui/intra-doc/macro-rules-error.rs26
-rw-r--r--src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr23
-rw-r--r--src/test/rustdoc-ui/intra-doc/macro-rules.rs24
-rw-r--r--src/test/rustdoc-ui/intra-doc/malformed-generics.rs19
-rw-r--r--src/test/rustdoc-ui/intra-doc/malformed-generics.stderr102
-rw-r--r--src/test/rustdoc-ui/intra-doc/non-path-primitives.rs34
-rw-r--r--src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr63
-rw-r--r--src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs4
-rw-r--r--src/test/rustdoc-ui/intra-doc/prim-conflict.rs30
-rw-r--r--src/test/rustdoc-ui/intra-doc/prim-conflict.stderr59
-rw-r--r--src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs6
-rw-r--r--src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr11
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.private.stderr27
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.public.stderr27
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.rs18
-rw-r--r--src/test/rustdoc-ui/intra-doc/span-ice-55723.rs13
-rw-r--r--src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr15
-rw-r--r--src/test/rustdoc-ui/intra-doc/through-proc-macro.rs18
-rw-r--r--src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr15
-rw-r--r--src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs14
-rw-r--r--src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr56
-rw-r--r--src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs6
-rw-r--r--src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr13
-rw-r--r--src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs5
-rw-r--r--src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr15
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning-crlf.rs26
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning-crlf.stderr35
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning.rs84
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning.stderr175
-rw-r--r--src/test/rustdoc-ui/invalid-cfg.rs4
-rw-r--r--src/test/rustdoc-ui/invalid-cfg.stderr14
-rw-r--r--src/test/rustdoc-ui/invalid-doc-attr.rs32
-rw-r--r--src/test/rustdoc-ui/invalid-doc-attr.stderr78
-rw-r--r--src/test/rustdoc-ui/invalid-html-tags.rs116
-rw-r--r--src/test/rustdoc-ui/invalid-html-tags.stderr98
-rw-r--r--src/test/rustdoc-ui/invalid-keyword.rs4
-rw-r--r--src/test/rustdoc-ui/invalid-keyword.stderr8
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.rs101
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.stderr154
-rw-r--r--src/test/rustdoc-ui/invalid-theme-name.rs3
-rw-r--r--src/test/rustdoc-ui/invalid-theme-name.stderr4
-rw-r--r--src/test/rustdoc-ui/issue-58473-2.rs12
-rw-r--r--src/test/rustdoc-ui/issue-58473.rs10
-rw-r--r--src/test/rustdoc-ui/issue-61592-2.rs10
-rw-r--r--src/test/rustdoc-ui/issue-61592-2.stderr12
-rw-r--r--src/test/rustdoc-ui/issue-61592.rs8
-rw-r--r--src/test/rustdoc-ui/issue-61592.stderr11
-rw-r--r--src/test/rustdoc-ui/issue-61732.rs4
-rw-r--r--src/test/rustdoc-ui/issue-61732.stderr13
-rw-r--r--src/test/rustdoc-ui/issue-74134.private.stderr11
-rw-r--r--src/test/rustdoc-ui/issue-74134.public.stderr11
-rw-r--r--src/test/rustdoc-ui/issue-74134.rs41
-rw-r--r--src/test/rustdoc-ui/issue-79465.rs3
-rw-r--r--src/test/rustdoc-ui/issue-79465.stderr15
-rw-r--r--src/test/rustdoc-ui/issue-79467.rs8
-rw-r--r--src/test/rustdoc-ui/issue-79467.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-79494.rs5
-rw-r--r--src/test/rustdoc-ui/issue-79494.stderr12
-rw-r--r--src/test/rustdoc-ui/issue-80992.rs11
-rw-r--r--src/test/rustdoc-ui/issue-80992.stdout6
-rw-r--r--src/test/rustdoc-ui/issue-81662-shortness.rs12
-rw-r--r--src/test/rustdoc-ui/issue-81662-shortness.stdout16
-rw-r--r--src/test/rustdoc-ui/issue-83883-describe-lints.rs10
-rw-r--r--src/test/rustdoc-ui/issue-83883-describe-lints.stdout24
-rw-r--r--src/test/rustdoc-ui/issue-91134.rs14
-rw-r--r--src/test/rustdoc-ui/issue-91134.stdout6
-rw-r--r--src/test/rustdoc-ui/issue-91713.rs3
-rw-r--r--src/test/rustdoc-ui/issue-91713.stderr5
-rw-r--r--src/test/rustdoc-ui/issue-91713.stdout29
-rw-r--r--src/test/rustdoc-ui/issue-98690.rs10
-rw-r--r--src/test/rustdoc-ui/issue-98690.stderr1
-rw-r--r--src/test/rustdoc-ui/lint-group.rs29
-rw-r--r--src/test/rustdoc-ui/lint-group.stderr50
-rw-r--r--src/test/rustdoc-ui/lint-missing-doc-code-example.rs100
-rw-r--r--src/test/rustdoc-ui/lint-missing-doc-code-example.stderr38
-rw-r--r--src/test/rustdoc-ui/macro-docs.rs12
-rw-r--r--src/test/rustdoc-ui/macro-docs.stderr20
-rw-r--r--src/test/rustdoc-ui/macro-docs.stdout0
-rw-r--r--src/test/rustdoc-ui/no-crate-level-doc-lint.rs6
-rw-r--r--src/test/rustdoc-ui/no-crate-level-doc-lint.stderr12
-rw-r--r--src/test/rustdoc-ui/no-run-flag-error.rs6
-rw-r--r--src/test/rustdoc-ui/no-run-flag-error.stderr2
-rw-r--r--src/test/rustdoc-ui/no-run-flag.rs38
-rw-r--r--src/test/rustdoc-ui/no-run-flag.stdout12
-rw-r--r--src/test/rustdoc-ui/nocapture-fail.rs12
-rw-r--r--src/test/rustdoc-ui/nocapture-fail.stderr18
-rw-r--r--src/test/rustdoc-ui/nocapture-fail.stdout6
-rw-r--r--src/test/rustdoc-ui/nocapture.rs10
-rw-r--r--src/test/rustdoc-ui/nocapture.stderr1
-rw-r--r--src/test/rustdoc-ui/nocapture.stdout7
-rw-r--r--src/test/rustdoc-ui/normalize-cycle.rs25
-rw-r--r--src/test/rustdoc-ui/normalize-overflow.rs3
-rw-r--r--src/test/rustdoc-ui/output-format-html-stable.rs4
-rw-r--r--src/test/rustdoc-ui/private-doc-test.rs12
-rw-r--r--src/test/rustdoc-ui/private-item-doc-test.rs11
-rw-r--r--src/test/rustdoc-ui/private-item-doc-test.stderr18
-rw-r--r--src/test/rustdoc-ui/private-public-item-doc-test.rs11
-rw-r--r--src/test/rustdoc-ui/private-public-item-doc-test.stderr18
-rw-r--r--src/test/rustdoc-ui/pub-export-lint.rs5
-rw-r--r--src/test/rustdoc-ui/pub-export-lint.stderr15
-rw-r--r--src/test/rustdoc-ui/public-reexported-item-doc-test.rs16
-rw-r--r--src/test/rustdoc-ui/range-pattern.rs3
-rw-r--r--src/test/rustdoc-ui/recursive-deref-ice.rs19
-rw-r--r--src/test/rustdoc-ui/reference-link-reports-error-once.rs20
-rw-r--r--src/test/rustdoc-ui/reference-link-reports-error-once.stderr63
-rw-r--r--src/test/rustdoc-ui/reference-links.rs6
-rw-r--r--src/test/rustdoc-ui/reference-links.stderr14
-rw-r--r--src/test/rustdoc-ui/renamed-lint-still-applies.rs10
-rw-r--r--src/test/rustdoc-ui/renamed-lint-still-applies.stderr42
-rw-r--r--src/test/rustdoc-ui/run-directory.correct.stdout6
-rw-r--r--src/test/rustdoc-ui/run-directory.incorrect.stdout6
-rw-r--r--src/test/rustdoc-ui/run-directory.rs23
-rw-r--r--src/test/rustdoc-ui/rustc-check-passes.rs4
-rw-r--r--src/test/rustdoc-ui/rustc-check-passes.stderr9
-rw-r--r--src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs7
-rw-r--r--src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr14
-rw-r--r--src/test/rustdoc-ui/scrape-examples-ice.rs4
-rw-r--r--src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs1
-rw-r--r--src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr2
-rw-r--r--src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs1
-rw-r--r--src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr2
-rw-r--r--src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs11
-rw-r--r--src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs38
-rw-r--r--src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr38
-rw-r--r--src/test/rustdoc-ui/suggestions/html-as-generics.fixed32
-rw-r--r--src/test/rustdoc-ui/suggestions/html-as-generics.rs32
-rw-r--r--src/test/rustdoc-ui/suggestions/html-as-generics.stderr73
-rw-r--r--src/test/rustdoc-ui/test-compile-fail1.rs8
-rw-r--r--src/test/rustdoc-ui/test-compile-fail1.stderr14
-rw-r--r--src/test/rustdoc-ui/test-compile-fail2.rs3
-rw-r--r--src/test/rustdoc-ui/test-compile-fail2.stderr8
-rw-r--r--src/test/rustdoc-ui/test-compile-fail3.rs3
-rw-r--r--src/test/rustdoc-ui/test-compile-fail3.stderr9
-rw-r--r--src/test/rustdoc-ui/test-no_std.rs13
-rw-r--r--src/test/rustdoc-ui/test-no_std.stdout6
-rw-r--r--src/test/rustdoc-ui/test-type.rs26
-rw-r--r--src/test/rustdoc-ui/test-type.stdout10
-rw-r--r--src/test/rustdoc-ui/tuple-variadic-check.rs15
-rw-r--r--src/test/rustdoc-ui/tuple-variadic-check.stderr8
-rw-r--r--src/test/rustdoc-ui/unknown-renamed-lints.rs24
-rw-r--r--src/test/rustdoc-ui/unknown-renamed-lints.stderr64
-rw-r--r--src/test/rustdoc-ui/unparseable-doc-test.rs11
-rw-r--r--src/test/rustdoc-ui/unparseable-doc-test.stdout23
-rw-r--r--src/test/rustdoc-ui/unused-braces-lint.rs14
-rw-r--r--src/test/rustdoc-ui/unused-extern-crate.rs3
-rw-r--r--src/test/rustdoc-ui/unused.rs14
-rw-r--r--src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs1
-rw-r--r--src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr2
-rw-r--r--src/test/rustdoc-ui/wasm-safe.rs5
-rw-r--r--src/test/rustdoc-ui/z-help.rs6
-rw-r--r--src/test/rustdoc-ui/z-help.stdout200
-rw-r--r--src/test/rustdoc/all.rs28
-rw-r--r--src/test/rustdoc/anchors.no_const_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_const_anchor2.html1
-rw-r--r--src/test/rustdoc/anchors.no_method_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_trait_method_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_tymethod_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_type_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_type_anchor2.html1
-rw-r--r--src/test/rustdoc/anchors.rs49
-rw-r--r--src/test/rustdoc/anonymous-lifetime.rs28
-rw-r--r--src/test/rustdoc/anonymous-reexport.rs22
-rw-r--r--src/test/rustdoc/asm-foreign.rs20
-rw-r--r--src/test/rustdoc/asm-foreign2.rs11
-rw-r--r--src/test/rustdoc/assoc-consts-version.rs15
-rw-r--r--src/test/rustdoc/assoc-consts.rs103
-rw-r--r--src/test/rustdoc/assoc-item-cast.rs14
-rw-r--r--src/test/rustdoc/assoc-types.rs37
-rw-r--r--src/test/rustdoc/associated-consts.rs51
-rw-r--r--src/test/rustdoc/async-fn.rs95
-rw-r--r--src/test/rustdoc/async-move-doctest.rs12
-rw-r--r--src/test/rustdoc/attribute-rendering.rs7
-rw-r--r--src/test/rustdoc/attributes.rs13
-rw-r--r--src/test/rustdoc/auto-impl-for-trait.rs16
-rw-r--r--src/test/rustdoc/auto-impl-primitive.rs10
-rw-r--r--src/test/rustdoc/auto-trait-not-send.rs8
-rw-r--r--src/test/rustdoc/auto-traits.rs13
-rw-r--r--src/test/rustdoc/auto_aliases.rs6
-rw-r--r--src/test/rustdoc/auxiliary/all-item-types.rs22
-rw-r--r--src/test/rustdoc/auxiliary/auto-traits.rs3
-rw-r--r--src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs19
-rw-r--r--src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs5
-rw-r--r--src/test/rustdoc/auxiliary/elided-lifetime.rs11
-rw-r--r--src/test/rustdoc/auxiliary/empty.rs1
-rw-r--r--src/test/rustdoc/auxiliary/enum-primitive.rs207
-rw-r--r--src/test/rustdoc/auxiliary/extern-impl-trait.rs27
-rw-r--r--src/test/rustdoc/auxiliary/extern-links.rs1
-rw-r--r--src/test/rustdoc/auxiliary/external-cross-doc.md4
-rw-r--r--src/test/rustdoc/auxiliary/external-cross.rs3
-rw-r--r--src/test/rustdoc/auxiliary/external-doc.md3
-rw-r--r--src/test/rustdoc/auxiliary/external-macro-src.rs15
-rw-r--r--src/test/rustdoc/auxiliary/html_root.rs2
-rw-r--r--src/test/rustdoc/auxiliary/inline-default-methods.rs6
-rw-r--r--src/test/rustdoc/auxiliary/issue-100204-aux.rs13
-rw-r--r--src/test/rustdoc/auxiliary/issue-13698.rs8
-rw-r--r--src/test/rustdoc/auxiliary/issue-15318.rs16
-rw-r--r--src/test/rustdoc/auxiliary/issue-17476.rs7
-rw-r--r--src/test/rustdoc/auxiliary/issue-19190-3.rs23
-rw-r--r--src/test/rustdoc/auxiliary/issue-20646.rs7
-rw-r--r--src/test/rustdoc/auxiliary/issue-20727.rs30
-rw-r--r--src/test/rustdoc/auxiliary/issue-21092.rs12
-rw-r--r--src/test/rustdoc/auxiliary/issue-21801.rs9
-rw-r--r--src/test/rustdoc/auxiliary/issue-22025.rs10
-rw-r--r--src/test/rustdoc/auxiliary/issue-23207-1.rs3
-rw-r--r--src/test/rustdoc/auxiliary/issue-23207-2.rs5
-rw-r--r--src/test/rustdoc/auxiliary/issue-26606-macro.rs4
-rw-r--r--src/test/rustdoc/auxiliary/issue-27362-aux.rs10
-rw-r--r--src/test/rustdoc/auxiliary/issue-28927-1.rs4
-rw-r--r--src/test/rustdoc/auxiliary/issue-28927-2.rs1
-rw-r--r--src/test/rustdoc/auxiliary/issue-29584.rs10
-rw-r--r--src/test/rustdoc/auxiliary/issue-30109-1.rs1
-rw-r--r--src/test/rustdoc/auxiliary/issue-34274.rs3
-rw-r--r--src/test/rustdoc/auxiliary/issue-36031.rs9
-rw-r--r--src/test/rustdoc/auxiliary/issue-40936.rs5
-rw-r--r--src/test/rustdoc/auxiliary/issue-46727.rs7
-rw-r--r--src/test/rustdoc/auxiliary/issue-48414.rs5
-rw-r--r--src/test/rustdoc/auxiliary/issue-53689.rs1
-rw-r--r--src/test/rustdoc/auxiliary/issue-57180.rs16
-rw-r--r--src/test/rustdoc/auxiliary/issue-61592.rs4
-rw-r--r--src/test/rustdoc/auxiliary/issue-73061.rs17
-rw-r--r--src/test/rustdoc/auxiliary/issue-85454.rs17
-rw-r--r--src/test/rustdoc/auxiliary/issue-86620-1.rs11
-rw-r--r--src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs17
-rw-r--r--src/test/rustdoc/auxiliary/issue-99221-aux.rs20
-rw-r--r--src/test/rustdoc/auxiliary/issue-99734-aux.rs11
-rw-r--r--src/test/rustdoc/auxiliary/macro_pub_in_module.rs13
-rw-r--r--src/test/rustdoc/auxiliary/masked.rs10
-rw-r--r--src/test/rustdoc/auxiliary/mod-stackoverflow.rs11
-rw-r--r--src/test/rustdoc/auxiliary/no_html_root.rs1
-rw-r--r--src/test/rustdoc/auxiliary/normalize-assoc-item.rs12
-rw-r--r--src/test/rustdoc/auxiliary/primitive-doc.rs9
-rw-r--r--src/test/rustdoc/auxiliary/primitive-reexport.rs8
-rw-r--r--src/test/rustdoc/auxiliary/pub-extern-crate.rs2
-rw-r--r--src/test/rustdoc/auxiliary/pub-use-extern-macros.rs21
-rw-r--r--src/test/rustdoc/auxiliary/real_gimli.rs13
-rw-r--r--src/test/rustdoc/auxiliary/realcore.rs15
-rw-r--r--src/test/rustdoc/auxiliary/reexp-stripped.rs11
-rw-r--r--src/test/rustdoc/auxiliary/reexport-check.rs2
-rw-r--r--src/test/rustdoc/auxiliary/reexports.rs66
-rw-r--r--src/test/rustdoc/auxiliary/rustdoc-default-impl.rs23
-rw-r--r--src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs11
-rw-r--r--src/test/rustdoc/auxiliary/rustdoc-extern-method.rs7
-rw-r--r--src/test/rustdoc/auxiliary/rustdoc-ffi.rs6
-rw-r--r--src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs3
-rw-r--r--src/test/rustdoc/auxiliary/source-code-bar.rs17
-rw-r--r--src/test/rustdoc/auxiliary/source_code.rs1
-rw-r--r--src/test/rustdoc/auxiliary/src-links-external.rs1
-rw-r--r--src/test/rustdoc/auxiliary/trait-alias-mention.rs3
-rw-r--r--src/test/rustdoc/auxiliary/trait-visibility.rs3
-rw-r--r--src/test/rustdoc/auxiliary/unit-return.rs3
-rw-r--r--src/test/rustdoc/auxiliary/unstable-trait.rs26
-rw-r--r--src/test/rustdoc/auxiliary/variant-struct.rs5
-rw-r--r--src/test/rustdoc/bad-codeblock-syntax.rs44
-rw-r--r--src/test/rustdoc/blanket-reexport-item.rs8
-rw-r--r--src/test/rustdoc/cap-lints.rs9
-rw-r--r--src/test/rustdoc/cfg-doctest.rs6
-rw-r--r--src/test/rustdoc/check-source-code-urls-to-def-std.rs42
-rw-r--r--src/test/rustdoc/check-source-code-urls-to-def.rs69
-rw-r--r--src/test/rustdoc/check-styled-link.rs8
-rw-r--r--src/test/rustdoc/check.rs5
-rw-r--r--src/test/rustdoc/codeblock-title.rs25
-rw-r--r--src/test/rustdoc/comment-in-doctest.rs20
-rw-r--r--src/test/rustdoc/const-display.rs86
-rw-r--r--src/test/rustdoc/const-doc.rs19
-rw-r--r--src/test/rustdoc/const-evalutation-ice.rs10
-rw-r--r--src/test/rustdoc/const-fn.rs16
-rw-r--r--src/test/rustdoc/const-generics/add-impl.rs17
-rw-r--r--src/test/rustdoc/const-generics/auxiliary/extern_crate.rs16
-rw-r--r--src/test/rustdoc/const-generics/const-generic-defaults.rs5
-rw-r--r--src/test/rustdoc/const-generics/const-generic-slice.rs11
-rw-r--r--src/test/rustdoc/const-generics/const-generics-docs.rs128
-rw-r--r--src/test/rustdoc/const-generics/const-impl.rs37
-rw-r--r--src/test/rustdoc/const-generics/generic_const_exprs.rs7
-rw-r--r--src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs18
-rw-r--r--src/test/rustdoc/const-generics/type-alias.rs4
-rw-r--r--src/test/rustdoc/const-underscore.rs7
-rw-r--r--src/test/rustdoc/const-value-display.rs9
-rw-r--r--src/test/rustdoc/const.rs10
-rw-r--r--src/test/rustdoc/constructor-imports.rs15
-rw-r--r--src/test/rustdoc/crate-version-escape.rs5
-rw-r--r--src/test/rustdoc/crate-version.rs3
-rw-r--r--src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs23
-rw-r--r--src/test/rustdoc/cross-crate-hidden-impl-parameter.rs35
-rw-r--r--src/test/rustdoc/cross-crate-links.rs59
-rw-r--r--src/test/rustdoc/cross-crate-primitive-doc.rs13
-rw-r--r--src/test/rustdoc/decl-trailing-whitespace.declaration.html7
-rw-r--r--src/test/rustdoc/decl-trailing-whitespace.rs30
-rw-r--r--src/test/rustdoc/decl_macro.rs56
-rw-r--r--src/test/rustdoc/decl_macro_priv.rs14
-rw-r--r--src/test/rustdoc/deep-structures.rs104
-rw-r--r--src/test/rustdoc/default-impl.rs9
-rw-r--r--src/test/rustdoc/default-theme.rs7
-rw-r--r--src/test/rustdoc/default-trait-method-link.rs15
-rw-r--r--src/test/rustdoc/default-trait-method.rs26
-rw-r--r--src/test/rustdoc/deprecated-future-staged-api.rs18
-rw-r--r--src/test/rustdoc/deprecated-future.rs6
-rw-r--r--src/test/rustdoc/deprecated-impls.rs118
-rw-r--r--src/test/rustdoc/deprecated.rs33
-rw-r--r--src/test/rustdoc/deref-const-fn.rs38
-rw-r--r--src/test/rustdoc/deref-mut-methods.rs29
-rw-r--r--src/test/rustdoc/deref-recursive-pathbuf.rs25
-rw-r--r--src/test/rustdoc/deref-recursive.rs41
-rw-r--r--src/test/rustdoc/deref-slice-core.rs22
-rw-r--r--src/test/rustdoc/deref-typedef.rs46
-rw-r--r--src/test/rustdoc/description.rs24
-rw-r--r--src/test/rustdoc/description_default.rs14
-rw-r--r--src/test/rustdoc/doc-assoc-item.rs18
-rw-r--r--src/test/rustdoc/doc-auto-cfg.rs35
-rw-r--r--src/test/rustdoc/doc-cfg-hide.rs32
-rw-r--r--src/test/rustdoc/doc-cfg-implicit-gate.rs7
-rw-r--r--src/test/rustdoc/doc-cfg-implicit.rs31
-rw-r--r--src/test/rustdoc/doc-cfg-simplification.rs182
-rw-r--r--src/test/rustdoc/doc-cfg-target-feature.rs21
-rw-r--r--src/test/rustdoc/doc-cfg-traits.rs124
-rw-r--r--src/test/rustdoc/doc-cfg.rs101
-rw-r--r--src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs23
-rw-r--r--src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs21
-rw-r--r--src/test/rustdoc/doc-notable_trait-slice.rs20
-rw-r--r--src/test/rustdoc/doc-notable_trait.rs36
-rw-r--r--src/test/rustdoc/doc-proc-macro.rs8
-rw-r--r--src/test/rustdoc/doctest-manual-crate-name.rs7
-rw-r--r--src/test/rustdoc/double-quote-escape.rs11
-rw-r--r--src/test/rustdoc/duplicate-cfg.rs53
-rw-r--r--src/test/rustdoc/duplicate-flags.rs4
-rw-r--r--src/test/rustdoc/duplicate_impls/impls.rs12
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs14
-rw-r--r--src/test/rustdoc/duplicated_impl.rs14
-rw-r--r--src/test/rustdoc/early-unindent.rs26
-rw-r--r--src/test/rustdoc/edition-doctest.rs44
-rw-r--r--src/test/rustdoc/edition-flag.rs11
-rw-r--r--src/test/rustdoc/elided-lifetime.rs43
-rw-r--r--src/test/rustdoc/empty-doc-comment.rs22
-rw-r--r--src/test/rustdoc/empty-impl-block.rs20
-rw-r--r--src/test/rustdoc/empty-impls.rs19
-rw-r--r--src/test/rustdoc/empty-mod-private.rs16
-rw-r--r--src/test/rustdoc/empty-mod-public.rs14
-rw-r--r--src/test/rustdoc/empty-section.rs13
-rw-r--r--src/test/rustdoc/ensure-src-link.rs6
-rw-r--r--src/test/rustdoc/enum-headings.rs40
-rw-r--r--src/test/rustdoc/escape-deref-methods.rs35
-rw-r--r--src/test/rustdoc/extern-default-method.no_href_on_anchor.html1
-rw-r--r--src/test/rustdoc/extern-default-method.rs23
-rw-r--r--src/test/rustdoc/extern-html-root-url-precedence.rs7
-rw-r--r--src/test/rustdoc/extern-html-root-url.rs18
-rw-r--r--src/test/rustdoc/extern-impl-trait.rs11
-rw-r--r--src/test/rustdoc/extern-impl.rs27
-rw-r--r--src/test/rustdoc/extern-links.rs21
-rw-r--r--src/test/rustdoc/extern-method.rs19
-rw-r--r--src/test/rustdoc/external-cross.rs10
-rw-r--r--src/test/rustdoc/external-doc.rs14
-rw-r--r--src/test/rustdoc/external-macro-src.rs12
-rw-r--r--src/test/rustdoc/feature-gate-doc_auto_cfg.rs8
-rw-r--r--src/test/rustdoc/ffi.rs12
-rw-r--r--src/test/rustdoc/fn-bound.rs21
-rw-r--r--src/test/rustdoc/fn-pointer-arg-name.rs5
-rw-r--r--src/test/rustdoc/fn-sidebar.rs9
-rw-r--r--src/test/rustdoc/fn-type.rs13
-rw-r--r--src/test/rustdoc/force-target-feature.rs11
-rw-r--r--src/test/rustdoc/foreigntype-reexport.rs56
-rw-r--r--src/test/rustdoc/foreigntype.rs18
-rw-r--r--src/test/rustdoc/generic-associated-types/gats.rs34
-rw-r--r--src/test/rustdoc/generic-associated-types/issue-94683.rs13
-rw-r--r--src/test/rustdoc/generic-impl.rs16
-rw-r--r--src/test/rustdoc/generic_const_exprs.rs24
-rw-r--r--src/test/rustdoc/hidden-impls.rs17
-rw-r--r--src/test/rustdoc/hidden-line.rs19
-rw-r--r--src/test/rustdoc/hidden-methods.rs29
-rw-r--r--src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs31
-rw-r--r--src/test/rustdoc/hidden-trait-methods.rs29
-rw-r--r--src/test/rustdoc/hidden-trait-struct-impls.rs22
-rw-r--r--src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs82
-rw-r--r--src/test/rustdoc/hide-complex-unevaluated-consts.rs71
-rw-r--r--src/test/rustdoc/hide-unstable-trait.rs11
-rw-r--r--src/test/rustdoc/higher-ranked-trait-bounds.rs61
-rw-r--r--src/test/rustdoc/impl-box.rs16
-rw-r--r--src/test/rustdoc/impl-disambiguation.rs30
-rw-r--r--src/test/rustdoc/impl-everywhere.rs30
-rw-r--r--src/test/rustdoc/impl-parts-crosscrate.rs20
-rw-r--r--src/test/rustdoc/impl-parts.rs12
-rw-r--r--src/test/rustdoc/impl-trait-alias.rs14
-rw-r--r--src/test/rustdoc/implementor-stable-version.rs21
-rw-r--r--src/test/rustdoc/include_str_cut.rs7
-rw-r--r--src/test/rustdoc/index-page.rs11
-rw-r--r--src/test/rustdoc/infinite-redirection.rs29
-rw-r--r--src/test/rustdoc/inline-default-methods.rs9
-rw-r--r--src/test/rustdoc/inline_cross/add-docs.rs9
-rw-r--r--src/test/rustdoc/inline_cross/assoc-items.rs42
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/add-docs.rs4
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs38
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs5
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs16
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs8
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs28
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs18
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs7
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs25
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/macros.rs10
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs47
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs9
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs12
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs4
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs34
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs13
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs13
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/use_crate.rs5
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs1
-rw-r--r--src/test/rustdoc/inline_cross/cross-glob.rs11
-rw-r--r--src/test/rustdoc/inline_cross/default-trait-method.rs20
-rw-r--r--src/test/rustdoc/inline_cross/hidden-use.rs12
-rw-r--r--src/test/rustdoc/inline_cross/impl-inline-without-trait.rs12
-rw-r--r--src/test/rustdoc/inline_cross/impl_trait.rs40
-rw-r--r--src/test/rustdoc/inline_cross/implementors-js.rs25
-rw-r--r--src/test/rustdoc/inline_cross/inline_hidden.rs12
-rw-r--r--src/test/rustdoc/inline_cross/issue-28480.rs13
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-1.rs27
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-2.rs21
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948.rs29
-rw-r--r--src/test/rustdoc/inline_cross/issue-32881.rs11
-rw-r--r--src/test/rustdoc/inline_cross/issue-33113.rs10
-rw-r--r--src/test/rustdoc/inline_cross/macro-vis.rs36
-rw-r--r--src/test/rustdoc/inline_cross/macros.rs19
-rw-r--r--src/test/rustdoc/inline_cross/proc_macro.rs36
-rw-r--r--src/test/rustdoc/inline_cross/renamed-via-module.rs24
-rw-r--r--src/test/rustdoc/inline_cross/trait-vis.rs7
-rw-r--r--src/test/rustdoc/inline_cross/use_crate.rs27
-rw-r--r--src/test/rustdoc/inline_local/glob-extern-document-private-items.rs25
-rw-r--r--src/test/rustdoc/inline_local/glob-extern.rs21
-rw-r--r--src/test/rustdoc/inline_local/glob-private-document-private-items.rs48
-rw-r--r--src/test/rustdoc/inline_local/glob-private.rs42
-rw-r--r--src/test/rustdoc/inline_local/hidden-use.rs10
-rw-r--r--src/test/rustdoc/inline_local/issue-28537.rs17
-rw-r--r--src/test/rustdoc/inline_local/issue-32343.rs23
-rw-r--r--src/test/rustdoc/inline_local/macro_by_example.rs17
-rw-r--r--src/test/rustdoc/inline_local/please_inline.rs19
-rw-r--r--src/test/rustdoc/inline_local/trait-vis.rs18
-rw-r--r--src/test/rustdoc/internal.rs16
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/self.rs10
-rw-r--r--src/test/rustdoc/intra-doc-crate/self.rs9
-rw-r--r--src/test/rustdoc/intra-doc/anchors.rs24
-rw-r--r--src/test/rustdoc/intra-doc/associated-defaults.rs26
-rw-r--r--src/test/rustdoc/intra-doc/associated-items.rs68
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/empty.rs1
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/empty2.rs1
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs28
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs11
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs3
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs4
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs6
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs6
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs2
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/my-core.rs23
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs34
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs1
-rw-r--r--src/test/rustdoc/intra-doc/basic.rs84
-rw-r--r--src/test/rustdoc/intra-doc/builtin-macros.rs3
-rw-r--r--src/test/rustdoc/intra-doc/crate-relative-assoc.rs17
-rw-r--r--src/test/rustdoc/intra-doc/crate-relative.rs13
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs6
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs19
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs7
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs5
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs7
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs20
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs12
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs13
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs16
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/basic.rs9
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/crate.rs6
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/hidden.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/macro.rs11
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/module.rs8
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs8
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs16
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/traits.rs14
-rw-r--r--src/test/rustdoc/intra-doc/disambiguators-removed.rs50
-rw-r--r--src/test/rustdoc/intra-doc/email-address.rs10
-rw-r--r--src/test/rustdoc/intra-doc/enum-struct-field.rs14
-rw-r--r--src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs11
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs19
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate.rs9
-rw-r--r--src/test/rustdoc/intra-doc/extern-inherent-impl.rs8
-rw-r--r--src/test/rustdoc/intra-doc/extern-reference-link.rs7
-rw-r--r--src/test/rustdoc/intra-doc/extern-type.rs37
-rw-r--r--src/test/rustdoc/intra-doc/external-traits.rs12
-rw-r--r--src/test/rustdoc/intra-doc/field.rs4
-rw-r--r--src/test/rustdoc/intra-doc/generic-params.rs62
-rw-r--r--src/test/rustdoc/intra-doc/generic-trait-impl.rs20
-rw-r--r--src/test/rustdoc/intra-doc/in-bodies.rs30
-rw-r--r--src/test/rustdoc/intra-doc/issue-66159.rs10
-rw-r--r--src/test/rustdoc/intra-doc/issue-82209.rs11
-rw-r--r--src/test/rustdoc/intra-doc/libstd-re-export.rs4
-rw-r--r--src/test/rustdoc/intra-doc/macros-disambiguators.rs25
-rw-r--r--src/test/rustdoc/intra-doc/mod-ambiguity.rs16
-rw-r--r--src/test/rustdoc/intra-doc/mod-relative.rs17
-rw-r--r--src/test/rustdoc/intra-doc/non-path-primitives.rs46
-rw-r--r--src/test/rustdoc/intra-doc/prim-assoc.rs4
-rw-r--r--src/test/rustdoc/intra-doc/prim-associated-traits.rs46
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-external-core.rs17
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-local.rs29
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods.rs7
-rw-r--r--src/test/rustdoc/intra-doc/prim-precedence.rs16
-rw-r--r--src/test/rustdoc/intra-doc/prim-self.rs41
-rw-r--r--src/test/rustdoc/intra-doc/primitive-disambiguators.rs4
-rw-r--r--src/test/rustdoc/intra-doc/primitive-non-default-impl.rs31
-rw-r--r--src/test/rustdoc/intra-doc/private-failures-ignored.rs8
-rw-r--r--src/test/rustdoc/intra-doc/private.rs20
-rw-r--r--src/test/rustdoc/intra-doc/proc-macro.rs27
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs17
-rw-r--r--src/test/rustdoc/intra-doc/raw-ident-self.rs13
-rw-r--r--src/test/rustdoc/intra-doc/reexport-additional-docs.rs23
-rw-r--r--src/test/rustdoc/intra-doc/self-cache.rs14
-rw-r--r--src/test/rustdoc/intra-doc/self.rs116
-rw-r--r--src/test/rustdoc/intra-doc/trait-impl.rs34
-rw-r--r--src/test/rustdoc/intra-doc/trait-item.rs11
-rw-r--r--src/test/rustdoc/intra-doc/true-false.rs8
-rw-r--r--src/test/rustdoc/intra-doc/type-alias.rs19
-rw-r--r--src/test/rustdoc/invalid.crate.name.rs3
-rw-r--r--src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs14
-rw-r--r--src/test/rustdoc/issue-12834.rs12
-rw-r--r--src/test/rustdoc/issue-13698.rs16
-rw-r--r--src/test/rustdoc/issue-15169.rs3
-rw-r--r--src/test/rustdoc/issue-15318-2.rs12
-rw-r--r--src/test/rustdoc/issue-15318-3.rs7
-rw-r--r--src/test/rustdoc/issue-15318.rs11
-rw-r--r--src/test/rustdoc/issue-15347.rs5
-rw-r--r--src/test/rustdoc/issue-16019.rs9
-rw-r--r--src/test/rustdoc/issue-16265-1.rs10
-rw-r--r--src/test/rustdoc/issue-16265-2.rs4
-rw-r--r--src/test/rustdoc/issue-17476.rs11
-rw-r--r--src/test/rustdoc/issue-18199.rs9
-rw-r--r--src/test/rustdoc/issue-19181.rs5
-rw-r--r--src/test/rustdoc/issue-19190-2.rs12
-rw-r--r--src/test/rustdoc/issue-19190-3.rs27
-rw-r--r--src/test/rustdoc/issue-19190.rs20
-rw-r--r--src/test/rustdoc/issue-20175.rs10
-rw-r--r--src/test/rustdoc/issue-20646.rs26
-rw-r--r--src/test/rustdoc/issue-20727-2.rs22
-rw-r--r--src/test/rustdoc/issue-20727-3.rs24
-rw-r--r--src/test/rustdoc/issue-20727-4.rs40
-rw-r--r--src/test/rustdoc/issue-20727.rs24
-rw-r--r--src/test/rustdoc/issue-21092.rs8
-rw-r--r--src/test/rustdoc/issue-21474.rs11
-rw-r--r--src/test/rustdoc/issue-21801.rs9
-rw-r--r--src/test/rustdoc/issue-22025.rs6
-rw-r--r--src/test/rustdoc/issue-22038.rs19
-rw-r--r--src/test/rustdoc/issue-23106.rs7
-rw-r--r--src/test/rustdoc/issue-23207.rs9
-rw-r--r--src/test/rustdoc/issue-23511.rs13
-rw-r--r--src/test/rustdoc/issue-23744.rs12
-rw-r--r--src/test/rustdoc/issue-23812.rs36
-rw-r--r--src/test/rustdoc/issue-25001.rs43
-rw-r--r--src/test/rustdoc/issue-25944.rs11
-rw-r--r--src/test/rustdoc/issue-26606.rs11
-rw-r--r--src/test/rustdoc/issue-26995.rs7
-rw-r--r--src/test/rustdoc/issue-27104.rs10
-rw-r--r--src/test/rustdoc/issue-27362.rs10
-rw-r--r--src/test/rustdoc/issue-27759.rs14
-rw-r--r--src/test/rustdoc/issue-27862.rs4
-rw-r--r--src/test/rustdoc/issue-28478.rs31
-rw-r--r--src/test/rustdoc/issue-28927.rs6
-rw-r--r--src/test/rustdoc/issue-29449.rs20
-rw-r--r--src/test/rustdoc/issue-29503.rs18
-rw-r--r--src/test/rustdoc/issue-29584.rs8
-rw-r--r--src/test/rustdoc/issue-30109.rs14
-rw-r--r--src/test/rustdoc/issue-30252.rs6
-rw-r--r--src/test/rustdoc/issue-30366.rs6
-rw-r--r--src/test/rustdoc/issue-31808.rs11
-rw-r--r--src/test/rustdoc/issue-31899.rs59
-rw-r--r--src/test/rustdoc/issue-32374.rs27
-rw-r--r--src/test/rustdoc/issue-32395.rs15
-rw-r--r--src/test/rustdoc/issue-32556.rs5
-rw-r--r--src/test/rustdoc/issue-32890.rs17
-rw-r--r--src/test/rustdoc/issue-33069.rs10
-rw-r--r--src/test/rustdoc/issue-33178-1.rs10
-rw-r--r--src/test/rustdoc/issue-33178.rs13
-rw-r--r--src/test/rustdoc/issue-33302.rs51
-rw-r--r--src/test/rustdoc/issue-33592.rs13
-rw-r--r--src/test/rustdoc/issue-34025.rs12
-rw-r--r--src/test/rustdoc/issue-34274.rs10
-rw-r--r--src/test/rustdoc/issue-34423.rs10
-rw-r--r--src/test/rustdoc/issue-34473.rs11
-rw-r--r--src/test/rustdoc/issue-34928.rs6
-rw-r--r--src/test/rustdoc/issue-35169-2.rs40
-rw-r--r--src/test/rustdoc/issue-35169.rs35
-rw-r--r--src/test/rustdoc/issue-35488.rs13
-rw-r--r--src/test/rustdoc/issue-36031.rs9
-rw-r--r--src/test/rustdoc/issue-38129.rs99
-rw-r--r--src/test/rustdoc/issue-38219.rs8
-rw-r--r--src/test/rustdoc/issue-40936.rs6
-rw-r--r--src/test/rustdoc/issue-41783.rs19
-rw-r--r--src/test/rustdoc/issue-42760.rs15
-rw-r--r--src/test/rustdoc/issue-43153.rs10
-rw-r--r--src/test/rustdoc/issue-43701.rs5
-rw-r--r--src/test/rustdoc/issue-43869.rs72
-rw-r--r--src/test/rustdoc/issue-43893.rs19
-rw-r--r--src/test/rustdoc/issue-45584.rs15
-rw-r--r--src/test/rustdoc/issue-46271.rs5
-rw-r--r--src/test/rustdoc/issue-46377.rs3
-rw-r--r--src/test/rustdoc/issue-46380-2.rs9
-rw-r--r--src/test/rustdoc/issue-46727.rs7
-rw-r--r--src/test/rustdoc/issue-46766.rs6
-rw-r--r--src/test/rustdoc/issue-46767.rs9
-rw-r--r--src/test/rustdoc/issue-46976.rs1
-rw-r--r--src/test/rustdoc/issue-47038.rs10
-rw-r--r--src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs8
-rw-r--r--src/test/rustdoc/issue-47639.rs6
-rw-r--r--src/test/rustdoc/issue-48377.rs13
-rw-r--r--src/test/rustdoc/issue-48414.rs11
-rw-r--r--src/test/rustdoc/issue-50159.rs20
-rw-r--r--src/test/rustdoc/issue-51236.rs14
-rw-r--r--src/test/rustdoc/issue-52873.rs171
-rw-r--r--src/test/rustdoc/issue-53689.rs16
-rw-r--r--src/test/rustdoc/issue-53812.rs20
-rw-r--r--src/test/rustdoc/issue-54478-demo-allocator.rs42
-rw-r--r--src/test/rustdoc/issue-54705.rs29
-rw-r--r--src/test/rustdoc/issue-55001.rs31
-rw-r--r--src/test/rustdoc/issue-55321.rs18
-rw-r--r--src/test/rustdoc/issue-55364.rs86
-rw-r--r--src/test/rustdoc/issue-56701.rs33
-rw-r--r--src/test/rustdoc/issue-56822.rs24
-rw-r--r--src/test/rustdoc/issue-57180.rs7
-rw-r--r--src/test/rustdoc/issue-60482.rs9
-rw-r--r--src/test/rustdoc/issue-60726.rs35
-rw-r--r--src/test/rustdoc/issue-61592.rs15
-rw-r--r--src/test/rustdoc/issue-67851-both.rs8
-rw-r--r--src/test/rustdoc/issue-67851-hidden.rs8
-rw-r--r--src/test/rustdoc/issue-67851-neither.rs6
-rw-r--r--src/test/rustdoc/issue-67851-private.rs8
-rw-r--r--src/test/rustdoc/issue-72340.rs19
-rw-r--r--src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs14
-rw-r--r--src/test/rustdoc/issue-74083.rs21
-rw-r--r--src/test/rustdoc/issue-75588.rs17
-rw-r--r--src/test/rustdoc/issue-76501.rs17
-rw-r--r--src/test/rustdoc/issue-78673.rs24
-rw-r--r--src/test/rustdoc/issue-78701.rs20
-rw-r--r--src/test/rustdoc/issue-79201.rs41
-rw-r--r--src/test/rustdoc/issue-80233-normalize-auto-trait.rs37
-rw-r--r--src/test/rustdoc/issue-82465-asref-for-and-of-local.rs16
-rw-r--r--src/test/rustdoc/issue-85454.rs29
-rw-r--r--src/test/rustdoc/issue-86620.rs9
-rw-r--r--src/test/rustdoc/issue-88600.rs35
-rw-r--r--src/test/rustdoc/issue-89309-heading-levels.rs29
-rw-r--r--src/test/rustdoc/issue-89852.rs14
-rw-r--r--src/test/rustdoc/issue-95633.rs7
-rw-r--r--src/test/rustdoc/issue-95873.rs2
-rw-r--r--src/test/rustdoc/issue-96381.rs16
-rw-r--r--src/test/rustdoc/issue-98697.rs17
-rw-r--r--src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs19
-rw-r--r--src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs17
-rw-r--r--src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs14
-rw-r--r--src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs16
-rw-r--r--src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs14
-rw-r--r--src/test/rustdoc/keyword.rs23
-rw-r--r--src/test/rustdoc/legacy-const-generic.rs16
-rw-r--r--src/test/rustdoc/lifetime-name.rs5
-rw-r--r--src/test/rustdoc/line-breaks.rs30
-rw-r--r--src/test/rustdoc/link-assoc-const.rs16
-rw-r--r--src/test/rustdoc/link-title-escape.rs9
-rw-r--r--src/test/rustdoc/logo-class-default.rs4
-rw-r--r--src/test/rustdoc/logo-class.rs10
-rw-r--r--src/test/rustdoc/macro-document-private-duplicate.rs25
-rw-r--r--src/test/rustdoc/macro-document-private.rs19
-rw-r--r--src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html6
-rw-r--r--src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html15
-rw-r--r--src/test/rustdoc/macro-generated-macro.rs39
-rw-r--r--src/test/rustdoc/macro-higher-kinded-function.rs21
-rw-r--r--src/test/rustdoc/macro-in-async-block.rs9
-rw-r--r--src/test/rustdoc/macro-in-closure.rs16
-rw-r--r--src/test/rustdoc/macro-indirect-use.rs16
-rw-r--r--src/test/rustdoc/macro-private-not-documented.rs19
-rw-r--r--src/test/rustdoc/macro_pub_in_module.rs82
-rw-r--r--src/test/rustdoc/macro_rules-matchers.rs39
-rw-r--r--src/test/rustdoc/macros.rs24
-rw-r--r--src/test/rustdoc/manual_impl.rs77
-rw-r--r--src/test/rustdoc/markdown-summaries.rs27
-rw-r--r--src/test/rustdoc/masked.rs30
-rw-r--r--src/test/rustdoc/method-list.rs18
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html3
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.rs25
-rw-r--r--src/test/rustdoc/mod-stackoverflow.rs6
-rw-r--r--src/test/rustdoc/module-impls.rs5
-rw-r--r--src/test/rustdoc/must_implement_one_of.rs10
-rw-r--r--src/test/rustdoc/mut-params.rs18
-rw-r--r--src/test/rustdoc/namespaces.rs16
-rw-r--r--src/test/rustdoc/negative-impl-sidebar.rs9
-rw-r--r--src/test/rustdoc/negative-impl.rs14
-rw-r--r--src/test/rustdoc/nested-modules.rs42
-rw-r--r--src/test/rustdoc/no-compiler-reexport.rs7
-rw-r--r--src/test/rustdoc/no-crate-filter.rs6
-rw-r--r--src/test/rustdoc/no-run-still-checks-lints.rs9
-rw-r--r--src/test/rustdoc/no-stack-overflow-25295.rs35
-rw-r--r--src/test/rustdoc/no_std-primitive.rs6
-rw-r--r--src/test/rustdoc/normalize-assoc-item.rs69
-rw-r--r--src/test/rustdoc/nul-error.rs8
-rw-r--r--src/test/rustdoc/playground-arg.rs13
-rw-r--r--src/test/rustdoc/playground-empty.rs13
-rw-r--r--src/test/rustdoc/playground-none.rs9
-rw-r--r--src/test/rustdoc/playground-syntax-error.rs21
-rw-r--r--src/test/rustdoc/playground.rs27
-rw-r--r--src/test/rustdoc/primitive-link.rs14
-rw-r--r--src/test/rustdoc/primitive-reexport.rs28
-rw-r--r--src/test/rustdoc/primitive-slice-auto-trait.rs14
-rw-r--r--src/test/rustdoc/primitive-tuple-auto-trait.rs22
-rw-r--r--src/test/rustdoc/primitive-tuple-variadic.rs18
-rw-r--r--src/test/rustdoc/primitive-unit-auto-trait.rs14
-rw-r--r--src/test/rustdoc/primitive.rs21
-rw-r--r--src/test/rustdoc/primitive/no_std.rs16
-rw-r--r--src/test/rustdoc/primitive/primitive-generic-impl.rs8
-rw-r--r--src/test/rustdoc/private-type-alias.rs31
-rw-r--r--src/test/rustdoc/proc-macro.rs72
-rw-r--r--src/test/rustdoc/process-termination.rs24
-rw-r--r--src/test/rustdoc/pub-extern-crate.rs9
-rw-r--r--src/test/rustdoc/pub-method.rs20
-rw-r--r--src/test/rustdoc/pub-use-extern-macros.rs17
-rw-r--r--src/test/rustdoc/range-arg-pattern.rs5
-rw-r--r--src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs21
-rw-r--r--src/test/rustdoc/recursion1.rs13
-rw-r--r--src/test/rustdoc/recursion2.rs13
-rw-r--r--src/test/rustdoc/recursion3.rs13
-rw-r--r--src/test/rustdoc/recursive-deref-sidebar.rs22
-rw-r--r--src/test/rustdoc/recursive-deref.rs120
-rw-r--r--src/test/rustdoc/redirect-const.rs13
-rw-r--r--src/test/rustdoc/redirect-map-empty.rs6
-rw-r--r--src/test/rustdoc/redirect-map.rs23
-rw-r--r--src/test/rustdoc/redirect-rename.rs34
-rw-r--r--src/test/rustdoc/redirect.rs39
-rw-r--r--src/test/rustdoc/reexport-check.rs18
-rw-r--r--src/test/rustdoc/reexport-dep-foreign-fn.rs12
-rw-r--r--src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs48
-rw-r--r--src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs61
-rw-r--r--src/test/rustdoc/reexports-priv.rs135
-rw-r--r--src/test/rustdoc/reexports.rs129
-rw-r--r--src/test/rustdoc/remove-duplicates.rs14
-rw-r--r--src/test/rustdoc/remove-url-from-headings.rs17
-rw-r--r--src/test/rustdoc/return-impl-trait.rs15
-rw-r--r--src/test/rustdoc/rfc-2632-const-trait-impl.rs70
-rw-r--r--src/test/rustdoc/rustc-macro-crate.rs14
-rw-r--r--src/test/rustdoc/safe-intrinsic.rs20
-rw-r--r--src/test/rustdoc/same-crate-hidden-impl-parameter.rs36
-rw-r--r--src/test/rustdoc/sanitizer-option.rs18
-rw-r--r--src/test/rustdoc/search-index-summaries.rs10
-rw-r--r--src/test/rustdoc/search-index.rs26
-rw-r--r--src/test/rustdoc/short-docblock-codeblock.rs12
-rw-r--r--src/test/rustdoc/short-docblock.rs25
-rw-r--r--src/test/rustdoc/short-line.md2
-rw-r--r--src/test/rustdoc/show-const-contents.rs68
-rw-r--r--src/test/rustdoc/sidebar-items.rs56
-rw-r--r--src/test/rustdoc/sidebar-link-generation.rs13
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs16
-rw-r--r--src/test/rustdoc/sized_trait.rs17
-rw-r--r--src/test/rustdoc/slice-links.link_box_generic.html1
-rw-r--r--src/test/rustdoc/slice-links.link_box_u32.html1
-rw-r--r--src/test/rustdoc/slice-links.link_slice_generic.html1
-rw-r--r--src/test/rustdoc/slice-links.link_slice_u32.html1
-rw-r--r--src/test/rustdoc/slice-links.rs28
-rw-r--r--src/test/rustdoc/smart-punct.rs28
-rw-r--r--src/test/rustdoc/smoke.rs25
-rw-r--r--src/test/rustdoc/sort-modules-by-appearance.rs13
-rw-r--r--src/test/rustdoc/source-file.rs5
-rw-r--r--src/test/rustdoc/source-version-separator.rs30
-rw-r--r--src/test/rustdoc/spotlight-from-dependency.rs24
-rw-r--r--src/test/rustdoc/src-links-auto-impls.rs12
-rw-r--r--src/test/rustdoc/src-links-external.rs13
-rw-r--r--src/test/rustdoc/src-links.rs46
-rw-r--r--src/test/rustdoc/src-links/compiletest-ignore-dir0
-rw-r--r--src/test/rustdoc/src-links/mod.rs19
-rw-r--r--src/test/rustdoc/stability.rs12
-rw-r--r--src/test/rustdoc/static-root-path.rs18
-rw-r--r--src/test/rustdoc/static.rs12
-rw-r--r--src/test/rustdoc/strip-block-doc-comments-stars.docblock.html2
-rw-r--r--src/test/rustdoc/strip-block-doc-comments-stars.rs11
-rw-r--r--src/test/rustdoc/strip-enum-variant.no-not-shown.html1
-rw-r--r--src/test/rustdoc/strip-enum-variant.rs11
-rw-r--r--src/test/rustdoc/struct-arg-pattern.rs10
-rw-r--r--src/test/rustdoc/struct-field.rs22
-rw-r--r--src/test/rustdoc/struct-implementations-title.rs9
-rw-r--r--src/test/rustdoc/structfields.rs44
-rw-r--r--src/test/rustdoc/synthetic_auto/basic.rs8
-rw-r--r--src/test/rustdoc/synthetic_auto/complex.rs42
-rw-r--r--src/test/rustdoc/synthetic_auto/crate-local.rs9
-rw-r--r--src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs25
-rw-r--r--src/test/rustdoc/synthetic_auto/lifetimes.rs19
-rw-r--r--src/test/rustdoc/synthetic_auto/manual.rs14
-rw-r--r--src/test/rustdoc/synthetic_auto/negative.rs13
-rw-r--r--src/test/rustdoc/synthetic_auto/nested.rs19
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs16
-rw-r--r--src/test/rustdoc/synthetic_auto/overflow.rs35
-rw-r--r--src/test/rustdoc/synthetic_auto/project.rs34
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs29
-rw-r--r--src/test/rustdoc/synthetic_auto/static-region.rs10
-rw-r--r--src/test/rustdoc/tab_title.rs44
-rw-r--r--src/test/rustdoc/table-in-docblock.rs16
-rw-r--r--src/test/rustdoc/task-lists.rs13
-rw-r--r--src/test/rustdoc/test-lists.rs26
-rw-r--r--src/test/rustdoc/test-parens.rs5
-rw-r--r--src/test/rustdoc/test-strikethrough.rs6
-rw-r--r--src/test/rustdoc/test_option_check/bar.rs9
-rw-r--r--src/test/rustdoc/test_option_check/test.rs18
-rw-r--r--src/test/rustdoc/thread-local-src.rs6
-rw-r--r--src/test/rustdoc/titles.rs56
-rw-r--r--src/test/rustdoc/toggle-item-contents.rs185
-rw-r--r--src/test/rustdoc/toggle-method.rs18
-rw-r--r--src/test/rustdoc/toggle-trait-fn.rs23
-rw-r--r--src/test/rustdoc/trait-alias-mention.rs10
-rw-r--r--src/test/rustdoc/trait-impl-items-links-and-anchors.rs65
-rw-r--r--src/test/rustdoc/trait-impl.rs47
-rw-r--r--src/test/rustdoc/trait-self-link.rs6
-rw-r--r--src/test/rustdoc/trait-src-link.rs26
-rw-r--r--src/test/rustdoc/trait-visibility.rs8
-rw-r--r--src/test/rustdoc/trait_alias.rs26
-rw-r--r--src/test/rustdoc/traits-in-bodies-private.rs13
-rw-r--r--src/test/rustdoc/traits-in-bodies.rs52
-rw-r--r--src/test/rustdoc/tuple-struct-fields-doc.rs50
-rw-r--r--src/test/rustdoc/tuples.link1_i32.html1
-rw-r--r--src/test/rustdoc/tuples.link1_t.html1
-rw-r--r--src/test/rustdoc/tuples.link2_i32.html1
-rw-r--r--src/test/rustdoc/tuples.link2_t.html1
-rw-r--r--src/test/rustdoc/tuples.link2_tu.html1
-rw-r--r--src/test/rustdoc/tuples.link_unit.html1
-rw-r--r--src/test/rustdoc/tuples.rs20
-rw-r--r--src/test/rustdoc/type-layout-flag-required.rs4
-rw-r--r--src/test/rustdoc/type-layout.rs85
-rw-r--r--src/test/rustdoc/typedef.rs25
-rw-r--r--src/test/rustdoc/unindent.md1
-rw-r--r--src/test/rustdoc/unindent.rs62
-rw-r--r--src/test/rustdoc/union.rs8
-rw-r--r--src/test/rustdoc/unit-return.rs17
-rw-r--r--src/test/rustdoc/universal-impl-trait.rs55
-rw-r--r--src/test/rustdoc/unneeded-trait-implementations-title.rs5
-rw-r--r--src/test/rustdoc/use-attr.rs8
-rw-r--r--src/test/rustdoc/useless_lifetime_bound.rs13
-rw-r--r--src/test/rustdoc/variadic.rs4
-rw-r--r--src/test/rustdoc/version-separator-without-source.rs23
-rw-r--r--src/test/rustdoc/viewpath-rename.rs21
-rw-r--r--src/test/rustdoc/viewpath-self.rs21
-rw-r--r--src/test/rustdoc/visibility.rs105
-rw-r--r--src/test/rustdoc/where-clause-order.rs19
-rw-r--r--src/test/rustdoc/where-sized.rs6
-rw-r--r--src/test/rustdoc/where.SWhere_Simd_item-decl.html1
-rw-r--r--src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html3
-rw-r--r--src/test/rustdoc/where.rs51
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.enum.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.enum2.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.rs77
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.struct.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.struct2.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.trait.html6
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.trait2.html6
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.union.html3
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.union2.html3
-rw-r--r--src/test/rustdoc/without-redirect.rs13
-rw-r--r--src/test/rustdoc/wrapping.rs5
1285 files changed, 29698 insertions, 0 deletions
diff --git a/src/test/rustdoc-gui/README.md b/src/test/rustdoc-gui/README.md
new file mode 100644
index 000000000..d9854e2e7
--- /dev/null
+++ b/src/test/rustdoc-gui/README.md
@@ -0,0 +1,34 @@
+The tests present here are used to test the generated HTML from rustdoc. The
+goal is to prevent unsound/unexpected GUI changes.
+
+This is using the [browser-ui-test] framework to do so. It works as follows:
+
+It wraps [puppeteer] to send commands to a web browser in order to navigate and
+test what's being currently displayed in the web page.
+
+You can find more information and its documentation in its [repository][browser-ui-test].
+
+If you need to have more information on the tests run, you can use `--test-args`:
+
+```bash
+$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --debug
+```
+
+If you don't want to run in headless mode (helpful to debug sometimes), you can use
+`--no-headless`:
+
+```bash
+$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --no-headless
+```
+
+To see the supported options, use `--help`.
+
+Important to be noted: if the chromium instance crashes when you run it, you might need to
+use `--no-sandbox` to make it work:
+
+```bash
+$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --no-sandbox
+```
+
+[browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/
+[puppeteer]: https://pptr.dev/
diff --git a/src/test/rustdoc-gui/anchor-navigable.goml b/src/test/rustdoc-gui/anchor-navigable.goml
new file mode 100644
index 000000000..424c31223
--- /dev/null
+++ b/src/test/rustdoc-gui/anchor-navigable.goml
@@ -0,0 +1,11 @@
+// The `impl Foo` heading underneath `Implementations` has a §
+// anchor to its left (used for linking to that heading). The anchor only shows
+// up when hovering the `impl Foo`. This test ensures there's no gap between the
+// anchor and the `impl Foo`. If there were a gap, this would cause an annoying
+// problem: you hover `impl Foo` to see the anchor, then when you move your
+// mouse to the left, the anchor disappears before you reach it.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// We check that ".item-info" is bigger than its content.
+move-cursor-to: ".impl"
+assert-property: (".impl > a.anchor", {"offsetWidth": "9"})
+assert-css: (".impl > a.anchor", {"left": "-8px"})
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
new file mode 100644
index 000000000..84b8bbd1b
--- /dev/null
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -0,0 +1,34 @@
+// This test is to ensure that the anchors (`§`) have the expected color and position.
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+show-text: true
+
+// This is needed to ensure that the text color is computed.
+show-text: true
+
+// Set the theme to light.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
+assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
+assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"})
+assert-css: (".srclink", {"color": "rgb(56, 115, 173)"})
+
+move-cursor-to: ".main-heading .srclink"
+assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"})
+
+assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
+
+assert-css: (".sidebar a", {"color": "rgb(53, 109, 164)"})
+assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"})
+
+// We move the cursor over the "Implementations" title so the anchor is displayed.
+move-cursor-to: "h2#implementations"
+assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"})
+
+// Same thing with the impl block title.
+move-cursor-to: "#impl-HeavilyDocumentedStruct"
+assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"})
+
+assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
diff --git a/src/test/rustdoc-gui/auto-hide-trait-implementations.goml b/src/test/rustdoc-gui/auto-hide-trait-implementations.goml
new file mode 100644
index 000000000..7b1358fed
--- /dev/null
+++ b/src/test/rustdoc-gui/auto-hide-trait-implementations.goml
@@ -0,0 +1,13 @@
+// Checks that the setting "auto hide trait implementations" is working as expected.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+
+// By default, the trait implementations are not collapsed.
+assert-attribute: ("#trait-implementations-list > details", {"open": ""}, ALL)
+
+// We now set the setting to auto hide all trait implementations.
+local-storage: {"rustdoc-auto-hide-trait-implementations": "true" }
+// We reload to ensure the trait implementations are collapsed as expected.
+reload:
+
+// We now check that all matching elements don't have the open attributes.
+assert-attribute-false: ("#trait-implementations-list > details", {"open": ""}, ALL)
diff --git a/src/test/rustdoc-gui/basic-code.goml b/src/test/rustdoc-gui/basic-code.goml
new file mode 100644
index 000000000..27deb2c98
--- /dev/null
+++ b/src/test/rustdoc-gui/basic-code.goml
@@ -0,0 +1,3 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+click: ".srclink"
+assert-count: (".line-numbers", 1)
diff --git a/src/test/rustdoc-gui/basic.goml b/src/test/rustdoc-gui/basic.goml
new file mode 100644
index 000000000..239e51a91
--- /dev/null
+++ b/src/test/rustdoc-gui/basic.goml
@@ -0,0 +1,4 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+assert: ("#functions")
+goto: ./struct.Foo.html
+assert: ("div.item-decl")
diff --git a/src/test/rustdoc-gui/check-code-blocks-margin.goml b/src/test/rustdoc-gui/check-code-blocks-margin.goml
new file mode 100644
index 000000000..f6266eba7
--- /dev/null
+++ b/src/test/rustdoc-gui/check-code-blocks-margin.goml
@@ -0,0 +1,6 @@
+// This test ensures that the docblock elements have the appropriate left margin.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+// The top docblock elements shouldn't have left margin...
+assert-css: ("#main-content .docblock.item-decl", {"margin-left": "0px"})
+// ... but all the others should!
+assert-css: ("#main-content .docblock:not(.item-decl)", {"margin-left": "24px"})
diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml
new file mode 100644
index 000000000..3bed7a0a0
--- /dev/null
+++ b/src/test/rustdoc-gui/check_info_sign_position.goml
@@ -0,0 +1,11 @@
+// This test checks the position of the information on the code blocks (like
+// `compile_fail` or `ignore`).
+goto: file://|DOC_PATH|/test_docs/index.html
+goto: ./fn.check_list_code_block.html
+// If the codeblock is the first element of the docblock, the information tooltip must have
+// have some top margin to avoid going over the toggle (the "[+]").
+assert-css: (".docblock > .information > .compile_fail", { "margin-top": "16px" })
+// Checks that the other codeblocks don't have this top margin.
+assert-css: ("ol > li > .information > .compile_fail", { "margin-top": "0px" })
+assert-css: ("ol > li > .information > .ignore", { "margin-top": "0px" })
+assert-css: (".docblock > .information > .ignore", { "margin-top": "0px" })
diff --git a/src/test/rustdoc-gui/code-blocks-overflow.goml b/src/test/rustdoc-gui/code-blocks-overflow.goml
new file mode 100644
index 000000000..f93f3f0ae
--- /dev/null
+++ b/src/test/rustdoc-gui/code-blocks-overflow.goml
@@ -0,0 +1,8 @@
+// This test ensures that codeblocks content don't overflow.
+goto: file://|DOC_PATH|/lib2/sub_mod/struct.Foo.html
+size: (1080, 600)
+// There should be two codeblocks: a rust one and a non-rust one.
+assert-count: (".docblock > .example-wrap", 2)
+assert: ".docblock > .example-wrap > .language-txt"
+assert: ".docblock > .example-wrap > .rust-example-rendered"
+assert-css: (".docblock > .example-wrap > pre", {"width": "785.25px", "overflow-x": "auto"}, ALL)
diff --git a/src/test/rustdoc-gui/code-color.goml b/src/test/rustdoc-gui/code-color.goml
new file mode 100644
index 000000000..2f95bfb6b
--- /dev/null
+++ b/src/test/rustdoc-gui/code-color.goml
@@ -0,0 +1,30 @@
+// The ayu theme has a different color for the "<code>" tags in the doc blocks. We need to
+// check that the rule isn't applied on other "<code>" elements.
+//
+// While we're at it, we also check it for the other themes.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// Set the theme to dark.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (".docblock pre > code", {"color": "rgb(221, 221, 221)"}, ALL)
+assert-css: (".docblock > p > code", {"color": "rgb(221, 221, 221)"}, ALL)
+
+// Set the theme to ayu.
+local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (".docblock pre > code", {"color": "rgb(230, 225, 207)"}, ALL)
+assert-css: (".docblock > p > code", {"color": "rgb(255, 180, 84)"}, ALL)
+
+// Set the theme to light.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (".docblock pre > code", {"color": "rgb(0, 0, 0)"}, ALL)
+assert-css: (".docblock > p > code", {"color": "rgb(0, 0, 0)"}, ALL)
diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml
new file mode 100644
index 000000000..867db0569
--- /dev/null
+++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml
@@ -0,0 +1,7 @@
+// This test checks that the source code pages sidebar toggle is working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+click: ".srclink"
+wait-for: "#sidebar-toggle"
+click: "#sidebar-toggle"
+fail: true
+assert-css: ("#source-sidebar", { "left": "-300px" })
diff --git a/src/test/rustdoc-gui/code-tags.goml b/src/test/rustdoc-gui/code-tags.goml
new file mode 100644
index 000000000..200569a28
--- /dev/null
+++ b/src/test/rustdoc-gui/code-tags.goml
@@ -0,0 +1,20 @@
+// This test ensures that items and documentation code blocks are wrapped in <pre><code>
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+size: (1080, 600)
+// There should be three doc codeblocks
+// Check that their content is inside <pre><code>
+assert-count: (".example-wrap pre > code", 3)
+// Check that function signature is inside <pre><code>
+assert: "pre.rust.fn > code"
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert: "pre.rust.struct > code"
+
+goto: file://|DOC_PATH|/test_docs/enum.AnEnum.html
+assert: "pre.rust.enum > code"
+
+goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
+assert: "pre.rust.trait > code"
+
+goto: file://|DOC_PATH|/test_docs/type.SomeType.html
+assert: "pre.rust.typedef > code"
diff --git a/src/test/rustdoc-gui/default-settings.goml b/src/test/rustdoc-gui/default-settings.goml
new file mode 100644
index 000000000..90f0b087a
--- /dev/null
+++ b/src/test/rustdoc-gui/default-settings.goml
@@ -0,0 +1,8 @@
+// This test ensures that the default settings are correctly applied.
+//
+// The "settings" crate uses "ayu" as default setting, which is what we will
+// check.
+goto: file://|DOC_PATH|/settings/index.html
+// Wait a bit to be sure the default theme is applied.
+// If the theme isn't applied, the command will time out.
+wait-for-css: ("body", {"background-color": "rgb(15, 20, 25)"})
diff --git a/src/test/rustdoc-gui/docblock-big-code-mobile.goml b/src/test/rustdoc-gui/docblock-big-code-mobile.goml
new file mode 100644
index 000000000..02f79f1fc
--- /dev/null
+++ b/src/test/rustdoc-gui/docblock-big-code-mobile.goml
@@ -0,0 +1,9 @@
+// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
+// that it'll be on two lines.
+emulate: "iPhone 8" // it has the following size: (375, 667)
+goto: file://|DOC_PATH|/test_docs/long_code_block/index.html
+// We now check that the block is on two lines:
+show-text: true // We need to enable text draw to be able to have the "real" size
+// Little explanations for this test: if the text wasn't displayed on two lines, it would take
+// around 20px (which is the font size).
+assert-property: (".docblock p > code", {"offsetHeight": "44"})
diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
new file mode 100644
index 000000000..baf9651c4
--- /dev/null
+++ b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
@@ -0,0 +1,22 @@
+// Checks that the setting "line numbers" is working as expected.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+
+// We check that without this setting, there is no line number displayed.
+assert-false: "pre.line-number"
+
+// We now set the setting to show the line numbers on code examples.
+local-storage: {"rustdoc-line-numbers": "true" }
+// We reload to make the line numbers appear.
+reload:
+
+// We wait for them to be added into the DOM by the JS...
+wait-for: "pre.line-number"
+// If the test didn't fail, it means that it was found!
+// Let's now check some CSS properties...
+assert-css: ("pre.line-number", {
+ "margin": "0px",
+ "padding": "13px 8px",
+ "text-align": "right",
+})
+// The first code block has two lines so let's check its `<pre>` elements lists both of them.
+assert-text: ("pre.line-number", "1\n2")
diff --git a/src/test/rustdoc-gui/docblock-details.goml b/src/test/rustdoc-gui/docblock-details.goml
new file mode 100644
index 000000000..f6287ade2
--- /dev/null
+++ b/src/test/rustdoc-gui/docblock-details.goml
@@ -0,0 +1,23 @@
+// This ensures that the `<details>`/`<summary>` elements are displayed as expected.
+goto: file://|DOC_PATH|/test_docs/details/struct.Details.html
+show-text: true
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+
+// We first check that the headers in the `.top-doc` doc block still have their
+// bottom border.
+assert-text: (".top-doc .docblock > h3", "Hello")
+assert-css: (
+ ".top-doc .docblock > h3",
+ {"border-bottom": "1px solid rgb(210, 210, 210)"},
+)
+// We now check that the `<summary>` doesn't have a bottom border and has the correct display.
+assert-css: (
+ ".top-doc .docblock summary h4",
+ {"border-bottom": "0px none rgb(210, 210, 210)"},
+)
+// This allows to ensure that summary is on one line only!
+assert-property: (".top-doc .docblock summary h4", {"offsetHeight": "33"})
+assert-css: (".top-doc .docblock summary h4", {"margin-top": "15px", "margin-bottom": "5px"})
+// So `33 + 15 + 5` == `53`
+assert-property: (".top-doc .docblock summary", {"offsetHeight": "53"})
diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml
new file mode 100644
index 000000000..af76d2ea4
--- /dev/null
+++ b/src/test/rustdoc-gui/docblock-table-overflow.goml
@@ -0,0 +1,21 @@
+// This test ensures that the type declaration content overflow is handled inside the <pre> directly.
+goto: file://|DOC_PATH|/lib2/long_table/struct.Foo.html
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// Logically, the ".docblock" and the "<p>" should have the same scroll width.
+compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["scrollWidth"])
+assert-property: (".top-doc .docblock", {"scrollWidth": "801"})
+// However, since there is overflow in the <table>, its scroll width is bigger.
+assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
+
+// Checking it works on other doc blocks as well...
+
+// Logically, the ".docblock" and the "<p>" should have the same scroll width.
+compare-elements-property: (
+ "#implementations-list > details .docblock",
+ "#implementations-list > details .docblock > p",
+ ["scrollWidth"],
+)
+assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"})
+// However, since there is overflow in the <table>, its scroll width is bigger.
+assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"})
diff --git a/src/test/rustdoc-gui/duplicate-macro-reexport.goml b/src/test/rustdoc-gui/duplicate-macro-reexport.goml
new file mode 100644
index 000000000..9ea599062
--- /dev/null
+++ b/src/test/rustdoc-gui/duplicate-macro-reexport.goml
@@ -0,0 +1,14 @@
+// This test ensures that there is no macro duplicates in the sidebar.
+goto: file://|DOC_PATH|/test_docs/macro.a.html
+// Waiting for the elements in the sidebar to be rendered.
+wait-for: ".sidebar-elems .macro"
+// Check there is only one macro named "a" listed in the sidebar.
+assert-count: (
+ "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='a']",
+ 1,
+)
+// Check there is only one macro named "b" listed in the sidebar.
+assert-count: (
+ "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='b']",
+ 1,
+)
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
new file mode 100644
index 000000000..a5afb037d
--- /dev/null
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -0,0 +1,35 @@
+// This test ensures that the "Escape" shortcut is handled correctly based on the
+// current content displayed.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First, we check that the search results are hidden when the Escape key is pressed.
+write: (".search-input", "test")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+wait-for: "#search h1" // The search element is empty before the first search
+// Check that the currently displayed element is search.
+wait-for: "#alternative-display #search"
+assert-attribute: ("#main-content", {"class": "content hidden"})
+assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
+press-key: "Escape"
+// Checks that search is no longer in the displayed content.
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
+assert-attribute: ("#main-content", {"class": "content"})
+assert-document-property: ({"URL": "index.html"}, [ENDS_WITH])
+
+// Check that focusing the search input brings back the search results
+focus: ".search-input"
+wait-for: "#alternative-display #search"
+assert-attribute: ("#main-content", {"class": "content hidden"})
+assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
+
+// Check that Escape hides the search results when a search result is focused.
+focus: ".search-input"
+assert: ".search-input:focus"
+press-key: "ArrowDown"
+assert-false: ".search-input:focus"
+assert: "#results a:focus"
+press-key: "Escape"
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
+assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
new file mode 100644
index 000000000..5f29fde66
--- /dev/null
+++ b/src/test/rustdoc-gui/font-weight.goml
@@ -0,0 +1,44 @@
+// This test checks that the font weight is correctly applied.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: (
+ "//*[@class='structfield small-section-header']//a[text()='Alias']",
+ {"font-weight": "400"},
+)
+assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
+assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"})
+assert-css: ("#associatedconstant\.Y > .code-header", {"font-weight": "600"})
+
+goto: file://|DOC_PATH|/test_docs/type.SomeType.html
+assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-css: (".impl-items .method", {"font-weight": "600"}, ALL)
+
+goto: file://|DOC_PATH|/lib2/trait.Trait.html
+
+// This is a complex selector, so here's how it works:
+//
+// * //*[@class='docblock item-decl'] — selects element of any tag with classes docblock and item-decl
+// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait
+// * /code — selects immediate child with tag code
+// * /a[@class='constant'] — selects immediate child with tag a and class constant
+// * //text() — selects child that is text node
+// * /parent::* — selects immediate parent of the text node (the * means it can be any tag)
+//
+// This uses '/parent::*' as a proxy for the style of the text node.
+// We can't just select the '<a>' because intermediate tags could be added.
+assert-count: (
+ "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+ 1,
+)
+assert-css: (
+ "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+ {"font-weight": "400"},
+)
+
+assert-count: (".methods .associatedtype", 1)
+assert-css: (".methods .associatedtype", {"font-weight": "600"})
+assert-count: (".methods .constant", 1)
+assert-css: (".methods .constant", {"font-weight": "600"})
+assert-css: (".methods .method", {"font-weight": "600"})
diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml
new file mode 100644
index 000000000..861f69283
--- /dev/null
+++ b/src/test/rustdoc-gui/hash-item-expansion.goml
@@ -0,0 +1,11 @@
+// This test ensures that the element corresponding to the hash is displayed.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow
+// In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)".
+assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""})
+// We first check that the impl block is open by default.
+assert-attribute: ("#implementations-list details", {"open": ""})
+// To ensure that we will click on the currently hidden method.
+assert-text: (".sidebar-elems section .block li > a", "must_use")
+click: ".sidebar-elems section .block li > a"
+// We check that the impl block was opened as expected so that we can see the method.
+assert-attribute: ("#implementations-list > details", {"open": ""})
diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml
new file mode 100644
index 000000000..a47a9c8a1
--- /dev/null
+++ b/src/test/rustdoc-gui/headers-color.goml
@@ -0,0 +1,117 @@
+// This test check for headers text and background colors for the different themes.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+
+// This is needed so that the text color is computed.
+show-text: true
+
+// Ayu theme
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".impl",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(230, 225, 207)", "background-color": "rgb(15, 20, 25)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
+assert-css: (
+ "#impl-Foo",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
+)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(197, 197, 197)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(57, 175, 215)"}, ALL)
+
+// Dark theme
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+
+assert-css: (
+ ".impl",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(53, 53, 53)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
+assert-css: (
+ "#impl-Foo",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
+)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(221, 221, 221)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(210, 153, 29)"}, ALL)
+
+// Light theme
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+
+assert-css: (
+ ".impl",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
+assert-css: ("#impl-Foo", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"})
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(0, 0, 0)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(56, 115, 173)"}, ALL)
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
new file mode 100644
index 000000000..8c2c3df15
--- /dev/null
+++ b/src/test/rustdoc-gui/headings.goml
@@ -0,0 +1,258 @@
+// This test checks that headers (a) have the correct heading level, (b) are the right size,
+// and (c) have the correct underlining (or absence of underlining).
+// The sizes may change as design changes, but try to make sure a lower header is never bigger than
+// its parent headers. Also make sure lower headers don't have underlines when their parents lack
+// an underline.
+// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
+// default 16px font size:
+// 24px 1.5em
+// 22px 1.375rem
+// 20px 1.25rem
+// 18px 1.125em
+// 16px 1rem
+// 14px 0.875rem
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+assert-css: ("h3#title-for-field", {"font-size": "20px"})
+assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "14px"})
+
+goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#variants", {"font-size": "22px"})
+assert-css: ("h2#variants", {"border-bottom-width": "1px"})
+
+assert-css: ("h4#none-prose-title", {"font-size": "16px"})
+assert-css: ("h4#none-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#none-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#none-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#wrapped-prose-title", {"font-size": "16px"})
+assert-css: ("h4#wrapped-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#wrapped-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#wrapped0-prose-title", {"font-size": "16px"})
+assert-css: ("h5#wrapped0-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h6#wrapped0-prose-sub-heading", {"font-size": "14px"})
+assert-css: ("h6#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#structy-prose-title", {"font-size": "16px"})
+assert-css: ("h5#structy-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h6#structy-prose-sub-heading", {"font-size": "14px"})
+assert-css: ("h6#structy-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+
+assert-text: (".sidebar .mod h3", "Modules")
+assert-css: (".sidebar .mod h3", {"border-bottom-width": "0px"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#title-for-union-variant", {"font-size": "20px"})
+assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "14px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+
+goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+// Checking colors now.
+show-text: true
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+assert-css: (
+ ".top-doc .docblock h2",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
+)
+assert-css: (
+ ".top-doc .docblock h3",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
+)
+assert-css: (
+ ".top-doc .docblock h4",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
+)
+assert-css: (
+ ".top-doc .docblock h5",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"},
+)
+assert-css: (
+ "#implementations-list .docblock h4",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"},
+)
+assert-css: (
+ "#implementations-list .docblock h5",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"},
+)
+assert-css: (
+ "#implementations-list .docblock h6",
+ {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"},
+)
+
+local-storage: {"rustdoc-theme": "dark"}
+reload:
+assert-css: (
+ ".top-doc .docblock h2",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
+)
+assert-css: (
+ ".top-doc .docblock h3",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
+)
+assert-css: (
+ ".top-doc .docblock h4",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
+)
+assert-css: (
+ ".top-doc .docblock h5",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"},
+)
+assert-css: (
+ "#implementations-list .docblock h4",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"},
+)
+assert-css: (
+ "#implementations-list .docblock h5",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"},
+)
+assert-css: (
+ "#implementations-list .docblock h6",
+ {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"},
+)
+
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+assert-css: (
+ ".top-doc .docblock h2",
+ {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
+)
+assert-css: (
+ ".top-doc .docblock h2",
+ {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
+)
+assert-css: (
+ ".top-doc .docblock h4",
+ {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
+)
+assert-css: (
+ ".top-doc .docblock h5",
+ {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"},
+)
+assert-css: (
+ "#implementations-list .docblock h4",
+ {"color": "rgb(255, 255, 255)", "border-bottom": "0px none rgb(92, 103, 115)"},
+)
+assert-css: (
+ "#implementations-list .docblock h5",
+ {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"},
+)
+assert-css: (
+ "#implementations-list .docblock h6",
+ {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"},
+)
+
+local-storage: {"rustdoc-theme": "light"}
+goto: file://|DOC_PATH|/staged_api/struct.Foo.html
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "dark"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml
new file mode 100644
index 000000000..4f75b5841
--- /dev/null
+++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml
@@ -0,0 +1,9 @@
+// Make sure that the last two entries are more than 12 pixels apart and not stacked on each other.
+
+goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
+
+compare-elements-position-near-false: (
+ "//*[@class='item-table']//div[last()-1]",
+ "//*[@class='item-table']//div[last()-3]",
+ {"y": 12},
+)
diff --git a/src/test/rustdoc-gui/impl-default-expansion.goml b/src/test/rustdoc-gui/impl-default-expansion.goml
new file mode 100644
index 000000000..6df2661e6
--- /dev/null
+++ b/src/test/rustdoc-gui/impl-default-expansion.goml
@@ -0,0 +1,3 @@
+// This test ensures that the impl blocks are open by default.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""})
diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml
new file mode 100644
index 000000000..666a6e125
--- /dev/null
+++ b/src/test/rustdoc-gui/implementors.goml
@@ -0,0 +1,35 @@
+// The goal of this test is to check that the external trait implementors, generated with JS,
+// have the same display than the "local" ones.
+goto: file://|DOC_PATH|/implementors/trait.Whatever.html
+assert: "#implementors-list"
+// There are supposed to be two implementors listed.
+assert-count: ("#implementors-list .impl", 2)
+// Now we check that both implementors have an anchor, an ID and a similar DOM.
+assert: ("#implementors-list .impl:nth-child(1) > a.anchor")
+assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"})
+assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"})
+assert: "#implementors-list .impl:nth-child(1) > .code-header.in-band"
+
+assert: ("#implementors-list .impl:nth-child(2) > a.anchor")
+assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"})
+assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"})
+assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band"
+
+goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html
+compare-elements-position-near-false: (
+ "#impl-EmptyTrait1-for-HasEmptyTraits",
+ "#impl-EmptyTrait2-for-HasEmptyTraits",
+ {"y": 30},
+)
+compare-elements-position-near: (
+ "#impl-EmptyTrait3-for-HasEmptyTraits h3",
+ "#impl-EmptyTrait3-for-HasEmptyTraits .item-info",
+ {"y": 30},
+)
+
+// Now check that re-exports work correctly.
+// There should be exactly one impl shown on both of these pages.
+goto: file://|DOC_PATH|/lib2/trait.TraitToReexport.html
+assert-count: ("#implementors-list .impl", 1)
+goto: file://|DOC_PATH|/implementors/trait.TraitToReexport.html
+assert-count: ("#implementors-list .impl", 1)
diff --git a/src/test/rustdoc-gui/item-info-overflow.goml b/src/test/rustdoc-gui/item-info-overflow.goml
new file mode 100644
index 000000000..b7095a3c5
--- /dev/null
+++ b/src/test/rustdoc-gui/item-info-overflow.goml
@@ -0,0 +1,31 @@
+// This test ensures that the "item-info" elements don't overflow.
+goto: file://|DOC_PATH|/lib2/struct.LongItemInfo.html
+// We set a fixed size so there is no chance of "random" resize.
+size: (1200, 870)
+// Logically, the "item-decl" and the "item-info" should have the same scroll width.
+compare-elements-property: (".docblock.item-decl", ".item-info", ["scrollWidth"])
+assert-property: (".item-info", {"scrollWidth": "890"})
+// Just to be sure we're comparing the correct "item-info":
+assert-text: (
+ ".item-info",
+ "Available on Android or Linux or Emscripten or DragonFly BSD",
+ STARTS_WITH,
+)
+
+// Checking the "item-info" on an impl block as well:
+goto: file://|DOC_PATH|/lib2/struct.LongItemInfo2.html
+compare-elements-property: (
+ "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
+ "#impl-SimpleTrait-for-LongItemInfo2 + .docblock",
+ ["scrollWidth"],
+)
+assert-property: (
+ "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
+ {"scrollWidth": "866"},
+)
+// Just to be sure we're comparing the correct "item-info":
+assert-text: (
+ "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
+ "Available on Android or Linux or Emscripten or DragonFly BSD",
+ STARTS_WITH,
+)
diff --git a/src/test/rustdoc-gui/item-info.goml b/src/test/rustdoc-gui/item-info.goml
new file mode 100644
index 000000000..50c45b76b
--- /dev/null
+++ b/src/test/rustdoc-gui/item-info.goml
@@ -0,0 +1,32 @@
+// This test ensures a few things for item info elements.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// Ensuring that the item information don't take 100% of the width if unnecessary.
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// We check that ".item-info" is bigger than its content.
+assert-css: (".item-info", {"width": "790px"})
+assert-css: (".item-info .stab", {"width": "289px"})
+assert-position: (".item-info .stab", {"x": 295})
+
+// Now we ensure that they're not rendered on the same line.
+goto: file://|DOC_PATH|/lib2/trait.Trait.html
+// We first ensure that there are two item info on the trait.
+assert-count: ("#main-content > .item-info .stab", 2)
+// They should not have the same `y` position!
+compare-elements-position-false: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ("y"),
+)
+// But they should have the same `x` position.
+compare-elements-position: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ("x"),
+)
+// They are supposed to have the same height too.
+compare-elements-css: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ["height"],
+)
diff --git a/src/test/rustdoc-gui/item-summary-table.goml b/src/test/rustdoc-gui/item-summary-table.goml
new file mode 100644
index 000000000..6bf4e288c
--- /dev/null
+++ b/src/test/rustdoc-gui/item-summary-table.goml
@@ -0,0 +1,6 @@
+// This test ensures that <table> elements aren't display in items summary.
+goto: file://|DOC_PATH|/lib2/summary_table/index.html
+// We check that we picked the right item first.
+assert-text: (".item-table .item-left", "Foo")
+// Then we check that its summary is empty.
+assert-text: (".item-table .item-right", "")
diff --git a/src/test/rustdoc-gui/javascript-disabled.goml b/src/test/rustdoc-gui/javascript-disabled.goml
new file mode 100644
index 000000000..1693f7b64
--- /dev/null
+++ b/src/test/rustdoc-gui/javascript-disabled.goml
@@ -0,0 +1,6 @@
+// When JavaScript is disabled, we hide the search bar, because it
+// can't be used without JS.
+javascript: false
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-css: (".sub", {"display": "none"})
diff --git a/src/test/rustdoc-gui/jump-to-def-background.goml b/src/test/rustdoc-gui/jump-to-def-background.goml
new file mode 100644
index 000000000..d17400f5b
--- /dev/null
+++ b/src/test/rustdoc-gui/jump-to-def-background.goml
@@ -0,0 +1,43 @@
+// We check the background color on the jump to definition links in the source code page.
+goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html
+
+// Set the theme to dark.
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(51, 51, 51)"},
+ ALL,
+)
+
+// Set the theme to ayu.
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(51, 51, 51)"},
+ ALL,
+)
+
+// Set the theme to light.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(238, 238, 238)"},
+ ALL,
+)
diff --git a/src/test/rustdoc-gui/label-next-to-symbol.goml b/src/test/rustdoc-gui/label-next-to-symbol.goml
new file mode 100644
index 000000000..ca3994a08
--- /dev/null
+++ b/src/test/rustdoc-gui/label-next-to-symbol.goml
@@ -0,0 +1,78 @@
+// These tests verify that labels like "UNIX" and "Deprecated" stay on the same line as their symbol.
+// It also verifies the staggered layout on mobile.
+goto: file://|DOC_PATH|/test_docs/index.html
+
+// Desktop view
+size: (1080, 600)
+assert: (".stab.deprecated")
+assert: (".stab.portability")
+
+// make sure that deprecated and portability are different colours
+assert-css: (
+ ".item-table .item-left .stab.deprecated",
+ { "background-color": "rgb(255, 196, 196)" },
+)
+assert-css: (
+ ".item-table .item-left .stab.portability",
+ { "background-color": "rgb(243, 223, 255)" },
+)
+
+// table like view
+assert-css: (".item-right.docblock-short", { "padding-left": "0px" })
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ ".item-left .stab.deprecated",
+ {"y": 2},
+)
+compare-elements-position: (
+ ".item-left .stab.deprecated",
+ ".item-left .stab.portability",
+ ("y"),
+)
+
+// Ensure no wrap
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ {"y": 2},
+)
+// compare parent elements
+compare-elements-position: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..",
+ ("y"),
+)
+
+
+// Mobile view
+size: (600, 600)
+// staggered layout with 2em spacing
+assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ ".item-left .stab.deprecated",
+ {"y": 1},
+)
+compare-elements-position: (
+ ".item-left .stab.deprecated",
+ ".item-left .stab.portability",
+ ("y"),
+)
+
+// Ensure wrap
+compare-elements-position-near-false: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ {"y": 12},
+)
+// compare parent elements
+compare-elements-position-false: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..",
+ ("y"),
+)
+compare-elements-position-false: (
+ ".item-left .stab.deprecated",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ ("y"),
+)
diff --git a/src/test/rustdoc-gui/list_code_block.goml b/src/test/rustdoc-gui/list_code_block.goml
new file mode 100644
index 000000000..eba1a662b
--- /dev/null
+++ b/src/test/rustdoc-gui/list_code_block.goml
@@ -0,0 +1,4 @@
+// This test checks that code blocks in list are supported.
+goto: file://|DOC_PATH|/test_docs/index.html
+goto: ./fn.check_list_code_block.html
+assert: ("pre.rust.fn")
diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml
new file mode 100644
index 000000000..13b9b563d
--- /dev/null
+++ b/src/test/rustdoc-gui/mobile.goml
@@ -0,0 +1,30 @@
+// Test various properties of the mobile UI
+goto: file://|DOC_PATH|/staged_api/struct.Foo.html
+size: (400, 600)
+
+font-size: 18
+wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
+
+// The out-of-band info (source, stable version, collapse) should be below the
+// h1 when the screen gets narrow enough.
+assert-css: (".main-heading", {
+ "display": "flex",
+ "flex-direction": "column"
+})
+
+assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36})
+
+// Note: We can't use assert-text here because the 'Since' is set by CSS and
+// is therefore not part of the DOM.
+assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
+
+size: (1000, 1000)
+wait-for: 100 // wait a bit for the resize to be fully taken into account.
+assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
+
+// On the settings page, the theme buttons should not line-wrap. Instead, they should
+// all be placed as a group on a line below the setting name "Theme."
+goto: file://|DOC_PATH|/settings.html
+size: (400, 600)
+// Ignored for now https://github.com/rust-lang/rust/issues/93784.
+// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
diff --git a/src/test/rustdoc-gui/module-items-font.goml b/src/test/rustdoc-gui/module-items-font.goml
new file mode 100644
index 000000000..758ee391a
--- /dev/null
+++ b/src/test/rustdoc-gui/module-items-font.goml
@@ -0,0 +1,67 @@
+// This test checks that the correct font is used on module items (in index.html pages).
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (
+ ".item-table .module-item a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+ ALL,
+)
+assert-css: (
+ ".item-table .docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+ ALL,
+)
+
+// modules
+assert-css: (
+ "#modules + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#modules + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
+// structs
+assert-css: (
+ "#structs + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#structs + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
+// enums
+assert-css: (
+ "#enums + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#enums + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
+// traits
+assert-css: (
+ "#traits + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#traits + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
+// functions
+assert-css: (
+ "#functions + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#functions + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
+// keywords
+assert-css: (
+ "#keywords + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#keywords + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
diff --git a/src/test/rustdoc-gui/overflow-tooltip-information.goml b/src/test/rustdoc-gui/overflow-tooltip-information.goml
new file mode 100644
index 000000000..7ef85a4c4
--- /dev/null
+++ b/src/test/rustdoc-gui/overflow-tooltip-information.goml
@@ -0,0 +1,8 @@
+// The goal of this test is to ensure that the tooltip `.information` class doesn't
+// have overflow and max-width CSS rules set because they create a bug in firefox on
+// mac. For more information: https://github.com/rust-lang/rust/issues/89185
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".docblock > .information", {
+ "overflow-x": "visible",
+ "max-width": "none"
+}, ALL)
diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml
new file mode 100644
index 000000000..54f3790a7
--- /dev/null
+++ b/src/test/rustdoc-gui/pocket-menu.goml
@@ -0,0 +1,77 @@
+// This test ensures that the "pocket menus" are working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First we check that the help menu doesn't exist yet.
+assert-false: "#help-button .popover"
+// Then we display the help menu.
+click: "#help-button"
+assert: "#help-button .popover"
+assert-css: ("#help-button .popover", {"display": "block"})
+
+// Now we click somewhere else on the page to ensure it is handling the blur event
+// correctly.
+click: ".sidebar"
+assert-css: ("#help-button .popover", {"display": "none"})
+
+// Now we will check that we cannot have two "pocket menus" displayed at the same time.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+click: "#settings-menu"
+assert-css: ("#help-button .popover", {"display": "none"})
+assert-css: ("#settings-menu .popover", {"display": "block"})
+
+// Now the other way.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
+// Now verify that clicking the help menu again closes it.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "none"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
+// We check the borders color now:
+
+// Ayu theme
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+ "#help-button .popover",
+ {"display": "block", "border-color": "rgb(92, 103, 115)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Dark theme
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+ "#help-button .popover",
+ {"display": "block", "border-color": "rgb(210, 210, 210)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Light theme
+local-storage: {
+ "rustdoc-theme": "light",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+ "#help-button .popover",
+ {"display": "block", "border-color": "rgb(221, 221, 221)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
diff --git a/src/test/rustdoc-gui/run-on-hover.goml b/src/test/rustdoc-gui/run-on-hover.goml
new file mode 100644
index 000000000..b8efa8e30
--- /dev/null
+++ b/src/test/rustdoc-gui/run-on-hover.goml
@@ -0,0 +1,7 @@
+// Example code blocks sometimes have a "Run" button to run them on the
+// Playground. That button is hidden until the user hovers over the code block.
+// This test checks that it is hidden, and that it shows on hover.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".test-arrow", {"visibility": "hidden"})
+move-cursor-to: ".example-wrap"
+assert-css: (".test-arrow", {"visibility": "visible"})
diff --git a/src/test/rustdoc-gui/rust-logo.goml b/src/test/rustdoc-gui/rust-logo.goml
new file mode 100644
index 000000000..4a9dcf735
--- /dev/null
+++ b/src/test/rustdoc-gui/rust-logo.goml
@@ -0,0 +1,78 @@
+// This test ensures that the correct style is applied to the rust logo in the sidebar.
+goto: file://|DOC_PATH|/test_docs/index.html
+
+// First we start with the dark theme.
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// Then with the ayu theme.
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// And finally with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "none"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "none"},
+)
diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml
new file mode 100644
index 000000000..d645e2370
--- /dev/null
+++ b/src/test/rustdoc-gui/search-filter.goml
@@ -0,0 +1,83 @@
+// Checks that the crate search filtering is handled correctly and changes the results.
+goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
+write: (".search-input", "test")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-text: ("#results .externcrate", "test_docs")
+
+wait-for: "#crate-search"
+// We now want to change the crate filter.
+click: "#crate-search"
+// We select "lib2" option then press enter to change the filter.
+press-key: "ArrowDown"
+press-key: "ArrowDown"
+press-key: "Enter"
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-document-property: ({"URL": "&filter-crate="}, CONTAINS)
+// We check that there is no more "test_docs" appearing.
+assert-false: "#results .externcrate"
+// We also check that "lib2" is the filter crate.
+assert-property: ("#crate-search", {"value": "lib2"})
+
+// Now we check that leaving the search results and putting them back keeps the
+// crate filtering.
+press-key: "Escape"
+wait-for-css: ("#main-content", {"display": "block"})
+focus: ".search-input"
+wait-for-css: ("#main-content", {"display": "none"})
+// We check that there is no more "test_docs" appearing.
+assert-false: "#results .externcrate"
+assert-property: ("#crate-search", {"value": "lib2"})
+
+// Selecting back "All crates"
+click: "#crate-search"
+press-key: "ArrowUp"
+press-key: "ArrowUp"
+press-key: "Enter"
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-property: ("#crate-search", {"value": "All crates"})
+
+// Checking that the URL parameter is taken into account for crate filtering.
+goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
+wait-for: "#crate-search"
+assert-property: ("#crate-search", {"value": "lib2"})
+assert-false: "#results .externcrate"
+
+// Checking that the text for the "title" is correct (the "All" comes from the "<select>").
+assert-text: ("#search-settings", "Results for test in All", STARTS_WITH)
+
+// Checking the display of the crate filter.
+// We start with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+timeout: 2000
+wait-for: "#crate-search"
+assert-css: ("#crate-search", {
+ "border": "1px solid rgb(224, 224, 224)",
+ "color": "rgb(0, 0, 0)",
+ "background-color": "rgb(255, 255, 255)",
+})
+
+// We now check the dark theme.
+click: "#settings-menu"
+wait-for: "#settings"
+click: "#theme-dark"
+wait-for-css: ("#crate-search", {
+ "border": "1px solid rgb(240, 240, 240)",
+ "color": "rgb(17, 17, 17)",
+ "background-color": "rgb(240, 240, 240)",
+})
+
+// And finally we check the ayu theme.
+click: "#theme-ayu"
+wait-for-css: ("#crate-search", {
+ "border": "1px solid rgb(66, 76, 87)",
+ "color": "rgb(197, 197, 197)",
+ "background-color": "rgb(20, 25, 32)",
+})
diff --git a/src/test/rustdoc-gui/search-input-mobile.goml b/src/test/rustdoc-gui/search-input-mobile.goml
new file mode 100644
index 000000000..5c95db70a
--- /dev/null
+++ b/src/test/rustdoc-gui/search-input-mobile.goml
@@ -0,0 +1,11 @@
+// Test to ensure that you can click on the search input, whatever the width.
+// The PR which fixed it is: https://github.com/rust-lang/rust/pull/81592
+goto: file://|DOC_PATH|/test_docs/index.html
+size: (463, 700)
+// We first check that the search input isn't already focused.
+assert-false: ("input.search-input:focus")
+click: "input.search-input"
+reload:
+size: (750, 700)
+click: "input.search-input"
+assert: ("input.search-input:focus")
diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml
new file mode 100644
index 000000000..44123b702
--- /dev/null
+++ b/src/test/rustdoc-gui/search-input.goml
@@ -0,0 +1,23 @@
+// Ensures that the search input border color changes on focus.
+goto: file://|DOC_PATH|/test_docs/index.html
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+focus: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"})
+
+local-storage: {"rustdoc-theme": "light"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"})
+
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
diff --git a/src/test/rustdoc-gui/search-reexport.goml b/src/test/rustdoc-gui/search-reexport.goml
new file mode 100644
index 000000000..5ef890d47
--- /dev/null
+++ b/src/test/rustdoc-gui/search-reexport.goml
@@ -0,0 +1,33 @@
+// Checks that the reexports are present in the search index, can have
+// doc aliases and are highligted when their ID is the hash of the page.
+goto: file://|DOC_PATH|/test_docs/index.html
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+// First we check that the reexport has the correct ID and no background color.
+assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;")
+assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"})
+write: (".search-input", "TheStdReexport")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+wait-for: "//a[@class='result-import']"
+assert-attribute: (
+ "//a[@class='result-import']",
+ {"href": "../test_docs/index.html#reexport.TheStdReexport"},
+)
+assert-text: ("//a[@class='result-import']", "test_docs::TheStdReexport")
+click: "//a[@class='result-import']"
+// We check that it has the background modified thanks to the focus.
+wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"})
+
+// We now check that the alias is working as well on the reexport.
+// To be SURE that the search will be run.
+press-key: 'Enter'
+write: (".search-input", "AliasForTheStdReexport")
+wait-for: "//a[@class='result-import']"
+assert-text: (
+ "//a[@class='result-import']",
+ "AliasForTheStdReexport - see test_docs::TheStdReexport",
+)
+// Same thing again, we click on it to ensure the background is once again set as expected.
+click: "//a[@class='result-import']"
+wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"})
diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml
new file mode 100644
index 000000000..9a49ae2c6
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-color.goml
@@ -0,0 +1,98 @@
+// The goal of this test is to ensure the color of the text is the one expected.
+goto: file://|DOC_PATH|/test_docs/index.html?search=coo
+
+// This is needed so that the text color is computed.
+show-text: true
+
+// Ayu theme
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(197, 197, 197)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(0, 150, 207)"},
+)
+
+// Checking the color for "keyword".
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(120, 135, 151)"},
+)
+
+// Dark theme
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(221, 221, 221)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(221, 221, 221)"},
+)
+
+// Checking the color for "keyword".
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(221, 221, 221)"},
+)
+
+// Light theme
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(0, 0, 0)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(0, 0, 0)"},
+)
+
+// Checking the color for "keyword".
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(0, 0, 0)"},
+)
+
+// Check the alias more specifically in the dark theme.
+goto: file://|DOC_PATH|/test_docs/index.html
+// We set the theme so we're sure that the correct values will be used, whatever the computer
+// this test is running on.
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// We reload the page so the local storage settings are being used.
+reload:
+write: (".search-input", "thisisanalias")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Checking that the colors for the alias element are the ones expected.
+assert-css: (".result-name > .alias", {"color": "rgb(255, 255, 255)"})
+assert-css: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"})
diff --git a/src/test/rustdoc-gui/search-result-description.goml b/src/test/rustdoc-gui/search-result-description.goml
new file mode 100644
index 000000000..d8cb6ee57
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-description.goml
@@ -0,0 +1,5 @@
+// This test is to ensure that the codeblocks are correctly rendered in the search results.
+goto: file://|DOC_PATH|/test_docs/index.html?search=some_more_function
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-text: (".search-results .desc code", "format!")
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
new file mode 100644
index 000000000..8464ba7c2
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -0,0 +1,42 @@
+// Checks that the search results have the expected width.
+goto: file://|DOC_PATH|/test_docs/index.html
+size: (900, 1000)
+write: (".search-input", "test")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+wait-for: "#search-settings"
+// The width is returned by "getComputedStyle" which returns the exact number instead of the
+// CSS rule which is "50%"...
+assert-css: (".search-results div.desc", {"width": "295px"})
+size: (600, 100)
+// As counter-intuitive as it may seem, in this width, the width is "100%", which is why
+// when computed it's larger.
+assert-css: (".search-results div.desc", {"width": "570px"})
+
+// Check that the crate filter `<select>` is correctly handled when it goes to next line.
+// To do so we need to update the length of one of its `<option>`.
+size: (900, 900)
+
+// First we check the current width and position.
+assert-css: ("#crate-search", {"width": "218px"})
+compare-elements-position-near: (
+ "#crate-search",
+ "#search-settings .search-results-title",
+ {"y": 5},
+)
+
+// Then we update the text of one of the `<option>`.
+text: (
+ "#crate-search option",
+ "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa",
+)
+
+// Then we compare again.
+assert-css: ("#crate-search", {"width": "640px"})
+compare-elements-position-near-false: (
+ "#crate-search",
+ "#search-settings .search-results-title",
+ {"y": 5},
+)
+// And we check that the `<select>` isn't bigger than its container.
+assert-css: ("#search", {"width": "640px"})
diff --git a/src/test/rustdoc-gui/search-result-go-to-first.goml b/src/test/rustdoc-gui/search-result-go-to-first.goml
new file mode 100644
index 000000000..255470a3e
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-go-to-first.goml
@@ -0,0 +1,19 @@
+// This test ensures that the "go_to_first" feature is working as expected.
+
+// First, we check that the first page doesn't have the string we're looking for to ensure
+// that the feature is changing page as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-text-false: (".fqn .in-band", "Struct test_docs::Foo")
+
+// We now check that we land on the search result page if "go_to_first" isn't set.
+goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-text-false: (".fqn .in-band", "Struct test_docs::Foo")
+// Ensure that the search results are displayed, not the "normal" content.
+assert-css: ("#main-content", {"display": "none"})
+
+// Now we can check that the feature is working as expected!
+goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo&go_to_first=true
+// Waiting for the page to load...
+wait-for-text: (".fqn .in-band", "Struct test_docs::Foo")
diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml
new file mode 100644
index 000000000..16ae10431
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-keyword.goml
@@ -0,0 +1,13 @@
+// Checks that the "keyword" results have the expected text alongside them.
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "CookieMonster")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Note: The two next assert commands could be merged as one but readability would be
+// less good.
+//
+// Checking that the CSS is displaying " (keyword)" in italic.
+assert-text: (".result-name span.keyword > i", "(keyword)")
+assert-text: (".result-name span.keyword", "CookieMonster (keyword)")
diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml
new file mode 100644
index 000000000..9d506c151
--- /dev/null
+++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml
@@ -0,0 +1,74 @@
+// Checks that the search tab results work correctly with function signature syntax
+// First, try a search-by-name
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "Foo")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+assert-text: ("#titles > button:nth-of-type(1)", "In Names", STARTS_WITH)
+assert: "input.search-input:focus"
+// Use left-right keys
+press-key: "ArrowDown"
+assert: "#results > .search-results.active > a:nth-of-type(1):focus"
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(2)", {"class": "selected"})
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"})
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+press-key: "ArrowLeft"
+wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"})
+
+// Now try search-by-return
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "-> String")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH)
+assert: "input.search-input:focus"
+// Use left-right keys
+press-key: "ArrowDown"
+assert: "#results > .search-results.active > a:nth-of-type(1):focus"
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+press-key: "ArrowRight"
+wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+press-key: "ArrowLeft"
+wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+
+// Try with a search-by-return with no results
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "-> Something")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH)
+
+// Try with a search-by-parameter
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "usize pattern")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+assert-text: ("#titles > button:nth-of-type(1)", "In Function Parameters", STARTS_WITH)
+
+// Try with a search-by-parameter-and-return
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "pattern -> str")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"})
+assert-text: ("#titles > button:nth-of-type(1)", "In Function Signatures", STARTS_WITH)
diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml
new file mode 100644
index 000000000..d9cf5ee66
--- /dev/null
+++ b/src/test/rustdoc-gui/settings.goml
@@ -0,0 +1,158 @@
+// This test ensures that the settings menu display is working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true // needed when we check for colors below.
+// First, we check that the settings page doesn't exist.
+assert-false: "#settings"
+// We now click on the settings button.
+click: "#settings-menu"
+wait-for: "#settings"
+assert-css: ("#settings", {"display": "block"})
+// Let's close it by clicking on the same button.
+click: "#settings-menu"
+wait-for-css: ("#settings", {"display": "none"})
+
+// Let's check that pressing "ESCAPE" is closing it.
+click: "#settings-menu"
+wait-for-css: ("#settings", {"display": "block"})
+press-key: "Escape"
+wait-for-css: ("#settings", {"display": "none"})
+
+// Let's click on it when the search results are displayed.
+focus: ".search-input"
+write: "test"
+// To be SURE that the search will be run.
+press-key: 'Enter'
+wait-for: "#alternative-display #search"
+click: "#settings-menu"
+wait-for-css: ("#settings", {"display": "block"})
+// Ensure that the search is still displayed.
+wait-for: "#alternative-display #search"
+assert: "#main-content.hidden"
+
+// Now let's check the content of the settings menu.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+click: "#settings-menu"
+wait-for: "#settings"
+
+// We check that the "Use system theme" is disabled.
+assert-property: ("#use-system-theme", {"checked": "false"})
+assert: "//*[@class='setting-line']//span[text()='Use system theme']"
+// Meaning that only the "theme" menu is showing up.
+assert: ".setting-line:not(.hidden) #theme"
+assert: ".setting-line.hidden #preferred-dark-theme"
+assert: ".setting-line.hidden #preferred-light-theme"
+
+// We check that the correct theme is selected.
+assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
+
+// Some style checks...
+// First we check the "default" display.
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+ },
+)
+assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"})
+// Let's start with the hover.
+move-cursor-to: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+ },
+)
+move-cursor-to: "#theme-light"
+assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"})
+move-cursor-to: "#theme-ayu"
+// Let's now check with the focus.
+focus: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+ },
+)
+focus: "#theme-light"
+assert-css: (
+ "#theme-light",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+ },
+)
+// Now we check we both focus and hover.
+move-cursor-to: "#theme-dark"
+focus: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+ },
+)
+move-cursor-to: "#theme-light"
+focus: "#theme-light"
+assert-css: (
+ "#theme-light",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+ },
+)
+
+// We now switch the display.
+click: "#use-system-theme"
+// Wait for the hidden element to show up.
+wait-for: ".setting-line:not(.hidden) #preferred-dark-theme"
+assert: ".setting-line:not(.hidden) #preferred-light-theme"
+// Check that the theme picking is hidden.
+assert: ".setting-line.hidden #theme"
+
+// We check their text as well.
+assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
+assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
+
+// We now check that clicking on the "sliders"' text is like clicking on the slider.
+// To test it, we use the "Disable keyboard shortcuts".
+local-storage: {"rustdoc-disable-shortcuts": "false"}
+click: ".setting-line:last-child .toggle .label"
+assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
+
+// Make sure that "Disable keyboard shortcuts" actually took effect.
+press-key: "Escape"
+press-key: "?"
+assert-false: "#help-button .popover"
+wait-for-css: ("#settings-menu .popover", {"display": "block"})
+
+// Now turn keyboard shortcuts back on, and see if they work.
+click: ".setting-line:last-child .toggle .label"
+assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
+press-key: "Escape"
+press-key: "?"
+wait-for-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
+// Now we go to the settings page to check that the CSS is loaded as expected.
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
+assert-css: (".setting-line .toggle .slider", {"width": "45px", "margin-right": "20px"})
+
+// We now check the display with JS disabled.
+assert-false: "noscript section"
+javascript: false
+reload:
+assert-css: ("noscript section", {"display": "block"})
+javascript: true
+
+// Check for the display on small screen
+show-text: true
+reload:
+size: (300, 1000)
+click: "#settings-menu"
+wait-for: "#settings"
+assert-css: ("#settings .slider", {"width": "45px"}, ALL)
diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml
new file mode 100644
index 000000000..1f20a0eaa
--- /dev/null
+++ b/src/test/rustdoc-gui/shortcuts.goml
@@ -0,0 +1,13 @@
+// Check that the various shortcuts are working.
+goto: file://|DOC_PATH|/test_docs/index.html
+// We first check that the search input isn't already focused.
+assert-false: "input.search-input:focus"
+press-key: "s"
+assert: "input.search-input:focus"
+press-key: "Escape"
+assert-false: "input.search-input:focus"
+// We now check for the help popup.
+press-key: "?"
+assert-css: ("#help-button .popover", {"display": "block"})
+press-key: "Escape"
+assert-css: ("#help-button .popover", {"display": "none"})
diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
new file mode 100644
index 000000000..a3a62fe54
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
@@ -0,0 +1,5 @@
+// This test ensures that the reexport of a macro doesn't make the original macro
+// displayed twice in the sidebar.
+goto: file://|DOC_PATH|/test_docs/macro.repro.html
+wait-for: ".sidebar-elems .macro .macro"
+assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
new file mode 100644
index 000000000..033c65783
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -0,0 +1,64 @@
+// This test ensure that the sidebar isn't "hidden" on mobile but instead moved out of the viewport.
+// This is especially important for devices for "text-first" content (like for users with
+// sight issues).
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// Switching to "mobile view" by reducing the width to 600px.
+size: (600, 600)
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+// Opening the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
+// Closing the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+// Force the sidebar open by focusing a link inside it.
+// This makes it easier for keyboard users to get to it.
+focus: ".sidebar-title a"
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
+// When we tab out of the sidebar, close it.
+focus: ".search-input"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"left": "0px"})
+
+// Click elsewhere.
+click: "body"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Check that the topbar is visible
+assert-property: (".mobile-topbar", {"clientHeight": "45"})
+
+// Check that clicking an element from the sidebar scrolls to the right place
+// so the target is not obscured by the topbar.
+click: ".sidebar-menu-toggle"
+click: ".sidebar-elems section .block li > a"
+assert-position: ("#method\.must_use", {"y": 45})
+
+// Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
+click: ".sidebar-menu-toggle"
+scroll-to: ".block.keyword li:nth-child(1)"
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
+
+// Now checking the background color of the sidebar.
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"})
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
new file mode 100644
index 000000000..fa322574f
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -0,0 +1,254 @@
+// This test ensures that the elements in the sidebar are displayed correctly.
+javascript: false
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// Since the javascript is disabled, there shouldn't be a toggle.
+assert-false: "#sidebar-toggle"
+// For some reason, we need to wait a bit here because it seems like the transition on opacity
+// is being applied whereas it can't be reproduced in a browser...
+wait-for-css: (".sidebar > *", {"visibility": "hidden", "opacity": 0})
+
+// Let's retry with javascript enabled.
+javascript: true
+reload:
+wait-for: "#sidebar-toggle"
+assert-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden", "opacity": 0})
+// Let's expand the sidebar now.
+click: "#sidebar-toggle"
+// Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`.
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+
+// We now check that opening the sidebar and clicking a link will leave it open.
+// The behavior here on desktop is different than the behavior on mobile,
+// but since the sidebar doesn't fill the entire screen here, it makes sense to have the
+// sidebar stay resident.
+wait-for-css: (".sidebar", {"width": "300px"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+click: ".sidebar a.selected"
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+wait-for-css: (".sidebar", {"width": "300px"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+
+// Now we check the display of the sidebar items.
+show-text: true
+
+// First we start with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+// Waiting for the sidebar to be displayed...
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (
+ "#source-sidebar details[open] > .files a.selected",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
+)
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"})
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
+assert-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+
+// Now with the dark theme.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+// Waiting for the sidebar to be displayed...
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (
+ "#source-sidebar details[open] > .files > a.selected",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"},
+)
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"})
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .files > a:not(.selected)",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
+assert-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+
+// And finally with the ayu theme.
+local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"}
+reload:
+// Waiting for the sidebar to be displayed...
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (
+ "#source-sidebar details[open] > .files a.selected",
+ {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"})
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
+assert-css: (
+ "#source-sidebar details[open] > .files a:not(.selected)",
+ {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+// Without hover.
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
+assert-css: (
+ "#source-sidebar details[open] > .folders > details > summary",
+ {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+
+// Now checking on mobile devices.
+size: (500, 700)
+reload:
+// Waiting for the sidebar to be displayed...
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+
+// We now check it takes the full size of the display.
+assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"})
+assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"})
+
+// We now check the display of the toggle once the sidebar is expanded.
+assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
+assert-css: (
+ "#sidebar-toggle",
+ {
+ "border-top-width": "0px",
+ "border-right-width": "0px",
+ "border-left-width": "0px",
+ "border-bottom-width": "1px",
+ },
+)
+
+// We now check that the scroll position is kept when opening the sidebar.
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "0px"})
+// We scroll to line 117 to change the scroll position.
+scroll-to: '//*[@id="117"]'
+assert-window-property: {"pageYOffset": "2519"}
+// Expanding the sidebar...
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "500px"})
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "0px"})
+// The "scrollTop" property should be the same.
+assert-window-property: {"pageYOffset": "2519"}
+
+// We now check that opening the sidebar and clicking a link will close it.
+// The behavior here on mobile is different than the behavior on desktop,
+// but common sense dictates that if you have a list of files that fills the entire screen, and
+// you click one of them, you probably want to actually see the file's contents, and not just
+// make it the current selection.
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+click: ".sidebar a.selected"
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
+// Resize back to desktop size, to check that the sidebar doesn't spontaneously open.
+size: (1000, 1000)
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml
new file mode 100644
index 000000000..e882080c7
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-source-code.goml
@@ -0,0 +1,45 @@
+// The goal of this test is to ensure that the sidebar is working as expected in the source
+// code pages.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// First: desktop mode.
+size: (1100, 800)
+// We check that the sidebar isn't expanded and has the expected width.
+assert-css: ("nav.sidebar", {"width": "50px"})
+// We now click on the button to expand the sidebar.
+click: (10, 10)
+// We wait for the sidebar to be expanded.
+wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "300px"})
+assert-css: (".source-sidebar-expanded nav.sidebar a", {"font-size": "14px"})
+// We collapse the sidebar.
+click: (10, 10)
+// We ensure that the class has been removed.
+wait-for: "html:not(.expanded)"
+assert: "nav.sidebar"
+
+// Checking that only the path to the current file is "open".
+goto: file://|DOC_PATH|/src/lib2/another_folder/sub_mod/mod.rs.html
+// First we expand the sidebar again.
+click: (10, 10)
+// We wait for the sidebar to be expanded.
+wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "300px"})
+assert: "//*[@class='dir-entry' and @open]/*[text()='lib2']"
+assert: "//*[@class='dir-entry' and @open]/*[text()='another_folder']"
+assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']"
+// Only "another_folder" should be "open" in "lib2".
+assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
+// All other trees should be collapsed.
+assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 5)
+
+// We now switch to mobile mode.
+size: (600, 600)
+wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"})
+// We collapse the sidebar.
+click: (10, 10)
+// We check that the sidebar has the expected width (0).
+assert-css: ("nav.sidebar", {"width": "0px"})
+// We ensure that the class has been removed.
+assert-false: ".source-sidebar-expanded"
+assert: "nav.sidebar"
+
+// Check that the topbar is not visible
+assert-property: (".mobile-topbar", {"offsetParent": "null"})
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
new file mode 100644
index 000000000..32fe3334f
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -0,0 +1,88 @@
+// Checks multiple things on the sidebar display (width of its elements, colors, etc).
+goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
+local-storage: {"rustdoc-theme": "light"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-text: (".sidebar > .location", "Crate test_docs")
+// In modules, we only have one "location" element.
+assert-count: (".sidebar .location", 1)
+assert-text: ("#all-types", "All Items")
+assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"})
+// We check that we have the crates list and that the "current" on is "test_docs".
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
+// And we're also supposed to have the list of items in the current module.
+assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Re-exports")
+assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Modules")
+assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Macros")
+assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Structs")
+assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Enums")
+assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Traits")
+assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Functions")
+assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Type Definitions")
+assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Unions")
+assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Keywords")
+assert-text: ("#structs + .item-table .item-left > a", "Foo")
+click: "#structs + .item-table .item-left > a"
+
+// PAGE: struct.Foo.html
+assert-count: (".sidebar .location", 2)
+// We check that there is no crate listed outside of the top level.
+assert-false: ".sidebar-elems > .crate"
+
+click: ".sidebar-elems section .block li > a"
+assert-property-false: ("html", {"scrollTop": "0"})
+
+click: ".sidebar h2.location a"
+assert-property: ("html", {"scrollTop": "0"})
+
+// We now go back to the crate page to click on the "lib2" crate link.
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(53, 109, 164)"})
+click: ".sidebar-elems .crate > ul > li:first-child > a"
+
+// PAGE: lib2/index.html
+goto: file://|DOC_PATH|/lib2/index.html
+assert-text: (".sidebar > .location", "Crate lib2")
+// We check that we have the crates list and that the "current" on is now "lib2".
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
+// We now go to the "foobar" function page.
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions")
+assert-text: ("#functions + .item-table .item-left > a", "foobar")
+click: "#functions + .item-table .item-left > a"
+
+// PAGE: fn.foobar.html
+// In items containing no items (like functions or constants) and in modules, we have one
+// "location" elements.
+assert-count: (".sidebar .location", 1)
+assert-text: (".sidebar .sidebar-elems .location", "In lib2")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./module/index.html
+assert-text: (".sidebar > .location", "Module module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./sub_module/sub_sub_module/index.html
+assert-text: (".sidebar > .location", "Module 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-left > a", "foo")
+
+// Links to trait implementations in the sidebar should not wrap even if they are long.
+goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html
+assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29})
+
+// Test that clicking on of the "In <module>" headings in the sidebar links to the
+// appropriate anchor in index.html.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+click: ".block.mod h3 a"
+// PAGE: index.html
+assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"})
diff --git a/src/test/rustdoc-gui/source-anchor-scroll.goml b/src/test/rustdoc-gui/source-anchor-scroll.goml
new file mode 100644
index 000000000..4e51c8dca
--- /dev/null
+++ b/src/test/rustdoc-gui/source-anchor-scroll.goml
@@ -0,0 +1,20 @@
+// We check that when the anchor changes and is output of the displayed content,
+// the page is scrolled to it.
+goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html
+
+// We reduce the window size to make it easier to make an element "out of the page".
+size: (600, 800)
+// We check that the scroll is at the top first.
+assert-property: ("html", {"scrollTop": "0"})
+
+click: '//a[text() = "barbar"]'
+assert-property: ("html", {"scrollTop": "125"})
+click: '//a[text() = "bar"]'
+assert-property: ("html", {"scrollTop": "166"})
+click: '//a[text() = "sub_fn"]'
+assert-property: ("html", {"scrollTop": "53"})
+
+// We now check that clicking on lines doesn't change the scroll
+// Extra information: the "sub_fn" function header is on line 1.
+click: '//*[@id="6"]'
+assert-property: ("html", {"scrollTop": "53"})
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
new file mode 100644
index 000000000..581f826a3
--- /dev/null
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -0,0 +1,49 @@
+// Checks that the interactions with the source code pages are working as expected.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// Check that we can click on the line number.
+click: ".line-numbers > span:nth-child(4)" // This is the span for line 4.
+// Ensure that the page URL was updated.
+assert-document-property: ({"URL": "lib.rs.html#4"}, ENDS_WITH)
+assert-attribute: ("//*[@id='4']", {"class": "line-highlighted"})
+// We now check that the good spans are highlighted
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html#4-6
+assert-attribute-false: (".line-numbers > span:nth-child(3)", {"class": "line-highlighted"})
+assert-attribute: (".line-numbers > span:nth-child(4)", {"class": "line-highlighted"})
+assert-attribute: (".line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
+assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
+assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
+// This is to ensure that the content is correctly align with the line numbers.
+compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+
+// Assert that the line numbers text is aligned to the right.
+assert-css: (".line-numbers", {"text-align": "right"})
+
+// Now let's check that clicking on something else than the line number doesn't
+// do anything (and certainly not add a `#NaN` to the URL!).
+show-text: true
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// We use this assert-position to know where we will click.
+assert-position: ("//*[@id='1']", {"x": 104, "y": 103})
+// We click on the left of the "1" span but still in the "line-number" `<pre>`.
+click: (103, 103)
+assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
+
+// Checking the source code sidebar.
+
+// First we "open" it.
+click: "#sidebar-toggle"
+assert: ".source-sidebar-expanded"
+
+// We check that the first entry of the sidebar is collapsed
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
+assert-text: ("#source-sidebar details:first-of-type > summary", "implementors")
+// We now click on it.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
+
+// And now we collapse it again.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
+
+// Check the spacing.
+assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml
new file mode 100644
index 000000000..0c01e2545
--- /dev/null
+++ b/src/test/rustdoc-gui/src-font-size.goml
@@ -0,0 +1,11 @@
+// This test ensures that the "[src]" have the same font size as their headers
+// to avoid having some weird height difference in the background when the element
+// is selected.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+show-text: true
+// Check the impl headers.
+assert-css: (".impl.has-srclink .srclink", {"font-size": "16px"}, ALL)
+assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "18px"}, ALL)
+// Check the impl items.
+assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
+assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
diff --git a/src/test/rustdoc-gui/src/lib2/Cargo.lock b/src/test/rustdoc-gui/src/lib2/Cargo.lock
new file mode 100644
index 000000000..a5873ceb3
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "implementors"
+version = "0.1.0"
+
+[[package]]
+name = "lib2"
+version = "0.1.0"
+dependencies = [
+ "implementors",
+]
diff --git a/src/test/rustdoc-gui/src/lib2/Cargo.toml b/src/test/rustdoc-gui/src/lib2/Cargo.toml
new file mode 100644
index 000000000..2e37f3f66
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "lib2"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+implementors = { path = "./implementors" }
diff --git a/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs b/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs
new file mode 100644
index 000000000..ec9a20859
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs
@@ -0,0 +1,3 @@
+pub fn another_fn() {}
+
+pub mod sub_mod;
diff --git a/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs b/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs
new file mode 100644
index 000000000..f16722cf3
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs
@@ -0,0 +1 @@
+pub fn subsubsub() {}
diff --git a/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs b/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs
new file mode 100644
index 000000000..9a4f007a2
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs
@@ -0,0 +1 @@
+pub fn tadam() {}
diff --git a/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock
new file mode 100644
index 000000000..cad99a991
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "implementors"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml
new file mode 100644
index 000000000..7ef1052c4
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "implementors"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
diff --git a/src/test/rustdoc-gui/src/lib2/implementors/lib.rs b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs
new file mode 100644
index 000000000..1620e8422
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs
@@ -0,0 +1,20 @@
+pub trait Whatever {
+ type Foo;
+
+ fn method() {}
+}
+
+pub struct Struct;
+
+impl Whatever for Struct {
+ type Foo = u8;
+}
+
+mod traits {
+ pub trait TraitToReexport {
+ fn method() {}
+ }
+}
+
+#[doc(inline)]
+pub use traits::TraitToReexport;
diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs
new file mode 100644
index 000000000..87f91be3a
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2/lib.rs
@@ -0,0 +1,145 @@
+// ignore-tidy-linelength
+
+#![feature(doc_cfg)]
+
+pub mod another_folder;
+pub mod another_mod;
+
+pub mod module {
+ pub mod sub_module {
+ pub mod sub_sub_module {
+ pub fn foo() {}
+ }
+ pub fn bar() {}
+ }
+ pub fn whatever() {}
+}
+
+pub fn foobar() {}
+
+pub type Alias = u32;
+
+#[doc(cfg(feature = "foo-method"))]
+pub struct Foo {
+ pub x: Alias,
+}
+
+impl Foo {
+ /// Some documentation
+ /// # A Heading
+ pub fn a_method(&self) {}
+}
+
+#[doc(cfg(feature = "foo-method"))]
+#[deprecated = "Whatever [`Foo::a_method`](#method.a_method)"]
+pub trait Trait {
+ type X;
+ const Y: u32;
+
+ #[deprecated = "Whatever [`Foo`](#tadam)"]
+ fn foo() {}
+}
+
+impl Trait for Foo {
+ type X = u32;
+ const Y: u32 = 0;
+}
+
+impl implementors::Whatever for Foo {
+ type Foo = u32;
+}
+
+#[doc(inline)]
+pub use implementors::TraitToReexport;
+
+pub struct StructToImplOnReexport;
+
+impl TraitToReexport for StructToImplOnReexport {}
+
+pub mod sub_mod {
+ /// ```txt
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// ```
+ ///
+ /// ```
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// ```
+ pub struct Foo;
+}
+
+pub mod long_trait {
+ use std::ops::DerefMut;
+
+ pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem:
+ DerefMut<Target = u32> + From<u128> + Send + Sync + AsRef<str> + 'static
+ {
+ }
+}
+
+pub mod long_table {
+ /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two |
+ /// | ----------- | ----------- | ----------- | ----------- |
+ /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two |
+ ///
+ /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq
+ pub struct Foo;
+
+ /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two |
+ /// | ----------- | ----------- | ----------- | ----------- |
+ /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two |
+ ///
+ /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq
+ impl Foo {
+ pub fn foo(&self) {}
+ }
+}
+
+pub mod summary_table {
+ /// | header 1 | header 2 |
+ /// | -------- | -------- |
+ /// | content | content |
+ pub struct Foo;
+}
+
+pub mod too_long {
+ pub type ReallyLongTypeNameLongLongLong =
+ Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>;
+
+ pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0;
+
+ /// This also has a really long doccomment. Lorem ipsum dolor sit amet,
+ /// consectetur adipiscing elit. Suspendisse id nibh malesuada, hendrerit
+ /// massa vel, tincidunt est. Nulla interdum, sem ac efficitur ornare, arcu
+ /// nunc dignissim nibh, at rutrum diam augue ac mauris. Fusce tincidunt et
+ /// ligula sed viverra. Aenean sed facilisis dui, non volutpat felis. In
+ /// vitae est dui. Donec felis nibh, blandit at nibh eu, tempor suscipit
+ /// nisl. Vestibulum ornare porta libero, eu faucibus purus iaculis ut. Ut
+ /// quis tincidunt nunc, in mollis purus. Nulla sed interdum quam. Nunc
+ /// vitae cursus ex.
+ pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+ pub a: u32,
+ }
+
+ impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+ /// ```
+ /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 };
+ /// ```
+ pub fn foo(&self) {}
+ }
+}
+
+pub struct HasALongTraitWithParams {}
+
+pub trait LongTraitWithParamsBananaBananaBanana<T> {}
+
+impl LongTraitWithParamsBananaBananaBanana<usize> for HasALongTraitWithParams {}
+
+#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
+pub struct LongItemInfo;
+
+pub trait SimpleTrait {}
+pub struct LongItemInfo2;
+
+/// Some docs.
+#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
+impl SimpleTrait for LongItemInfo2 {}
diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock
new file mode 100644
index 000000000..e4b4e52d0
--- /dev/null
+++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "link_to_definition"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml
new file mode 100644
index 000000000..cdd294d74
--- /dev/null
+++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "link_to_definition"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
diff --git a/src/test/rustdoc-gui/src/link_to_definition/lib.rs b/src/test/rustdoc-gui/src/link_to_definition/lib.rs
new file mode 100644
index 000000000..419a9ccee
--- /dev/null
+++ b/src/test/rustdoc-gui/src/link_to_definition/lib.rs
@@ -0,0 +1,35 @@
+pub fn sub_fn() {
+ barbar();
+}
+fn barbar() {
+ bar(vec![], vec![], vec![], vec![], Bar { a: "a".into(), b: 0 });
+}
+
+pub struct Bar {
+ pub a: String,
+ pub b: u32,
+}
+
+pub fn foo(_b: &Bar) {}
+
+// The goal now is to add
+// a lot of lines so
+// that the next content
+// will be out of the screen
+// to allow us to test that
+// if the anchor changes to
+// something outside of the
+// current view, it'll
+// scroll to it as expected.
+
+// More filling content.
+
+pub fn bar(
+ _a: Vec<String>,
+ _b: Vec<String>,
+ _c: Vec<String>,
+ _d: Vec<String>,
+ _e: Bar,
+) {
+ sub_fn();
+}
diff --git a/src/test/rustdoc-gui/src/settings/.cargo/config.toml b/src/test/rustdoc-gui/src/settings/.cargo/config.toml
new file mode 100644
index 000000000..bbb8d11a2
--- /dev/null
+++ b/src/test/rustdoc-gui/src/settings/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+rustdocflags = ["--default-theme", "ayu"]
diff --git a/src/test/rustdoc-gui/src/settings/Cargo.lock b/src/test/rustdoc-gui/src/settings/Cargo.lock
new file mode 100644
index 000000000..6f0de1ac1
--- /dev/null
+++ b/src/test/rustdoc-gui/src/settings/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "settings"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/settings/Cargo.toml b/src/test/rustdoc-gui/src/settings/Cargo.toml
new file mode 100644
index 000000000..c8a211a47
--- /dev/null
+++ b/src/test/rustdoc-gui/src/settings/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "settings"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
diff --git a/src/test/rustdoc-gui/src/settings/lib.rs b/src/test/rustdoc-gui/src/settings/lib.rs
new file mode 100644
index 000000000..b76b4321d
--- /dev/null
+++ b/src/test/rustdoc-gui/src/settings/lib.rs
@@ -0,0 +1 @@
+pub fn foo() {}
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.lock b/src/test/rustdoc-gui/src/staged_api/Cargo.lock
new file mode 100644
index 000000000..6e8eba56c
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "staged_api"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.toml b/src/test/rustdoc-gui/src/staged_api/Cargo.toml
new file mode 100644
index 000000000..117c4134e
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "staged_api"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "lib.rs"
+
+[features]
+default = ["some_feature"]
+some_feature = []
diff --git a/src/test/rustdoc-gui/src/staged_api/lib.rs b/src/test/rustdoc-gui/src/staged_api/lib.rs
new file mode 100644
index 000000000..0cb460f03
--- /dev/null
+++ b/src/test/rustdoc-gui/src/staged_api/lib.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "some_feature", since = "1.3.5")]
+
+#[stable(feature = "some_feature", since = "1.3.5")]
+pub struct Foo {}
+
+impl Foo {
+ #[stable(feature = "some_feature", since = "1.3.5")]
+ pub fn bar() {}
+}
diff --git a/src/test/rustdoc-gui/src/test_docs/Cargo.lock b/src/test/rustdoc-gui/src/test_docs/Cargo.lock
new file mode 100644
index 000000000..6b80f6e88
--- /dev/null
+++ b/src/test/rustdoc-gui/src/test_docs/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "test_docs"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/test_docs/Cargo.toml b/src/test/rustdoc-gui/src/test_docs/Cargo.toml
new file mode 100644
index 000000000..8be819b76
--- /dev/null
+++ b/src/test/rustdoc-gui/src/test_docs/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "test_docs"
+version = "0.1.0"
+edition = "2018"
+
+build = "build.rs"
+
+[lib]
+path = "lib.rs"
+
+[features]
+default = ["some-feature"]
+some-feature = []
diff --git a/src/test/rustdoc-gui/src/test_docs/build.rs b/src/test/rustdoc-gui/src/test_docs/build.rs
new file mode 100644
index 000000000..16c96ded9
--- /dev/null
+++ b/src/test/rustdoc-gui/src/test_docs/build.rs
@@ -0,0 +1,15 @@
+//! generate 2000 constants for testing
+
+use std::{fs::write, path::PathBuf};
+
+fn main() -> std::io::Result<()> {
+ let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not defined");
+
+ let mut output = String::new();
+ for i in 0..2000 {
+ let line = format!("/// Some const A{0}\npub const A{0}: isize = 0;\n", i);
+ output.push_str(&*line);
+ };
+
+ write(&[&*out_dir, "huge_amount_of_consts.rs"].iter().collect::<PathBuf>(), output)
+}
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
new file mode 100644
index 000000000..1b26aaecb
--- /dev/null
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -0,0 +1,295 @@
+//! The point of this crate is to be able to have enough different "kinds" of
+//! documentation generated so we can test each different features.
+#![doc(html_playground_url="https://play.rust-lang.org/")]
+
+#![crate_name = "test_docs"]
+#![feature(rustdoc_internals)]
+#![feature(doc_cfg)]
+
+use std::convert::AsRef;
+use std::fmt;
+
+/// Basic function with some code examples:
+///
+/// ```
+/// println!("nothing fancy");
+/// println!("but with two lines!");
+/// ```
+///
+/// A failing to compile one:
+///
+/// ```compile_fail
+/// println!("where did my argument {} go? :'(");
+/// ```
+///
+/// An ignored one:
+///
+/// ```ignore (it's a test)
+/// Let's say I'm just some text will ya?
+/// ```
+///
+/// An inlined `code`!
+pub fn foo() {}
+
+/// Just a normal struct.
+pub struct Foo;
+
+impl Foo {
+ #[must_use]
+ pub fn must_use(&self) -> bool {
+ true
+ }
+}
+
+impl AsRef<str> for Foo {
+ fn as_ref(&self) -> &str {
+ "hello"
+ }
+}
+
+/// Just a normal enum.
+///
+/// # title!
+#[doc(alias = "ThisIsAnAlias")]
+pub enum WhoLetTheDogOut {
+ /// Woof!
+ Woof,
+ /// Meoooooooow...
+ Meow,
+}
+
+/// Who doesn't love to wrap a `format!` call?
+pub fn some_more_function<T: fmt::Debug>(t: &T) -> String {
+ format!("{:?}", t)
+}
+
+/// Woohoo! A trait!
+pub trait AnotherOne {
+ /// Some func 3.
+ fn func3();
+
+ /// Some func 1.
+ fn func1();
+
+ fn another();
+ fn why_not();
+
+ /// Some func 2.
+ fn func2();
+
+ fn hello();
+}
+
+/// ```compile_fail
+/// whatever
+/// ```
+///
+/// Check for "i" signs in lists!
+///
+/// 1. elem 1
+/// 2. test 1
+/// ```compile_fail
+/// fn foo() {}
+/// ```
+/// 3. elem 3
+/// 4. ```ignore (it's a test)
+/// fn foo() {}
+/// ```
+/// 5. elem 5
+///
+/// Final one:
+///
+/// ```ignore (still a test)
+/// let x = 12;
+/// ```
+pub fn check_list_code_block() {}
+
+/// a thing with a label
+#[deprecated(since = "1.0.0", note = "text why this deprecated")]
+#[doc(cfg(unix))]
+pub fn replaced_function() {}
+
+/// Some doc with `code`!
+pub enum AnEnum {
+ WithVariants { and: usize, sub: usize, variants: usize },
+}
+
+#[doc(keyword = "CookieMonster")]
+/// Some keyword.
+pub mod keyword {}
+
+/// Just some type alias.
+pub type SomeType = u32;
+
+pub mod huge_amount_of_consts {
+ include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
+}
+
+/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
+pub mod long_code_block {}
+
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+pub use crate::repro as repro2;
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+///
+/// #### You know the drill.
+///
+/// More text.
+pub struct HeavilyDocumentedStruct {
+ /// # Title for field
+ /// ## Sub-heading for field
+ pub nothing: (),
+}
+
+/// # Title for struct impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for struct impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for struct impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedStruct {
+ /// # Title for struct impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for struct impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for struct impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub enum HeavilyDocumentedEnum {
+ /// # None prose title
+ /// ## None prose sub-heading
+ None,
+ /// # Wrapped prose title
+ /// ## Wrapped prose sub-heading
+ Wrapped(
+ /// # Wrapped.0 prose title
+ /// ## Wrapped.0 prose sub-heading
+ String,
+ String,
+ ),
+ Structy {
+ /// # Structy prose title
+ /// ## Structy prose sub-heading
+ alpha: String,
+ beta: String,
+ },
+}
+
+/// # Title for enum impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for enum impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for enum impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedEnum {
+ /// # Title for enum impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for enum impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for enum impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+pub union HeavilyDocumentedUnion {
+ /// # Title for union variant
+ /// ## Sub-heading for union variant
+ pub nothing: (),
+ pub something: f32,
+}
+
+/// # Title for union impl doc
+/// ## Sub-heading for union impl doc
+impl HeavilyDocumentedUnion {
+ /// # Title for union impl-item doc
+ /// ## Sub-heading for union impl-item doc
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+#[macro_export]
+macro_rules! heavily_documented_macro {
+ () => {};
+}
+
+pub trait EmptyTrait1 {}
+pub trait EmptyTrait2 {}
+pub trait EmptyTrait3 {}
+
+pub struct HasEmptyTraits{}
+
+impl EmptyTrait1 for HasEmptyTraits {}
+impl EmptyTrait2 for HasEmptyTraits {}
+#[doc(cfg(feature = "some-feature"))]
+impl EmptyTrait3 for HasEmptyTraits {}
+
+mod macros;
+pub use macros::*;
+
+#[doc(alias = "AliasForTheStdReexport")]
+pub use ::std as TheStdReexport;
+
+pub mod details {
+ /// We check the appearance of the `<details>`/`<summary>` in here.
+ ///
+ /// ## Hello
+ ///
+ /// <details>
+ /// <summary><h4>I'm a summary</h4></summary>
+ /// <div>I'm the content of the details!</div>
+ /// </details>
+ pub struct Details;
+}
diff --git a/src/test/rustdoc-gui/src/test_docs/macros.rs b/src/test/rustdoc-gui/src/test_docs/macros.rs
new file mode 100644
index 000000000..07b2b9792
--- /dev/null
+++ b/src/test/rustdoc-gui/src/test_docs/macros.rs
@@ -0,0 +1,4 @@
+#[macro_export]
+macro_rules! a{ () => {}}
+#[macro_export]
+macro_rules! b{ () => {}}
diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml
new file mode 100644
index 000000000..fb1c37ae6
--- /dev/null
+++ b/src/test/rustdoc-gui/theme-change.goml
@@ -0,0 +1,32 @@
+// Ensures that the theme change is working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+click: "#settings-menu"
+wait-for: "#theme-ayu"
+click: "#theme-ayu"
+// should be the ayu theme so let's check the color.
+wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" })
+assert-local-storage: { "rustdoc-theme": "ayu" }
+click: "#theme-light"
+// should be the light theme so let's check the color.
+wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+click: "#theme-dark"
+// Should be the dark theme so let's check the color.
+wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
+click: "#theme-light"
+wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+
+click: "#theme-dark"
+wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+click: "#theme-ayu"
+wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" })
+assert-local-storage: { "rustdoc-theme": "ayu" }
diff --git a/src/test/rustdoc-gui/theme-in-history.goml b/src/test/rustdoc-gui/theme-in-history.goml
new file mode 100644
index 000000000..f576ced1c
--- /dev/null
+++ b/src/test/rustdoc-gui/theme-in-history.goml
@@ -0,0 +1,28 @@
+// Ensures that the theme is working when going back in history.
+goto: file://|DOC_PATH|/test_docs/index.html
+// Set the theme to dark.
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+// We reload the page so the local storage settings are being used.
+reload:
+assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+// Now we go to the settings page.
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
+// We change the theme to "light".
+click: "#theme-light"
+wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+
+// We go back in history.
+history-go-back:
+// Confirm that we're not on the settings page.
+assert-false: "#settings"
+// Check that the current theme is still "light".
+assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
diff --git a/src/test/rustdoc-gui/toggle-click-deadspace.goml b/src/test/rustdoc-gui/toggle-click-deadspace.goml
new file mode 100644
index 000000000..4a328c9f9
--- /dev/null
+++ b/src/test/rustdoc-gui/toggle-click-deadspace.goml
@@ -0,0 +1,12 @@
+// This test ensures that clicking on a method summary, but not on the "[-]",
+// doesn't toggle the <details>.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+click: "h4.code-header" // This is the position of "pub" in "pub fn a_method"
+assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+click: ".impl-items .rustdoc-toggle summary::before" // This is the position of "[-]" next to that pub fn.
+assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
+
+// Click the "Trait" part of "impl Trait" and verify it navigates.
+click: "#impl-Trait-for-Foo h3 a:first-of-type"
+assert-text: (".fqn .in-band", "Trait lib2::Trait")
diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml
new file mode 100644
index 000000000..ee6bc3cf7
--- /dev/null
+++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml
@@ -0,0 +1,33 @@
+// Checks that the documentation toggles on mobile have the correct position, style and work
+// as expected.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+size: (433, 600)
+assert-attribute: (".top-doc", {"open": ""})
+click: (4, 270) // This is the position of the top doc comment toggle
+assert-attribute-false: (".top-doc", {"open": ""})
+click: (4, 270)
+assert-attribute: (".top-doc", {"open": ""})
+// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
+click: (3, 270)
+assert-attribute: (".top-doc", {"open": ""})
+
+// Assert the position of the toggle on the top doc block.
+assert-position: (".top-doc summary::before", {"x": 4})
+// Assert the position of the toggle on the impl block.
+assert-position: ("#implementations-list > details > summary::before", {"x": 4})
+// Assert the position of the toggle on a method.
+assert-position: (
+ "#trait-implementations-list .impl-items .method-toggle > summary::before",
+ {"x": 4},
+)
+
+// Now we do the same but with a little bigger width
+size: (600, 600)
+assert-attribute: (".top-doc", {"open": ""})
+click: (4, 270) // New Y position since all search elements are back on one line.
+assert-attribute-false: (".top-doc", {"open": ""})
+click: (4, 270)
+assert-attribute: (".top-doc", {"open": ""})
+// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
+click: (3, 270)
+assert-attribute: (".top-doc", {"open": ""})
diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml
new file mode 100644
index 000000000..63962b576
--- /dev/null
+++ b/src/test/rustdoc-gui/toggle-docs.goml
@@ -0,0 +1,42 @@
+// Checks that the documentation toggles have the correct position, style and work as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
+click: "#toggle-all-docs"
+wait-for: 50
+// This is now collapsed so there shouldn't be the "open" attribute on details.
+assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[+]")
+click: "#toggle-all-docs"
+// Not collapsed anymore so the "open" attribute should be back.
+wait-for-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
+
+// Check that it works on non-module pages as well.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// We first check that everything is visible.
+assert-text: ("#toggle-all-docs", "[−]")
+assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute-false: (
+ "#blanket-implementations-list > details.rustdoc-toggle",
+ {"open": ""},
+ ALL,
+)
+
+// We collapse them all.
+click: "#toggle-all-docs"
+wait-for-text: ("#toggle-all-docs", "[+]")
+// We check that all <details> are collapsed (except for the impl block ones).
+assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
+// We now check that the other impl blocks are collapsed.
+assert-attribute-false: (
+ "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
+ {"open": ""},
+ ALL,
+)
+// We open them all again.
+click: "#toggle-all-docs"
+wait-for-text: ("#toggle-all-docs", "[−]")
+assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
diff --git a/src/test/rustdoc-gui/toggle-implementors.goml b/src/test/rustdoc-gui/toggle-implementors.goml
new file mode 100644
index 000000000..15521ff0f
--- /dev/null
+++ b/src/test/rustdoc-gui/toggle-implementors.goml
@@ -0,0 +1,4 @@
+// This test ensures that the implementors toggle are not open by default.
+goto: file://|DOC_PATH|/implementors/trait.Whatever.html
+
+assert-attribute-false: ("#implementors-list > details", {"open": ""}, ALL)
diff --git a/src/test/rustdoc-gui/toggled-open-implementations.goml b/src/test/rustdoc-gui/toggled-open-implementations.goml
new file mode 100644
index 000000000..bc97b38c8
--- /dev/null
+++ b/src/test/rustdoc-gui/toggled-open-implementations.goml
@@ -0,0 +1,5 @@
+// This tests that the "implementations" section on struct/enum pages
+// has all the implementations toggled open by default, so users can
+// find method names in those implementations with Ctrl-F.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""})
diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
new file mode 100644
index 000000000..d77d1dca4
--- /dev/null
+++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
@@ -0,0 +1,8 @@
+// Checks that the elements in the sidebar are alphabetically sorted.
+goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
+assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another")
+assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1")
+assert-text: (".sidebar-elems section .block li:nth-of-type(3) > a", "func2")
+assert-text: (".sidebar-elems section .block li:nth-of-type(4) > a", "func3")
+assert-text: (".sidebar-elems section .block li:nth-of-type(5) > a", "hello")
+assert-text: (".sidebar-elems section .block li:nth-of-type(6) > a", "why_not")
diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml
new file mode 100644
index 000000000..22212a317
--- /dev/null
+++ b/src/test/rustdoc-gui/type-declation-overflow.goml
@@ -0,0 +1,37 @@
+// This test ensures that the items declaration content overflow is handled inside the <pre> directly.
+goto: file://|DOC_PATH|/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// Logically, the <body> scroll width should be the width of the window.
+assert-property: ("body", {"scrollWidth": "1100"})
+// However, since there is overflow in the type declaration, its scroll width is bigger.
+assert-property: (".item-decl pre", {"scrollWidth": "1324"})
+
+// In the table-ish view on the module index, the name should not be wrapped more than necessary.
+goto: file://|DOC_PATH|/lib2/too_long/index.html
+assert-property: (".item-table .struct", {"offsetWidth": "684"})
+
+// We now make the same check on type declaration...
+goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
+assert-property: ("body", {"scrollWidth": "1100"})
+// We now check that the section width hasn't grown because of it.
+assert-property: ("#main-content", {"scrollWidth": "825"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "1103"})
+
+// ... and constant.
+// On a sidenote, it also checks that the (very) long title isn't changing the docblock width.
+goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html
+assert-property: ("body", {"scrollWidth": "1100"})
+// We now check that the section width hasn't grown because of it.
+assert-property: ("#main-content", {"scrollWidth": "825"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "950"})
+
+// On mobile:
+size: (600, 600)
+goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
+// It shouldn't have an overflow in the topbar either.
+assert-property: (".mobile-topbar .location", {"scrollWidth": "492"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "492"})
+assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-js-std/alias-1.js b/src/test/rustdoc-js-std/alias-1.js
new file mode 100644
index 000000000..7c6327fcd
--- /dev/null
+++ b/src/test/rustdoc-js-std/alias-1.js
@@ -0,0 +1,7 @@
+const QUERY = '&';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'reference' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js
new file mode 100644
index 000000000..798fa29ef
--- /dev/null
+++ b/src/test/rustdoc-js-std/alias-2.js
@@ -0,0 +1,10 @@
+const QUERY = '+';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::ops', 'name': 'AddAssign' },
+ { 'path': 'std::ops', 'name': 'Add' },
+ { 'path': 'core::ops', 'name': 'AddAssign' },
+ { 'path': 'core::ops', 'name': 'Add' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/alias-3.js b/src/test/rustdoc-js-std/alias-3.js
new file mode 100644
index 000000000..392b1e818
--- /dev/null
+++ b/src/test/rustdoc-js-std/alias-3.js
@@ -0,0 +1,7 @@
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/alias-4.js b/src/test/rustdoc-js-std/alias-4.js
new file mode 100644
index 000000000..bf2bb4d29
--- /dev/null
+++ b/src/test/rustdoc-js-std/alias-4.js
@@ -0,0 +1,7 @@
+const QUERY = '<';
+
+const EXPECTED = {
+ 'others': [
+ { 'name': 'Ord' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/alias.js b/src/test/rustdoc-js-std/alias.js
new file mode 100644
index 000000000..2b709c991
--- /dev/null
+++ b/src/test/rustdoc-js-std/alias.js
@@ -0,0 +1,11 @@
+// ignore-order
+
+const QUERY = '[';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'slice' },
+ { 'path': 'std::ops', 'name': 'IndexMut' },
+ { 'path': 'std::ops', 'name': 'Index' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/asrawfd.js b/src/test/rustdoc-js-std/asrawfd.js
new file mode 100644
index 000000000..fd228a590
--- /dev/null
+++ b/src/test/rustdoc-js-std/asrawfd.js
@@ -0,0 +1,14 @@
+// ignore-order
+
+const QUERY = 'RawFd::as_raw_fd';
+
+const EXPECTED = {
+ 'others': [
+ // Reproduction test for https://github.com/rust-lang/rust/issues/78724
+ // Validate that type alias methods get the correct path.
+ { 'path': 'std::os::unix::io::AsRawFd', 'name': 'as_raw_fd' },
+ { 'path': 'std::os::wasi::io::AsRawFd', 'name': 'as_raw_fd' },
+ { 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' },
+ { 'path': 'std::os::unix::io::RawFd', 'name': 'as_raw_fd' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/basic.js b/src/test/rustdoc-js-std/basic.js
new file mode 100644
index 000000000..824cac710
--- /dev/null
+++ b/src/test/rustdoc-js-std/basic.js
@@ -0,0 +1,15 @@
+const QUERY = 'String';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::string', 'name': 'String' },
+ { 'path': 'std::ffi', 'name': 'CString' },
+ { 'path': 'std::ffi', 'name': 'OsString' },
+ ],
+ 'in_args': [
+ { 'path': 'std::str', 'name': 'eq' },
+ ],
+ 'returned': [
+ { 'path': 'std::string::String', 'name': 'add' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/deduplication.js b/src/test/rustdoc-js-std/deduplication.js
new file mode 100644
index 000000000..f02f6cf55
--- /dev/null
+++ b/src/test/rustdoc-js-std/deduplication.js
@@ -0,0 +1,11 @@
+// ignore-order
+
+const QUERY = 'is_nan';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::f32', 'name': 'is_nan' },
+ { 'path': 'std::f64', 'name': 'is_nan' },
+ { 'path': 'std::option::Option', 'name': 'is_none' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/enum-option.js b/src/test/rustdoc-js-std/enum-option.js
new file mode 100644
index 000000000..902e09069
--- /dev/null
+++ b/src/test/rustdoc-js-std/enum-option.js
@@ -0,0 +1,7 @@
+const QUERY = 'enum:Option';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::option', 'name': 'Option' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/filter-crate.js b/src/test/rustdoc-js-std/filter-crate.js
new file mode 100644
index 000000000..b47a1fefa
--- /dev/null
+++ b/src/test/rustdoc-js-std/filter-crate.js
@@ -0,0 +1,9 @@
+// exact-check
+
+const QUERY = '"hashmap"';
+const FILTER_CRATE = 'core';
+
+const EXPECTED = {
+ 'others': [
+ ],
+};
diff --git a/src/test/rustdoc-js-std/fn-forget.js b/src/test/rustdoc-js-std/fn-forget.js
new file mode 100644
index 000000000..66a5fcaa7
--- /dev/null
+++ b/src/test/rustdoc-js-std/fn-forget.js
@@ -0,0 +1,8 @@
+const QUERY = 'fn:forget';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::mem', 'name': 'forget' },
+ { 'path': 'std::fmt', 'name': 'format' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/from_u.js b/src/test/rustdoc-js-std/from_u.js
new file mode 100644
index 000000000..e3f3cd436
--- /dev/null
+++ b/src/test/rustdoc-js-std/from_u.js
@@ -0,0 +1,9 @@
+const QUERY = 'from_u';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::char', 'name': 'from_u32' },
+ { 'path': 'std::str', 'name': 'from_utf8' },
+ { 'path': 'std::string::String', 'name': 'from_utf8' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/keyword.js b/src/test/rustdoc-js-std/keyword.js
new file mode 100644
index 000000000..868ddd7b6
--- /dev/null
+++ b/src/test/rustdoc-js-std/keyword.js
@@ -0,0 +1,10 @@
+// ignore-order
+
+const QUERY = 'fn';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'fn', ty: 15 }, // 15 is for primitive types
+ { 'path': 'std', 'name': 'fn', ty: 21 }, // 21 is for keywords
+ ],
+};
diff --git a/src/test/rustdoc-js-std/macro-check.js b/src/test/rustdoc-js-std/macro-check.js
new file mode 100644
index 000000000..242e0cbf5
--- /dev/null
+++ b/src/test/rustdoc-js-std/macro-check.js
@@ -0,0 +1,10 @@
+// ignore-order
+
+const QUERY = 'panic';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'panic', ty: 14 }, // 15 is for macros
+ { 'path': 'std', 'name': 'panic', ty: 0 }, // 0 is for modules
+ ],
+};
diff --git a/src/test/rustdoc-js-std/macro-print.js b/src/test/rustdoc-js-std/macro-print.js
new file mode 100644
index 000000000..858046e72
--- /dev/null
+++ b/src/test/rustdoc-js-std/macro-print.js
@@ -0,0 +1,10 @@
+const QUERY = 'macro:print';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'print' },
+ { 'path': 'std', 'name': 'eprint' },
+ { 'path': 'std', 'name': 'println' },
+ { 'path': 'std', 'name': 'eprintln' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/never.js b/src/test/rustdoc-js-std/never.js
new file mode 100644
index 000000000..392b1e818
--- /dev/null
+++ b/src/test/rustdoc-js-std/never.js
@@ -0,0 +1,7 @@
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js
new file mode 100644
index 000000000..dc42031e0
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-errors.js
@@ -0,0 +1,385 @@
+const QUERY = [
+ '<P>',
+ '-> <P>',
+ 'a<"P">',
+ '"P" "P"',
+ 'P "P"',
+ '"p" p',
+ '"const": p',
+ "a<:a>",
+ "a<::a>",
+ "((a))",
+ "(p -> p",
+ "::a::b",
+ "a::::b",
+ "a::b::",
+ ":a",
+ "a b:",
+ "a (b:",
+ "_:",
+ "a-bb",
+ "a>bb",
+ "ab'",
+ "a->",
+ '"p" <a>',
+ '"p" a<a>',
+ "a,<",
+ "aaaaa<>b",
+ "fn:aaaaa<>b",
+ "->a<>b",
+ "a<->",
+ "a:: a",
+ "a ::a",
+ "a<a>:",
+ "a<>:",
+ "a,:",
+ " a<> :",
+ "mod : :",
+ "a!a",
+ "a!!",
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: "<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "<p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "-> <P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "-> <p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<\"P\">",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<\"p\">",
+ error: "`\"` cannot be used in generics",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"P\" \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" \"p\"",
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "P \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p \"p\"",
+ error: "Cannot use literal search when there is more than one element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"p\" p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" p",
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"const\": p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"const\": p",
+ error: "You cannot use quotes on type filter",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<:a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<:a>",
+ error: "Unexpected `:` after `<`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<::a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<::a>",
+ error: "Unexpected `::`: paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "((a))",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "((a))",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "(p -> p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "(p -> p",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "::a::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "::a::b",
+ error: "Paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::::b",
+ error: "Unexpected `::::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::b::",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b::",
+ error: "Paths cannot end with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ":a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ":a",
+ error: "Expected type filter before `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b:",
+ error: "Unexpected `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a (b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a (b:",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "_:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "_:",
+ error: "Unknown type filter `_`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a-bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a-bb",
+ error: "Unexpected `-` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a>bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a>bb",
+ error: "Unexpected `>` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "ab'",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "ab'",
+ error: "Unexpected `'`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a->",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a->",
+ error: "Expected at least one item after `->`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" <a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" <a>',
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" a<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" a<a>',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a,<',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a,<',
+ error: 'Found generics without a path',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'aaaaa<>b',
+ error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'fn:aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'fn:aaaaa<>b',
+ error: 'Expected `,`, ` ` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->a<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->a<>b',
+ error: 'Expected `,` or ` `, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a<->',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<->',
+ error: 'Unexpected `-` after `<`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a:: a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a:: a',
+ error: 'Paths cannot end with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a ::a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a ::a',
+ error: 'Paths cannot start with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<a>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<a>:",
+ error: 'Unexpected `:`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<>:",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,:",
+ error: 'Unexpected `,` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<> :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<> :",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "mod : :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod : :",
+ error: 'Unexpected `:`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a!a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!a",
+ error: '`!` can only be at the end of an ident',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a!!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!!",
+ error: 'Cannot have more than one `!` in an ident',
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-filter.js b/src/test/rustdoc-js-std/parser-filter.js
new file mode 100644
index 000000000..e5a87a415
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-filter.js
@@ -0,0 +1,43 @@
+const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "fn:foo",
+ returned: [],
+ typeFilter: 5,
+ userQuery: "fn:foo",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "enum : foo",
+ returned: [],
+ typeFilter: 4,
+ userQuery: "enum : foo",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "macro<f>:foo",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "macro<f>:foo",
+ error: "Unexpected `:`",
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js
new file mode 100644
index 000000000..0cf7f5019
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-generics.js
@@ -0,0 +1,62 @@
+const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>'];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'A<B<C<D>, E>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<b<c<d>, e>',
+ error: 'Unexpected `<` after `<`',
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ {
+ name: "u8",
+ fullPath: ["u8"],
+ pathWithoutLast: [],
+ pathLast: "u8",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "p<> u8",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p<> u8",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: '"p"<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p"<a>',
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-ident.js b/src/test/rustdoc-js-std/parser-ident.js
new file mode 100644
index 000000000..4b5ab01ac
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-ident.js
@@ -0,0 +1,93 @@
+const QUERY = [
+ "R<!>",
+ "!",
+ "a!",
+ "a!::b",
+ "a!::b!",
+];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "r",
+ fullPath: ["r"],
+ pathWithoutLast: [],
+ pathLast: "r",
+ generics: [
+ {
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ },
+ ],
+ }],
+ foundElems: 1,
+ original: "R<!>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "r<!>",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "!",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "a!",
+ fullPath: ["a!"],
+ pathWithoutLast: [],
+ pathLast: "a!",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "a!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "a!::b",
+ fullPath: ["a!", "b"],
+ pathWithoutLast: ["a!"],
+ pathLast: "b",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "a!::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!::b",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "a!::b!",
+ fullPath: ["a!", "b!"],
+ pathWithoutLast: ["a!"],
+ pathLast: "b!",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "a!::b!",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a!::b!",
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-literal.js b/src/test/rustdoc-js-std/parser-literal.js
new file mode 100644
index 000000000..87b3baff1
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-literal.js
@@ -0,0 +1,27 @@
+const QUERY = ['R<P>'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "r",
+ fullPath: ["r"],
+ pathWithoutLast: [],
+ pathLast: "r",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ foundElems: 1,
+ original: "R<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "r<p>",
+ error: null,
+ }
+];
diff --git a/src/test/rustdoc-js-std/parser-paths.js b/src/test/rustdoc-js-std/parser-paths.js
new file mode 100644
index 000000000..9f823f933
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-paths.js
@@ -0,0 +1,90 @@
+const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "A::B",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b,c',
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [
+ {
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [],
+ },
+ ],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B<f>,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b<f>,c',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "mod::a",
+ fullPath: ["mod", "a"],
+ pathWithoutLast: ["mod"],
+ pathLast: "a",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "mod::a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod::a",
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-quote.js b/src/test/rustdoc-js-std/parser-quote.js
new file mode 100644
index 000000000..1e16c90de
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-quote.js
@@ -0,0 +1,87 @@
+const QUERY = [
+ '-> "p"',
+ '"p",',
+ '"p" -> a',
+ '"a" -> "p"',
+ '->"-"',
+ '"a',
+ '""',
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: '-> "p"',
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: '-> "p"',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: '"p",',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p",',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" -> a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" -> a',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a" -> "p"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a" -> "p"',
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->"-"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->"-"',
+ error: 'Unexpected `-` in a string element',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a',
+ error: 'Unclosed `"`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '""',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '""',
+ error: 'Cannot have empty string element',
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js
new file mode 100644
index 000000000..6fce17dca
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-returned.js
@@ -0,0 +1,99 @@
+const QUERY = [
+ "-> F<P>",
+ "-> P",
+ "->,a",
+ "aaaaa->a",
+ "-> !",
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> F<P>",
+ returned: [{
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ typeFilter: -1,
+ userQuery: "-> f<p>",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> P",
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "-> p",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "->,a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "->,a",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "aaaaa",
+ fullPath: ["aaaaa"],
+ pathWithoutLast: [],
+ pathLast: "aaaaa",
+ generics: [],
+ }],
+ foundElems: 2,
+ original: "aaaaa->a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "aaaaa->a",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> !",
+ returned: [{
+ name: "!",
+ fullPath: ["!"],
+ pathWithoutLast: [],
+ pathLast: "!",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "-> !",
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-separators.js b/src/test/rustdoc-js-std/parser-separators.js
new file mode 100644
index 000000000..5b7abdfa8
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-separators.js
@@ -0,0 +1,206 @@
+// ignore-tidy-tab
+
+const QUERY = [
+ 'aaaaaa b',
+ 'a b',
+ 'a,b',
+ 'a\tb',
+ 'a<b c>',
+ 'a<b,c>',
+ 'a<b\tc>',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: 'aaaaaa',
+ fullPath: ['aaaaaa'],
+ pathWithoutLast: [],
+ pathLast: 'aaaaaa',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaaaaa b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaaaaa b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a,b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a\tb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a\tb",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b,c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b,c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b\tc>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b\tc>",
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/parser-weird-queries.js b/src/test/rustdoc-js-std/parser-weird-queries.js
new file mode 100644
index 000000000..a3d85aeca
--- /dev/null
+++ b/src/test/rustdoc-js-std/parser-weird-queries.js
@@ -0,0 +1,123 @@
+// This test is mostly to check that the parser still kinda outputs something
+// (and doesn't enter an infinite loop!) even though the query is completely
+// invalid.
+const QUERY = [
+ 'a b',
+ 'a b',
+ 'a,b(c)',
+ 'aaa,a',
+ ',,,,',
+ 'mod :',
+ 'mod\t:',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,b(c)",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b(c)",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [
+ {
+ name: "aaa",
+ fullPath: ["aaa"],
+ pathWithoutLast: [],
+ pathLast: "aaa",
+ generics: [],
+ },
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaa,a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaa,a",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ",,,,",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ",,,,",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod :',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod :',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod\t:',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod\t:',
+ error: null,
+ },
+];
diff --git a/src/test/rustdoc-js-std/path-ordering.js b/src/test/rustdoc-js-std/path-ordering.js
new file mode 100644
index 000000000..7dcdd4023
--- /dev/null
+++ b/src/test/rustdoc-js-std/path-ordering.js
@@ -0,0 +1,12 @@
+const QUERY = 'hashset::insert';
+
+const EXPECTED = {
+ 'others': [
+ // ensure hashset::insert comes first
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
+ { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/primitive.js b/src/test/rustdoc-js-std/primitive.js
new file mode 100644
index 000000000..e5690383e
--- /dev/null
+++ b/src/test/rustdoc-js-std/primitive.js
@@ -0,0 +1,75 @@
+const QUERY = [
+ 'i8',
+ 'u32',
+ 'str',
+ 'char',
+ 'unit',
+ 'tuple',
+ 'fn',
+];
+
+const EXPECTED = [
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'i8',
+ 'href': '../std/primitive.i8.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'u32',
+ 'href': '../std/primitive.u32.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'str',
+ 'href': '../std/primitive.str.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'char',
+ 'href': '../std/primitive.char.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'unit',
+ 'href': '../std/primitive.unit.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'tuple',
+ 'href': '../std/primitive.tuple.html',
+ },
+ ]
+ },
+ {
+ 'others': [
+ {
+ 'path': 'std',
+ 'name': 'fn',
+ 'href': '../std/primitive.fn.html',
+ },
+ ]
+ },
+];
diff --git a/src/test/rustdoc-js-std/quoted.js b/src/test/rustdoc-js-std/quoted.js
new file mode 100644
index 000000000..aec8484a4
--- /dev/null
+++ b/src/test/rustdoc-js-std/quoted.js
@@ -0,0 +1,21 @@
+// ignore-order
+
+const QUERY = '"error"';
+const FILTER_CRATE = 'std';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'error' },
+ { 'path': 'std::fmt', 'name': 'Error' },
+ { 'path': 'std::io', 'name': 'Error' },
+ ],
+ 'in_args': [
+ { 'path': 'std::fmt::Error', 'name': 'eq' },
+ { 'path': 'std::fmt::Error', 'name': 'cmp' },
+ { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
+
+ ],
+ 'returned': [
+ { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/return-specific-literal.js b/src/test/rustdoc-js-std/return-specific-literal.js
new file mode 100644
index 000000000..c7c347240
--- /dev/null
+++ b/src/test/rustdoc-js-std/return-specific-literal.js
@@ -0,0 +1,10 @@
+const QUERY = 'struct:"string"';
+
+const EXPECTED = {
+ 'in_args': [
+ { 'path': 'std::string::String', 'name': 'ne' },
+ ],
+ 'returned': [
+ { 'path': 'std::string::String', 'name': 'add' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/return-specific.js b/src/test/rustdoc-js-std/return-specific.js
new file mode 100644
index 000000000..d9a910553
--- /dev/null
+++ b/src/test/rustdoc-js-std/return-specific.js
@@ -0,0 +1,10 @@
+const QUERY = 'struct:string';
+
+const EXPECTED = {
+ 'in_args': [
+ { 'path': 'std::string::String', 'name': 'ne' },
+ ],
+ 'returned': [
+ { 'path': 'std::string::String', 'name': 'add' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/should-fail.js b/src/test/rustdoc-js-std/should-fail.js
new file mode 100644
index 000000000..b85a47dc0
--- /dev/null
+++ b/src/test/rustdoc-js-std/should-fail.js
@@ -0,0 +1,9 @@
+// should-fail
+
+const QUERY = 'fn';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'fn', ty: 14 },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/string-from_ut.js b/src/test/rustdoc-js-std/string-from_ut.js
new file mode 100644
index 000000000..f9edf4408
--- /dev/null
+++ b/src/test/rustdoc-js-std/string-from_ut.js
@@ -0,0 +1,11 @@
+const QUERY = 'String::from_ut';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::string::String', 'name': 'from_utf8' },
+ { 'path': 'std::string::String', 'name': 'from_utf8' },
+ { 'path': 'std::string::String', 'name': 'from_utf8_lossy' },
+ { 'path': 'std::string::String', 'name': 'from_utf16_lossy' },
+ { 'path': 'std::string::String', 'name': 'from_utf8_unchecked' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/struct-vec.js b/src/test/rustdoc-js-std/struct-vec.js
new file mode 100644
index 000000000..29609904b
--- /dev/null
+++ b/src/test/rustdoc-js-std/struct-vec.js
@@ -0,0 +1,8 @@
+const QUERY = 'struct:VecD';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::collections', 'name': 'VecDeque' },
+ { 'path': 'std::vec', 'name': 'Vec' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/typed-query.js b/src/test/rustdoc-js-std/typed-query.js
new file mode 100644
index 000000000..25efbad26
--- /dev/null
+++ b/src/test/rustdoc-js-std/typed-query.js
@@ -0,0 +1,17 @@
+// exact-check
+
+const QUERY = 'macro:print';
+const FILTER_CRATE = 'std';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'print' },
+ { 'path': 'std', 'name': 'eprint' },
+ { 'path': 'std', 'name': 'println' },
+ { 'path': 'std', 'name': 'eprintln' },
+ { 'path': 'std::pin', 'name': 'pin' },
+ { 'path': 'std::future', 'name': 'join' },
+ { 'path': 'std', 'name': 'line' },
+ { 'path': 'std', 'name': 'write' },
+ ],
+};
diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js
new file mode 100644
index 000000000..cd0e8e7b4
--- /dev/null
+++ b/src/test/rustdoc-js-std/vec-new.js
@@ -0,0 +1,9 @@
+const QUERY = 'Vec::new';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::vec::Vec', 'name': 'new' },
+ { 'path': 'std::vec::Vec', 'name': 'ne' },
+ { 'path': 'alloc::vec::Vec', 'name': 'ne' },
+ ],
+};
diff --git a/src/test/rustdoc-js/basic.js b/src/test/rustdoc-js/basic.js
new file mode 100644
index 000000000..d99b23468
--- /dev/null
+++ b/src/test/rustdoc-js/basic.js
@@ -0,0 +1,7 @@
+const QUERY = 'Fo';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'basic', 'name': 'Foo' },
+ ],
+};
diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs
new file mode 100644
index 000000000..da946a58b
--- /dev/null
+++ b/src/test/rustdoc-js/basic.rs
@@ -0,0 +1,2 @@
+/// Docs for Foo
+pub struct Foo;
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.js b/src/test/rustdoc-js/doc-alias-filter-out.js
new file mode 100644
index 000000000..46a089d06
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-filter-out.js
@@ -0,0 +1,9 @@
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'some_other_crate';
+
+const EXPECTED = {
+ 'others': [],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.rs b/src/test/rustdoc-js/doc-alias-filter-out.rs
new file mode 100644
index 000000000..3f0c09479
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-filter-out.rs
@@ -0,0 +1,2 @@
+#[doc(alias = "true")]
+pub struct Foo;
diff --git a/src/test/rustdoc-js/doc-alias-filter.js b/src/test/rustdoc-js/doc-alias-filter.js
new file mode 100644
index 000000000..e06047ba7
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-filter.js
@@ -0,0 +1,17 @@
+// exact-check
+
+const QUERY = '"true"';
+
+const FILTER_CRATE = 'doc_alias_filter';
+
+const EXPECTED = {
+ 'others': [
+ {
+ 'path': 'doc_alias_filter',
+ 'name': 'Foo',
+ 'alias': 'true',
+ 'href': '../doc_alias_filter/struct.Foo.html',
+ 'is_alias': true
+ },
+ ],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter.rs b/src/test/rustdoc-js/doc-alias-filter.rs
new file mode 100644
index 000000000..d5227814c
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-filter.rs
@@ -0,0 +1,5 @@
+#[doc(alias = "true")]
+pub struct Foo;
+
+#[doc(alias = "false")]
+pub struct Bar;
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js
new file mode 100644
index 000000000..c9fc0c431
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.js
@@ -0,0 +1,19 @@
+// exact-check
+
+const QUERY = [
+ 'Demon Lord',
+];
+
+const EXPECTED = [
+ {
+ 'others': [
+ {
+ 'path': 'doc_alias_whitespace',
+ 'name': 'Struct',
+ 'alias': 'Demon Lord',
+ 'href': '../doc_alias_whitespace/struct.Struct.html',
+ 'is_alias': true
+ },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs
new file mode 100644
index 000000000..16c022c74
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.rs
@@ -0,0 +1,2 @@
+#[doc(alias = "Demon Lord")]
+pub struct Struct;
diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js
new file mode 100644
index 000000000..7bb0cbe38
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.js
@@ -0,0 +1,295 @@
+// exact-check
+
+const QUERY = [
+ 'StructItem',
+ 'StructFieldItem',
+ 'StructMethodItem',
+ 'ImplTraitItem',
+ 'StructImplConstItem',
+ 'ImplTraitFunction',
+ 'EnumItem',
+ 'VariantItem',
+ 'EnumMethodItem',
+ 'TypedefItem',
+ 'TraitItem',
+ 'TraitTypeItem',
+ 'AssociatedConstItem',
+ 'TraitFunctionItem',
+ 'FunctionItem',
+ 'ModuleItem',
+ 'ConstItem',
+ 'StaticItem',
+ 'UnionItem',
+ 'UnionFieldItem',
+ 'UnionMethodItem',
+ 'MacroItem',
+];
+
+const EXPECTED = [
+ {
+ // StructItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Struct',
+ 'alias': 'StructItem',
+ 'href': '../doc_alias/struct.Struct.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // StructFieldItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Struct',
+ 'name': 'field',
+ 'alias': 'StructFieldItem',
+ 'href': '../doc_alias/struct.Struct.html#structfield.field',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // StructMethodItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Struct',
+ 'name': 'method',
+ 'alias': 'StructMethodItem',
+ 'href': '../doc_alias/struct.Struct.html#method.method',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // ImplTraitItem
+ 'others': [],
+ },
+ {
+ // StructImplConstItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Struct',
+ 'name': 'ImplConstItem',
+ 'alias': 'StructImplConstItem',
+ 'href': '../doc_alias/struct.Struct.html#associatedconstant.ImplConstItem',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // ImplTraitFunction
+ 'others': [
+ {
+ 'path': 'doc_alias::Struct',
+ 'name': 'function',
+ 'alias': 'ImplTraitFunction',
+ 'href': '../doc_alias/struct.Struct.html#method.function',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // EnumItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Enum',
+ 'alias': 'EnumItem',
+ 'href': '../doc_alias/enum.Enum.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // VariantItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Enum',
+ 'name': 'Variant',
+ 'alias': 'VariantItem',
+ 'href': '../doc_alias/enum.Enum.html#variant.Variant',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // EnumMethodItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Enum',
+ 'name': 'method',
+ 'alias': 'EnumMethodItem',
+ 'href': '../doc_alias/enum.Enum.html#method.method',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // TypedefItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Typedef',
+ 'alias': 'TypedefItem',
+ 'href': '../doc_alias/type.Typedef.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // TraitItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Trait',
+ 'alias': 'TraitItem',
+ 'href': '../doc_alias/trait.Trait.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // TraitTypeItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Trait',
+ 'name': 'Target',
+ 'alias': 'TraitTypeItem',
+ 'href': '../doc_alias/trait.Trait.html#associatedtype.Target',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // AssociatedConstItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Trait',
+ 'name': 'AssociatedConst',
+ 'alias': 'AssociatedConstItem',
+ 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // TraitFunctionItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Trait',
+ 'name': 'function',
+ 'alias': 'TraitFunctionItem',
+ 'href': '../doc_alias/trait.Trait.html#tymethod.function',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // FunctionItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'function',
+ 'alias': 'FunctionItem',
+ 'href': '../doc_alias/fn.function.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // ModuleItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Module',
+ 'alias': 'ModuleItem',
+ 'href': '../doc_alias/Module/index.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // ConstItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Const',
+ 'alias': 'ConstItem',
+ 'href': '../doc_alias/constant.Const.html',
+ 'is_alias': true
+ },
+ {
+ 'path': 'doc_alias::Struct',
+ 'name': 'ImplConstItem',
+ },
+ ],
+ },
+ {
+ // StaticItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Static',
+ 'alias': 'StaticItem',
+ 'href': '../doc_alias/static.Static.html',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // UnionItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Union',
+ 'alias': 'UnionItem',
+ 'href': '../doc_alias/union.Union.html',
+ 'is_alias': true
+ },
+ // Not an alias!
+ {
+ 'path': 'doc_alias::Union',
+ 'name': 'union_item',
+ 'href': '../doc_alias/union.Union.html#structfield.union_item'
+ },
+ ],
+ },
+ {
+ // UnionFieldItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Union',
+ 'name': 'union_item',
+ 'alias': 'UnionFieldItem',
+ 'href': '../doc_alias/union.Union.html#structfield.union_item',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // UnionMethodItem
+ 'others': [
+ {
+ 'path': 'doc_alias::Union',
+ 'name': 'method',
+ 'alias': 'UnionMethodItem',
+ 'href': '../doc_alias/union.Union.html#method.method',
+ 'is_alias': true
+ },
+ ],
+ },
+ {
+ // MacroItem
+ 'others': [
+ {
+ 'path': 'doc_alias',
+ 'name': 'Macro',
+ 'alias': 'MacroItem',
+ 'href': '../doc_alias/macro.Macro.html',
+ 'is_alias': true
+ },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs
new file mode 100644
index 000000000..750b7b757
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.rs
@@ -0,0 +1,75 @@
+#[doc(alias = "StructItem")]
+pub struct Struct {
+ #[doc(alias = "StructFieldItem")]
+ pub field: u32,
+}
+
+impl Struct {
+ #[doc(alias = "StructImplConstItem")]
+ pub const ImplConstItem: i32 = 0;
+ #[doc(alias = "StructMethodItem")]
+ pub fn method(&self) {}
+}
+
+impl Trait for Struct {
+ type Target = u32;
+ const AssociatedConst: i32 = 12;
+
+ #[doc(alias = "ImplTraitFunction")]
+ fn function() -> Self::Target { 0 }
+}
+
+#[doc(alias = "EnumItem")]
+pub enum Enum {
+ #[doc(alias = "VariantItem")]
+ Variant,
+}
+
+impl Enum {
+ #[doc(alias = "EnumMethodItem")]
+ pub fn method(&self) {}
+}
+
+#[doc(alias = "TypedefItem")]
+pub type Typedef = i32;
+
+#[doc(alias = "TraitItem")]
+pub trait Trait {
+ #[doc(alias = "TraitTypeItem")]
+ type Target;
+ #[doc(alias = "AssociatedConstItem")]
+ const AssociatedConst: i32;
+
+ #[doc(alias = "TraitFunctionItem")]
+ fn function() -> Self::Target;
+}
+
+#[doc(alias = "FunctionItem")]
+pub fn function() {}
+
+#[doc(alias = "ModuleItem")]
+pub mod Module {}
+
+#[doc(alias = "ConstItem")]
+pub const Const: u32 = 0;
+
+#[doc(alias = "StaticItem")]
+pub static Static: u32 = 0;
+
+#[doc(alias = "UnionItem")]
+pub union Union {
+ #[doc(alias = "UnionFieldItem")]
+ pub union_item: u32,
+ pub y: f32,
+}
+
+impl Union {
+ #[doc(alias = "UnionMethodItem")]
+ pub fn method(&self) {}
+}
+
+#[doc(alias = "MacroItem")]
+#[macro_export]
+macro_rules! Macro {
+ () => {}
+}
diff --git a/src/test/rustdoc-js/exact-match.js b/src/test/rustdoc-js/exact-match.js
new file mode 100644
index 000000000..b0a411bee
--- /dev/null
+++ b/src/test/rustdoc-js/exact-match.js
@@ -0,0 +1,9 @@
+const QUERY = 'si::pc';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'exact_match::Si', 'name': 'pc' },
+ { 'path': 'exact_match::Psi', 'name': 'pc' },
+ { 'path': 'exact_match::Si', 'name': 'pa' },
+ ],
+};
diff --git a/src/test/rustdoc-js/exact-match.rs b/src/test/rustdoc-js/exact-match.rs
new file mode 100644
index 000000000..2eacc0a35
--- /dev/null
+++ b/src/test/rustdoc-js/exact-match.rs
@@ -0,0 +1,68 @@
+macro_rules! imp {
+ ($name:ident) => {
+ pub struct $name {
+ pub op: usize,
+ }
+ impl $name {
+ pub fn op() {}
+ pub fn cmp() {}
+ pub fn map() {}
+ pub fn pop() {}
+ pub fn ptr() {}
+ pub fn rpo() {}
+ pub fn drop() {}
+ pub fn copy() {}
+ pub fn zip() {}
+ pub fn sup() {}
+ pub fn pa() {}
+ pub fn pb() {}
+ pub fn pc() {}
+ pub fn pd() {}
+ pub fn pe() {}
+ pub fn pf() {}
+ pub fn pg() {}
+ pub fn ph() {}
+ pub fn pi() {}
+ pub fn pj() {}
+ pub fn pk() {}
+ pub fn pl() {}
+ pub fn pm() {}
+ pub fn pn() {}
+ pub fn po() {}
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ imp!($name);
+ imp!($($names),*);
+ };
+}
+macro_rules! en {
+ ($name:ident) => {
+ pub enum $name {
+ Ptr,
+ Rp,
+ Rpo,
+ Pt,
+ Drop,
+ Dr,
+ Dro,
+ Sup,
+ Op,
+ Cmp,
+ Map,
+ Mp,
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ en!($name);
+ en!($($names),*);
+ };
+}
+
+imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd);
+imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp);
+imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp);
+
+en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
+
+pub struct P;
diff --git a/src/test/rustdoc-js/foreign-type-path.js b/src/test/rustdoc-js/foreign-type-path.js
new file mode 100644
index 000000000..334761bad
--- /dev/null
+++ b/src/test/rustdoc-js/foreign-type-path.js
@@ -0,0 +1,9 @@
+const QUERY = 'MyForeignType::my_method';
+
+const EXPECTED = {
+ 'others': [
+ // Test case for https://github.com/rust-lang/rust/pull/96887#pullrequestreview-967154358
+ // Validates that the parent path for a foreign type method is correct.
+ { 'path': 'foreign_type_path::aaaaaaa::MyForeignType', 'name': 'my_method' },
+ ],
+};
diff --git a/src/test/rustdoc-js/foreign-type-path.rs b/src/test/rustdoc-js/foreign-type-path.rs
new file mode 100644
index 000000000..83400104e
--- /dev/null
+++ b/src/test/rustdoc-js/foreign-type-path.rs
@@ -0,0 +1,13 @@
+#![feature(extern_types)]
+
+pub mod aaaaaaa {
+
+ extern {
+ pub type MyForeignType;
+ }
+
+ impl MyForeignType {
+ pub fn my_method() {}
+ }
+
+}
diff --git a/src/test/rustdoc-js/generics-impl.js b/src/test/rustdoc-js/generics-impl.js
new file mode 100644
index 000000000..bb6e0041d
--- /dev/null
+++ b/src/test/rustdoc-js/generics-impl.js
@@ -0,0 +1,57 @@
+// exact-check
+
+const QUERY = [
+ 'Aaaaaaa -> u32',
+ 'Aaaaaaa -> bool',
+ 'Aaaaaaa -> usize',
+ 'Read -> u64',
+ 'bool -> u64',
+ 'Ddddddd -> u64',
+ '-> Ddddddd'
+];
+
+const EXPECTED = [
+ {
+ // Aaaaaaa -> u32
+ 'others': [
+ { 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' },
+ ],
+ },
+ {
+ // Aaaaaaa -> bool
+ 'others': [
+ { 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' },
+ ],
+ },
+ {
+ // Aaaaaaa -> usize
+ 'others': [
+ { 'path': 'generics_impl::Aaaaaaa', 'name': 'read' },
+ ],
+ },
+ {
+ // Read -> u64
+ 'others': [
+ { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
+ { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
+ ],
+ },
+ {
+ // bool -> u64
+ 'others': [
+ { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' },
+ ],
+ },
+ {
+ // Ddddddd -> u64
+ 'others': [
+ { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
+ ],
+ },
+ {
+ // -> Ddddddd
+ 'others': [
+ { 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/generics-impl.rs b/src/test/rustdoc-js/generics-impl.rs
new file mode 100644
index 000000000..696218021
--- /dev/null
+++ b/src/test/rustdoc-js/generics-impl.rs
@@ -0,0 +1,35 @@
+use std::io::{Result as IoResult, Read};
+
+pub struct Aaaaaaa;
+
+impl Aaaaaaa {
+ pub fn bbbbbbb(self) -> u32 {
+ 1
+ }
+ pub fn ccccccc(&self) -> bool {
+ true
+ }
+}
+
+impl Read for Aaaaaaa {
+ fn read(&mut self, out: &mut [u8]) -> IoResult<usize> {
+ Ok(out.len())
+ }
+}
+
+pub struct Ddddddd<T>(T);
+
+impl<T: Read> Ddddddd<T> {
+ pub fn eeeeeee(_: T) -> u64 {
+ 1
+ }
+ pub fn fffffff(_: bool) -> u64 {
+ 1
+ }
+ pub fn ggggggg(self) -> u64 {
+ 1
+ }
+ pub fn hhhhhhh() -> Self where T: Default {
+ Ddddddd(T::default())
+ }
+}
diff --git a/src/test/rustdoc-js/generics-multi-trait.js b/src/test/rustdoc-js/generics-multi-trait.js
new file mode 100644
index 000000000..e7fcea876
--- /dev/null
+++ b/src/test/rustdoc-js/generics-multi-trait.js
@@ -0,0 +1,32 @@
+// exact-check
+
+const QUERY = [
+ 'Result<SomeTrait>',
+ 'Zzzzzzzzzzzzzzzzzz',
+ 'Nonononononononono',
+];
+
+const EXPECTED = [
+ // check one of the generic items
+ {
+ 'in_args': [
+ { 'path': 'generics_multi_trait', 'name': 'beta' },
+ ],
+ 'returned': [
+ { 'path': 'generics_multi_trait', 'name': 'bet' },
+ ],
+ },
+ {
+ 'in_args': [
+ { 'path': 'generics_multi_trait', 'name': 'beta' },
+ ],
+ 'returned': [
+ { 'path': 'generics_multi_trait', 'name': 'bet' },
+ ],
+ },
+ // ignore the name of the generic itself
+ {
+ 'in_args': [],
+ 'returned': [],
+ },
+];
diff --git a/src/test/rustdoc-js/generics-multi-trait.rs b/src/test/rustdoc-js/generics-multi-trait.rs
new file mode 100644
index 000000000..e6fd06d25
--- /dev/null
+++ b/src/test/rustdoc-js/generics-multi-trait.rs
@@ -0,0 +1,12 @@
+pub trait SomeTrait {}
+pub trait Zzzzzzzzzzzzzzzzzz {}
+
+pub fn bet<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>() -> Result<Nonononononononono, ()> {
+ loop {}
+}
+
+pub fn beta<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>(
+ _param: Result<Nonononononononono, ()>,
+) {
+ loop {}
+}
diff --git a/src/test/rustdoc-js/generics-trait.js b/src/test/rustdoc-js/generics-trait.js
new file mode 100644
index 000000000..787662243
--- /dev/null
+++ b/src/test/rustdoc-js/generics-trait.js
@@ -0,0 +1,23 @@
+const QUERY = [
+ 'Result<SomeTrait>',
+ 'OtherThingxxxxxxxx',
+];
+
+const EXPECTED = [
+ {
+ 'in_args': [
+ { 'path': 'generics_trait', 'name': 'beta' },
+ ],
+ 'returned': [
+ { 'path': 'generics_trait', 'name': 'bet' },
+ ],
+ },
+ {
+ 'in_args': [
+ { 'path': 'generics_trait', 'name': 'alpha' },
+ ],
+ 'returned': [
+ { 'path': 'generics_trait', 'name': 'alef' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/generics-trait.rs b/src/test/rustdoc-js/generics-trait.rs
new file mode 100644
index 000000000..20db117cc
--- /dev/null
+++ b/src/test/rustdoc-js/generics-trait.rs
@@ -0,0 +1,8 @@
+pub trait SomeTrait {}
+pub trait OtherThingxxxxxxxx {}
+
+pub fn alef<T: OtherThingxxxxxxxx>() -> Result<T, ()> { loop {} }
+pub fn bet<T: SomeTrait>() -> Result<T, ()> { loop {} }
+
+pub fn alpha<T: OtherThingxxxxxxxx>(_param: Result<T, ()>) { loop {} }
+pub fn beta<T: SomeTrait>(_param: Result<T, ()>) { loop {} }
diff --git a/src/test/rustdoc-js/generics.js b/src/test/rustdoc-js/generics.js
new file mode 100644
index 000000000..5e5ba7cd9
--- /dev/null
+++ b/src/test/rustdoc-js/generics.js
@@ -0,0 +1,73 @@
+// exact-check
+
+const QUERY = [
+ 'R<P>',
+ '"P"',
+ 'P',
+ 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
+ 'TraitCat',
+ 'TraitDog',
+ 'Result<String>',
+];
+
+const EXPECTED = [
+ {
+ // R<P>
+ 'returned': [
+ { 'path': 'generics', 'name': 'alef' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'alpha' },
+ ],
+ },
+ {
+ // "P"
+ 'others': [
+ { 'path': 'generics', 'name': 'P' },
+ ],
+ 'returned': [
+ { 'path': 'generics', 'name': 'alef' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'alpha' },
+ ],
+ },
+ {
+ // P
+ 'returned': [
+ { 'path': 'generics', 'name': 'alef' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'alpha' },
+ ],
+ },
+ {
+ // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
+ 'in_args': [
+ { 'path': 'generics', 'name': 'extracreditlabhomework' },
+ ],
+ 'returned': [],
+ },
+ {
+ // TraitCat
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
+ {
+ // TraitDog
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
+ {
+ // Result<String>
+ 'others': [],
+ 'returned': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/generics.rs b/src/test/rustdoc-js/generics.rs
new file mode 100644
index 000000000..055c51c7e
--- /dev/null
+++ b/src/test/rustdoc-js/generics.rs
@@ -0,0 +1,28 @@
+pub struct P;
+pub struct Q;
+pub struct R<T>(T);
+
+// returns test
+pub fn alef() -> R<P> { loop {} }
+pub fn bet() -> R<Q> { loop {} }
+
+// in_args test
+pub fn alpha(_x: R<P>) { loop {} }
+pub fn beta(_x: R<Q>) { loop {} }
+
+// test case with multiple appearances of the same type
+pub struct ExtraCreditStructMulti<T, U> { t: T, u: U }
+pub struct ExtraCreditInnerMulti {}
+pub fn extracreditlabhomework(
+ _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
+) { loop {} }
+pub fn redherringmatchforextracredit(
+ _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>
+) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
+
+pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
diff --git a/src/test/rustdoc-js/impl-trait.js b/src/test/rustdoc-js/impl-trait.js
new file mode 100644
index 000000000..8d594bf8a
--- /dev/null
+++ b/src/test/rustdoc-js/impl-trait.js
@@ -0,0 +1,51 @@
+// ignore-order
+
+const QUERY = [
+ 'Aaaaaaa -> i32',
+ 'Aaaaaaa -> Aaaaaaa',
+ 'Aaaaaaa -> usize',
+ '-> Aaaaaaa',
+ 'Aaaaaaa',
+];
+
+const EXPECTED = [
+ {
+ // Aaaaaaa -> i32
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ },
+ {
+ // Aaaaaaa -> Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ ],
+ },
+ {
+ // Aaaaaaa -> usize
+ 'others': [],
+ },
+ {
+ // -> Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+ ],
+ },
+ {
+ // Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait', 'name': 'Aaaaaaa' },
+ ],
+ 'in_args': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ 'returned': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/impl-trait.rs b/src/test/rustdoc-js/impl-trait.rs
new file mode 100644
index 000000000..fb8869b46
--- /dev/null
+++ b/src/test/rustdoc-js/impl-trait.rs
@@ -0,0 +1,21 @@
+pub trait Aaaaaaa {}
+
+impl Aaaaaaa for () {}
+
+pub fn bbbbbbb() -> impl Aaaaaaa {
+ ()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+ pub fn ddddddd(&self) -> impl Aaaaaaa {
+ ()
+ }
+ pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 {
+ 0
+ }
+ pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa {
+ x
+ }
+}
diff --git a/src/test/rustdoc-js/module-substring.js b/src/test/rustdoc-js/module-substring.js
new file mode 100644
index 000000000..a446c39eb
--- /dev/null
+++ b/src/test/rustdoc-js/module-substring.js
@@ -0,0 +1,9 @@
+const QUERY = 'ig::pc';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'module_substring::Sig', 'name': 'pc' },
+ { 'path': 'module_substring::Si', 'name': 'pc' },
+ { 'path': 'module_substring::Si', 'name': 'pa' },
+ ],
+};
diff --git a/src/test/rustdoc-js/module-substring.rs b/src/test/rustdoc-js/module-substring.rs
new file mode 100644
index 000000000..2eacc0a35
--- /dev/null
+++ b/src/test/rustdoc-js/module-substring.rs
@@ -0,0 +1,68 @@
+macro_rules! imp {
+ ($name:ident) => {
+ pub struct $name {
+ pub op: usize,
+ }
+ impl $name {
+ pub fn op() {}
+ pub fn cmp() {}
+ pub fn map() {}
+ pub fn pop() {}
+ pub fn ptr() {}
+ pub fn rpo() {}
+ pub fn drop() {}
+ pub fn copy() {}
+ pub fn zip() {}
+ pub fn sup() {}
+ pub fn pa() {}
+ pub fn pb() {}
+ pub fn pc() {}
+ pub fn pd() {}
+ pub fn pe() {}
+ pub fn pf() {}
+ pub fn pg() {}
+ pub fn ph() {}
+ pub fn pi() {}
+ pub fn pj() {}
+ pub fn pk() {}
+ pub fn pl() {}
+ pub fn pm() {}
+ pub fn pn() {}
+ pub fn po() {}
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ imp!($name);
+ imp!($($names),*);
+ };
+}
+macro_rules! en {
+ ($name:ident) => {
+ pub enum $name {
+ Ptr,
+ Rp,
+ Rpo,
+ Pt,
+ Drop,
+ Dr,
+ Dro,
+ Sup,
+ Op,
+ Cmp,
+ Map,
+ Mp,
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ en!($name);
+ en!($($names),*);
+ };
+}
+
+imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd);
+imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp);
+imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp);
+
+en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
+
+pub struct P;
diff --git a/src/test/rustdoc-js/path-ordering.js b/src/test/rustdoc-js/path-ordering.js
new file mode 100644
index 000000000..4aee569b0
--- /dev/null
+++ b/src/test/rustdoc-js/path-ordering.js
@@ -0,0 +1,14 @@
+// exact-check
+
+const QUERY = 'b::ccccccc';
+
+const EXPECTED = {
+ 'others': [
+ // `ccccccc` is an exact match for all three of these.
+ // However `b` is a closer match for `bb` than for any
+ // of the others, so it ought to go first.
+ { 'path': 'path_ordering::bb', 'name': 'Ccccccc' },
+ { 'path': 'path_ordering::aa', 'name': 'Ccccccc' },
+ { 'path': 'path_ordering::dd', 'name': 'Ccccccc' },
+ ],
+};
diff --git a/src/test/rustdoc-js/path-ordering.rs b/src/test/rustdoc-js/path-ordering.rs
new file mode 100644
index 000000000..7843cf7f9
--- /dev/null
+++ b/src/test/rustdoc-js/path-ordering.rs
@@ -0,0 +1,9 @@
+pub mod dd {
+ pub struct Ccccccc;
+}
+pub mod aa {
+ pub struct Ccccccc;
+}
+pub mod bb {
+ pub struct Ccccccc;
+}
diff --git a/src/test/rustdoc-js/primitive.js b/src/test/rustdoc-js/primitive.js
new file mode 100644
index 000000000..918f70999
--- /dev/null
+++ b/src/test/rustdoc-js/primitive.js
@@ -0,0 +1,25 @@
+// exact-check
+
+const QUERY = [
+ "i32",
+ "str",
+ "TotoIsSomewhere",
+];
+
+const EXPECTED = [
+ {
+ 'in_args': [
+ { 'path': 'primitive', 'name': 'foo' },
+ ],
+ },
+ {
+ 'returned': [
+ { 'path': 'primitive', 'name': 'foo' },
+ ],
+ },
+ {
+ 'others': [],
+ 'in_args': [],
+ 'returned': [],
+ },
+];
diff --git a/src/test/rustdoc-js/primitive.rs b/src/test/rustdoc-js/primitive.rs
new file mode 100644
index 000000000..2b30ccf15
--- /dev/null
+++ b/src/test/rustdoc-js/primitive.rs
@@ -0,0 +1,5 @@
+pub fn foo(i: i32) -> &'static str {
+ "hello"
+}
+
+pub fn foo2<TotoIsSomewhere>(i: &TotoIsSomewhere, j: TotoIsSomewhere) {}
diff --git a/src/test/rustdoc-js/prototype.js b/src/test/rustdoc-js/prototype.js
new file mode 100644
index 000000000..2f1d841c3
--- /dev/null
+++ b/src/test/rustdoc-js/prototype.js
@@ -0,0 +1,16 @@
+// exact-check
+
+const QUERY = ['constructor', '__proto__'];
+
+const EXPECTED = [
+ {
+ 'others': [],
+ 'returned': [],
+ 'in_args': [],
+ },
+ {
+ 'others': [],
+ 'returned': [],
+ 'in_args': [],
+ },
+];
diff --git a/src/test/rustdoc-js/prototype.rs b/src/test/rustdoc-js/prototype.rs
new file mode 100644
index 000000000..5f6d73cc1
--- /dev/null
+++ b/src/test/rustdoc-js/prototype.rs
@@ -0,0 +1,4 @@
+// The alias needed to be there to reproduce the bug
+// that used to be here.
+#[doc(alias="other_alias")]
+pub fn something_else() {}
diff --git a/src/test/rustdoc-js/raw-pointer.js b/src/test/rustdoc-js/raw-pointer.js
new file mode 100644
index 000000000..140b955ea
--- /dev/null
+++ b/src/test/rustdoc-js/raw-pointer.js
@@ -0,0 +1,55 @@
+// ignore-order
+
+const QUERY = [
+ 'Aaaaaaa -> i32',
+ 'Aaaaaaa -> Aaaaaaa',
+ 'Aaaaaaa -> usize',
+ '-> Aaaaaaa',
+ 'Aaaaaaa',
+];
+
+const EXPECTED = [
+ {
+ // Aaaaaaa -> i32
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ },
+ {
+ // Aaaaaaa -> Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ ],
+ },
+ {
+ // Aaaaaaa -> usize
+ 'others': [],
+ },
+ {
+ // -> Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+ ],
+ },
+ {
+ // Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer', 'name': 'Aaaaaaa' },
+ ],
+ 'in_args': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ 'returned': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/raw-pointer.rs b/src/test/rustdoc-js/raw-pointer.rs
new file mode 100644
index 000000000..b8ace2e0b
--- /dev/null
+++ b/src/test/rustdoc-js/raw-pointer.rs
@@ -0,0 +1,24 @@
+use std::ptr;
+
+pub struct Aaaaaaa {}
+
+pub fn bbbbbbb() -> *const Aaaaaaa {
+ ptr::null()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+ pub fn ddddddd(&self) -> *const Aaaaaaa {
+ ptr::null()
+ }
+ pub fn eeeeeee(&self, _x: *const Aaaaaaa) -> i32 {
+ 0
+ }
+ pub fn fffffff(&self, x: *const Aaaaaaa) -> *const Aaaaaaa {
+ x
+ }
+ pub fn ggggggg(&self, x: *mut Aaaaaaa) -> *mut Aaaaaaa {
+ x
+ }
+}
diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js
new file mode 100644
index 000000000..d14672af7
--- /dev/null
+++ b/src/test/rustdoc-js/search-short-types.js
@@ -0,0 +1,10 @@
+const QUERY = 'P';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'search_short_types', 'name': 'P' },
+ { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' },
+ { 'path': 'search_short_types', 'name': 'Ap' },
+ { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' },
+ ],
+};
diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs
new file mode 100644
index 000000000..a4083f9a7
--- /dev/null
+++ b/src/test/rustdoc-js/search-short-types.rs
@@ -0,0 +1,74 @@
+macro_rules! imp {
+ ($name:ident) => {
+ pub struct $name {
+ pub op: usize,
+ }
+ impl $name {
+ pub fn op() {}
+ pub fn cmp() {}
+ pub fn map() {}
+ pub fn pop() {}
+ pub fn ptr() {}
+ pub fn rpo() {}
+ pub fn drop() {}
+ pub fn copy() {}
+ pub fn zip() {}
+ pub fn sup() {}
+ pub fn pa() {}
+ pub fn pb() {}
+ pub fn pc() {}
+ pub fn pd() {}
+ pub fn pe() {}
+ pub fn pf() {}
+ pub fn pg() {}
+ pub fn ph() {}
+ pub fn pi() {}
+ pub fn pj() {}
+ pub fn pk() {}
+ pub fn pl() {}
+ pub fn pm() {}
+ pub fn pn() {}
+ pub fn po() {}
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ imp!($name);
+ imp!($($names),*);
+ };
+}
+macro_rules! en {
+ ($name:ident) => {
+ pub enum $name {
+ Ptr,
+ Rp,
+ Rpo,
+ Pt,
+ Drop,
+ Dr,
+ Dro,
+ Sup,
+ Op,
+ Cmp,
+ Map,
+ Mp,
+ }
+ };
+ ($name:ident, $($names:ident),*) => {
+ en!($name);
+ en!($($names),*);
+ };
+}
+
+imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd);
+imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp);
+imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp);
+
+en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
+
+pub struct P;
+
+pub struct VeryLongTypeName;
+impl VeryLongTypeName {
+ pub fn p() {}
+ pub fn ap() {}
+}
diff --git a/src/test/rustdoc-js/struct-like-variant.js b/src/test/rustdoc-js/struct-like-variant.js
new file mode 100644
index 000000000..f6deea51e
--- /dev/null
+++ b/src/test/rustdoc-js/struct-like-variant.js
@@ -0,0 +1,7 @@
+const QUERY = 'name';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'struct_like_variant::Enum::Bar', 'name': 'name', 'desc': 'This is a name.' },
+ ],
+};
diff --git a/src/test/rustdoc-js/struct-like-variant.rs b/src/test/rustdoc-js/struct-like-variant.rs
new file mode 100644
index 000000000..2f52a319a
--- /dev/null
+++ b/src/test/rustdoc-js/struct-like-variant.rs
@@ -0,0 +1,8 @@
+#![crate_name = "struct_like_variant"]
+
+pub enum Enum {
+ Bar {
+ /// This is a name.
+ name: String
+ }
+}
diff --git a/src/test/rustdoc-js/substring.js b/src/test/rustdoc-js/substring.js
new file mode 100644
index 000000000..af05cd1ad
--- /dev/null
+++ b/src/test/rustdoc-js/substring.js
@@ -0,0 +1,8 @@
+const QUERY = 'waker_from';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'substring::SuperWaker', 'name': 'local_waker_from_nonlocal' },
+ { 'path': 'substring::SuperWakerTask', 'name': 'local_waker_from_nonlocal' },
+ ],
+};
diff --git a/src/test/rustdoc-js/substring.rs b/src/test/rustdoc-js/substring.rs
new file mode 100644
index 000000000..e729c722c
--- /dev/null
+++ b/src/test/rustdoc-js/substring.rs
@@ -0,0 +1,21 @@
+pub struct SuperWaker;
+
+impl SuperWaker {
+ pub fn local_waker_from_nonlocal() {}
+ pub fn local_waker_frm_nonlocal() {}
+ pub fn some_method() {}
+ pub fn some_other_method() {}
+ pub fn waker_non_local() {}
+ pub fn from_non_local() {}
+}
+
+pub struct SuperWakerTask;
+
+impl SuperWakerTask {
+ pub fn local_waker_from_nonlocal() {}
+ pub fn local_waker_frm_nonlocal() {}
+ pub fn some_method() {}
+ pub fn some_other_method() {}
+ pub fn waker_non_local() {}
+ pub fn from_non_local() {}
+}
diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js
new file mode 100644
index 000000000..dfb11e804
--- /dev/null
+++ b/src/test/rustdoc-js/summaries.js
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2'];
+
+const EXPECTED = [
+ {
+ 'others': [
+ { 'path': '', 'name': 'summaries', 'desc': 'This <em>summary</em> has a link, [<code>code</code>], and <code>Sidebar2</code> intra-doc.' },
+ ],
+ },
+ {
+ 'others': [
+ { 'path': 'summaries', 'name': 'Sidebar', 'desc': 'This <code>code</code> will be rendered in a code tag.' },
+ ],
+ },
+ {
+ 'others': [
+ { 'path': 'summaries', 'name': 'Sidebar2', 'desc': '' },
+ ],
+ },
+];
diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs
new file mode 100644
index 000000000..1ee1c34aa
--- /dev/null
+++ b/src/test/rustdoc-js/summaries.rs
@@ -0,0 +1,22 @@
+#![crate_type = "lib"]
+#![crate_name = "summaries"]
+
+#![allow(rustdoc::broken_intra_doc_links)]
+
+//! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc.
+//!
+//! This is the second paragraph. It should not be rendered.
+//! To test that intra-doc links are resolved properly, [`code`] should render
+//! the square brackets, and [`Sidebar2`] should not.
+//!
+//! [link]: https://example.com
+
+/// This `code` will be rendered in a code tag.
+///
+/// This text should not be rendered.
+pub struct Sidebar;
+
+/// ```text
+/// this block should not be rendered
+/// ```
+pub struct Sidebar2;
diff --git a/src/test/rustdoc-json/assoc_items.rs b/src/test/rustdoc-json/assoc_items.rs
new file mode 100644
index 000000000..2ee64c9f6
--- /dev/null
+++ b/src/test/rustdoc-json/assoc_items.rs
@@ -0,0 +1,29 @@
+#![no_std]
+
+// @has assoc_items.json
+
+pub struct Simple;
+
+impl Simple {
+ // @has - "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\"
+ pub const CONSTANT: usize = 0;
+}
+
+pub trait EasyToImpl {
+ // @has - "$.index[*][?(@.name=='ToDeclare')].kind" \"assoc_type\"
+ // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default" null
+ type ToDeclare;
+ // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].kind" \"assoc_const\"
+ // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" null
+ const AN_ATTRIBUTE: usize;
+}
+
+impl EasyToImpl for Simple {
+ // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.kind" \"primitive\"
+ // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.inner" \"usize\"
+ type ToDeclare = usize;
+ // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.kind" \"primitive\"
+ // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.inner" \"usize\"
+ // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" \"12\"
+ const AN_ATTRIBUTE: usize = 12;
+}
diff --git a/src/test/rustdoc-json/assoc_type.rs b/src/test/rustdoc-json/assoc_type.rs
new file mode 100644
index 000000000..716bb3d28
--- /dev/null
+++ b/src/test/rustdoc-json/assoc_type.rs
@@ -0,0 +1,22 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98547>.
+
+// @has assoc_type.json
+// @has - "$.index[*][?(@.name=='Trait')]"
+// @has - "$.index[*][?(@.name=='AssocType')]"
+// @has - "$.index[*][?(@.name=='S')]"
+// @has - "$.index[*][?(@.name=='S2')]"
+
+pub trait Trait {
+ type AssocType;
+}
+
+impl<T> Trait for T {
+ type AssocType = Self;
+}
+
+pub struct S;
+
+/// Not needed for the #98547 ICE to occur, but added to maximize the chance of
+/// getting an ICE in the future. See
+/// <https://github.com/rust-lang/rust/pull/98548#discussion_r908219164>
+pub struct S2;
diff --git a/src/test/rustdoc-json/blanket_impls.rs b/src/test/rustdoc-json/blanket_impls.rs
new file mode 100644
index 000000000..edf1a9fe2
--- /dev/null
+++ b/src/test/rustdoc-json/blanket_impls.rs
@@ -0,0 +1,9 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98658>
+
+#![no_std]
+
+// @has blanket_impls.json
+// @has - "$.index[*][?(@.name=='Error')].kind" \"assoc_type\"
+// @has - "$.index[*][?(@.name=='Error')].inner.default.kind" \"resolved_path\"
+// @has - "$.index[*][?(@.name=='Error')].inner.default.inner.name" \"Infallible\"
+pub struct ForBlanketTryFromImpl;
diff --git a/src/test/rustdoc-json/doc_hidden_failure.rs b/src/test/rustdoc-json/doc_hidden_failure.rs
new file mode 100644
index 000000000..5c4ccf996
--- /dev/null
+++ b/src/test/rustdoc-json/doc_hidden_failure.rs
@@ -0,0 +1,22 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98007>.
+
+#![feature(no_core)]
+#![no_core]
+
+mod auto {
+ mod action_row {
+ pub struct ActionRowBuilder;
+ }
+
+ #[doc(hidden)]
+ pub mod builders {
+ pub use super::action_row::ActionRowBuilder;
+ }
+}
+
+// @count doc_hidden_failure.json "$.index[*][?(@.name=='builders')]" 2
+pub use auto::*;
+
+pub mod builders {
+ pub use crate::auto::builders::*;
+}
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
new file mode 100644
index 000000000..fcd92887c
--- /dev/null
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -0,0 +1,11 @@
+// @has variant_struct.json "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
+pub enum EnumStruct {
+ // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
+ // @has - "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+ // @has - "$.index[*][?(@.name=='y')].kind" \"struct_field\"
+ VariantS {
+ x: u32,
+ y: String,
+ },
+}
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
new file mode 100644
index 000000000..ac3e72e29
--- /dev/null
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -0,0 +1,8 @@
+// @has variant_tuple_struct.json "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
+pub enum EnumTupleStruct {
+ // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
+ // @has - "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+ // @has - "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+ VariantA(u32, String),
+}
diff --git a/src/test/rustdoc-json/fn_pointer/abi.rs b/src/test/rustdoc-json/fn_pointer/abi.rs
new file mode 100644
index 000000000..eef20e60a
--- /dev/null
+++ b/src/test/rustdoc-json/fn_pointer/abi.rs
@@ -0,0 +1,25 @@
+// ignore-tidy-linelength
+
+#![feature(abi_vectorcall)]
+#![feature(c_unwind)]
+
+// @is abi.json "$.index[*][?(@.name=='AbiRust')].inner.type.inner.header.abi" \"Rust\"
+pub type AbiRust = fn();
+
+// @is - "$.index[*][?(@.name=='AbiC')].inner.type.inner.header.abi" '{"C": {"unwind": false}}'
+pub type AbiC = extern "C" fn();
+
+// @is - "$.index[*][?(@.name=='AbiSystem')].inner.type.inner.header.abi" '{"System": {"unwind": false}}'
+pub type AbiSystem = extern "system" fn();
+
+// @is - "$.index[*][?(@.name=='AbiCUnwind')].inner.type.inner.header.abi" '{"C": {"unwind": true}}'
+pub type AbiCUnwind = extern "C-unwind" fn();
+
+// @is - "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type.inner.header.abi" '{"System": {"unwind": true}}'
+pub type AbiSystemUnwind = extern "system-unwind" fn();
+
+// @is - "$.index[*][?(@.name=='AbiVecorcall')].inner.type.inner.header.abi.Other" '"\"vectorcall\""'
+pub type AbiVecorcall = extern "vectorcall" fn();
+
+// @is - "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type.inner.header.abi.Other" '"\"vectorcall-unwind\""'
+pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn();
diff --git a/src/test/rustdoc-json/fn_pointer/generics.rs b/src/test/rustdoc-json/fn_pointer/generics.rs
new file mode 100644
index 000000000..646f720e6
--- /dev/null
+++ b/src/test/rustdoc-json/fn_pointer/generics.rs
@@ -0,0 +1,14 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @count generics.json "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][0]" '"val"'
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].inner.lifetime" \"\'c\"
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.output" '{ "kind": "primitive", "inner": "i32" }'
+// @count - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].name" \"\'c\"
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32;
diff --git a/src/test/rustdoc-json/fn_pointer/qualifiers.rs b/src/test/rustdoc-json/fn_pointer/qualifiers.rs
new file mode 100644
index 000000000..381922085
--- /dev/null
+++ b/src/test/rustdoc-json/fn_pointer/qualifiers.rs
@@ -0,0 +1,9 @@
+// @is qualifiers.json "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.unsafe" false
+// @is - "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.const" false
+// @is - "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.async" false
+pub type FnPointer = fn();
+
+// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.unsafe" true
+// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.const" false
+// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.async" false
+pub type UnsafePointer = unsafe fn();
diff --git a/src/test/rustdoc-json/fns/abi.rs b/src/test/rustdoc-json/fns/abi.rs
new file mode 100644
index 000000000..16b579130
--- /dev/null
+++ b/src/test/rustdoc-json/fns/abi.rs
@@ -0,0 +1,25 @@
+// ignore-tidy-linelength
+
+#![feature(abi_vectorcall)]
+#![feature(c_unwind)]
+
+// @is abi.json "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\"
+pub fn abi_rust() {}
+
+// @is - "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}'
+pub extern "C" fn abi_c() {}
+
+// @is - "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}'
+pub extern "system" fn abi_system() {}
+
+// @is - "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}'
+pub extern "C-unwind" fn abi_c_unwind() {}
+
+// @is - "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}'
+pub extern "system-unwind" fn abi_system_unwind() {}
+
+// @is - "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""'
+pub extern "vectorcall" fn abi_vectorcall() {}
+
+// @is - "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""'
+pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
diff --git a/src/test/rustdoc-json/fns/generic_args.rs b/src/test/rustdoc-json/fns/generic_args.rs
new file mode 100644
index 000000000..69150443c
--- /dev/null
+++ b/src/test/rustdoc-json/fns/generic_args.rs
@@ -0,0 +1,71 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @set foo = generic_args.json "$.index[*][?(@.name=='Foo')].id"
+pub trait Foo {}
+
+// @set generic_foo = generic_args.json "$.index[*][?(@.name=='GenericFoo')].id"
+pub trait GenericFoo<'a> {}
+
+// @is - "$.index[*][?(@.name=='generics')].inner.generics.where_predicates" "[]"
+// @count - "$.index[*][?(@.name=='generics')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].name" '"F"'
+// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.default" 'null'
+// @count - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" '$foo'
+// @count - "$.index[*][?(@.name=='generics')].inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][0]" '"f"'
+// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].kind" '"generic"'
+// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].inner" '"F"'
+pub fn generics<F: Foo>(f: F) {}
+
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.where_predicates" "[]"
+// @count - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].name" '"impl Foo"'
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $foo
+// @count - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][0]" '"f"'
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].kind" '"impl_trait"'
+// @count - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[*]" 1
+// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $foo
+pub fn impl_trait(f: impl Foo) {}
+
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.params[*]" 3
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].name" '"F"'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[*]" 3
+// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][0]" '"f"'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].kind" '"generic"'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].inner" '"F"'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[*]" 3
+
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F", "kind": "generic"}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo
+
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.type" '{"inner": "G", "kind": "generic"}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.inner.id" $generic_foo
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.generic_params" "[]"
+
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.lifetime" \"\'b\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.type" '{"inner": "H", "kind": "generic"}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]"
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+pub fn where_clase<F, G, H>(f: F, g: G, h: H)
+where
+ F: Foo,
+ G: for<'a> GenericFoo<'a>,
+ for<'b> &'b H: Foo,
+{
+}
diff --git a/src/test/rustdoc-json/fns/generic_returns.rs b/src/test/rustdoc-json/fns/generic_returns.rs
new file mode 100644
index 000000000..1a0f33fe3
--- /dev/null
+++ b/src/test/rustdoc-json/fns/generic_returns.rs
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @count generic_returns.json "$.index[*][?(@.name=='generic_returns')].inner.items[*]" 2
+
+// @set foo = - "$.index[*][?(@.name=='Foo')].id"
+pub trait Foo {}
+
+// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.inputs" []
+// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.output.kind" '"impl_trait"'
+// @count - "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[*]" 1
+// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[0].trait_bound.trait.inner.id" $foo
+pub fn get_foo() -> impl Foo {
+ Fooer {}
+}
+
+struct Fooer {}
+
+impl Foo for Fooer {}
diff --git a/src/test/rustdoc-json/fns/generics.rs b/src/test/rustdoc-json/fns/generics.rs
new file mode 100644
index 000000000..e777fabaa
--- /dev/null
+++ b/src/test/rustdoc-json/fns/generics.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @set wham_id = generics.json "$.index[*][?(@.name=='Wham')].id"
+pub trait Wham {}
+
+// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" []
+// @count - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"'
+// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false
+// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
+// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]'
+pub fn one_generic_param_fn<T: Wham>(w: T) {}
+
+// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" []
+// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"'
+// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true
+// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
+// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"'
+// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"'
+// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $wham_id
+pub fn one_synthetic_generic_param_fn(w: impl Wham) {}
diff --git a/src/test/rustdoc-json/fns/qualifiers.rs b/src/test/rustdoc-json/fns/qualifiers.rs
new file mode 100644
index 000000000..5cb3b43e6
--- /dev/null
+++ b/src/test/rustdoc-json/fns/qualifiers.rs
@@ -0,0 +1,33 @@
+// edition:2018
+
+// @is qualifiers.json "$.index[*][?(@.name=='nothing_fn')].inner.header.async" false
+// @is - "$.index[*][?(@.name=='nothing_fn')].inner.header.const" false
+// @is - "$.index[*][?(@.name=='nothing_fn')].inner.header.unsafe" false
+pub fn nothing_fn() {}
+
+// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.async" false
+// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.const" false
+// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.unsafe" true
+pub unsafe fn unsafe_fn() {}
+
+// @is - "$.index[*][?(@.name=='const_fn')].inner.header.async" false
+// @is - "$.index[*][?(@.name=='const_fn')].inner.header.const" true
+// @is - "$.index[*][?(@.name=='const_fn')].inner.header.unsafe" false
+pub const fn const_fn() {}
+
+// @is - "$.index[*][?(@.name=='async_fn')].inner.header.async" true
+// @is - "$.index[*][?(@.name=='async_fn')].inner.header.const" false
+// @is - "$.index[*][?(@.name=='async_fn')].inner.header.unsafe" false
+pub async fn async_fn() {}
+
+// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.async" true
+// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.const" false
+// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.unsafe" true
+pub async unsafe fn async_unsafe_fn() {}
+
+// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.async" false
+// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.const" true
+// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.unsafe" true
+pub const unsafe fn const_unsafe_fn() {}
+
+// It's impossible for a function to be both const and async, so no test for that
diff --git a/src/test/rustdoc-json/generic-associated-types/gats.rs b/src/test/rustdoc-json/generic-associated-types/gats.rs
new file mode 100644
index 000000000..368ff8d8d
--- /dev/null
+++ b/src/test/rustdoc-json/generic-associated-types/gats.rs
@@ -0,0 +1,44 @@
+// ignore-tidy-linelength
+
+#![no_core]
+#![feature(generic_associated_types, lang_items, no_core)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Display {}
+
+// @has gats.json
+pub trait LendingIterator {
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*]" 1
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*].name" \"\'a\"
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*]" 1
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.type.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\"
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.bounds[*]" 1
+ type LendingItem<'a>: Display
+ where
+ Self: 'a;
+
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.kind" \"qualified_path\"
+ // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 1
+ // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.self_type.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.name" \"LendingItem\"
+ fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>;
+}
+
+// @has gats.json
+pub trait Iterator {
+ // @count - "$.index[*][?(@.name=='Item')].inner.generics.params[*]" 0
+ // @count - "$.index[*][?(@.name=='Item')].inner.generics.where_predicates[*]" 0
+ // @count - "$.index[*][?(@.name=='Item')].inner.bounds[*]" 1
+ type Item: Display;
+
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.kind" \"qualified_path\"
+ // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 0
+ // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.self_type.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.name" \"Item\"
+ fn next<'a>(&'a self) -> Self::Item;
+}
diff --git a/src/test/rustdoc-json/generic_impl.rs b/src/test/rustdoc-json/generic_impl.rs
new file mode 100644
index 000000000..ac68ba578
--- /dev/null
+++ b/src/test/rustdoc-json/generic_impl.rs
@@ -0,0 +1,24 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/97986>.
+
+// @has generic_impl.json
+// @has - "$.index[*][?(@.name=='f')]"
+// @has - "$.index[*][?(@.name=='AssocTy')]"
+// @has - "$.index[*][?(@.name=='AssocConst')]"
+
+pub mod m {
+ pub struct S;
+}
+
+pub trait F {
+ type AssocTy;
+ const AssocConst: usize;
+ fn f() -> m::S;
+}
+
+impl<T> F for T {
+ type AssocTy = u32;
+ const AssocConst: usize = 0;
+ fn f() -> m::S {
+ m::S
+ }
+}
diff --git a/src/test/rustdoc-json/glob_import.rs b/src/test/rustdoc-json/glob_import.rs
new file mode 100644
index 000000000..d7ac952d1
--- /dev/null
+++ b/src/test/rustdoc-json/glob_import.rs
@@ -0,0 +1,24 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/98003>.
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+// @has glob_import.json
+// @has - "$.index[*][?(@.name=='glob')]"
+// @has - "$.index[*][?(@.kind=='import')].inner.name" \"*\"
+
+
+mod m1 {
+ pub fn f() {}
+}
+mod m2 {
+ pub fn f(_: u8) {}
+}
+
+pub use m1::*;
+pub use m2::*;
+
+pub mod glob {
+ pub use *;
+}
diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs
new file mode 100644
index 000000000..a3d55b35f
--- /dev/null
+++ b/src/test/rustdoc-json/impls/blanket_with_local.rs
@@ -0,0 +1,18 @@
+// Test for the ICE in rust/83718
+// A blanket impl plus a local type together shouldn't result in mismatched ID issues
+
+// @has blanket_with_local.json "$.index[*][?(@.name=='Load')]"
+pub trait Load {
+ // @has - "$.index[*][?(@.name=='load')]"
+ fn load() {}
+ // @has - "$.index[*][?(@.name=='write')]"
+ fn write(self) {}
+}
+
+impl<P> Load for P {
+ fn load() {}
+ fn write(self) {}
+}
+
+// @has - "$.index[*][?(@.name=='Wrapper')]"
+pub struct Wrapper {}
diff --git a/src/test/rustdoc-json/keyword.rs b/src/test/rustdoc-json/keyword.rs
new file mode 100644
index 000000000..78a843aca
--- /dev/null
+++ b/src/test/rustdoc-json/keyword.rs
@@ -0,0 +1,21 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98002>.
+
+// Keywords should not be generated in rustdoc JSON output and this test
+// ensures it.
+
+#![feature(rustdoc_internals)]
+#![no_std]
+
+// @has keyword.json
+// @!has - "$.index[*][?(@.name=='match')]"
+// @has - "$.index[*][?(@.name=='foo')]"
+
+#[doc(keyword = "match")]
+/// this is a test!
+pub mod foo {}
+
+// @!has - "$.index[*][?(@.name=='hello')]"
+// @!has - "$.index[*][?(@.name=='bar')]"
+#[doc(keyword = "hello")]
+/// hello
+mod bar {}
diff --git a/src/test/rustdoc-json/lifetime/longest.rs b/src/test/rustdoc-json/lifetime/longest.rs
new file mode 100644
index 000000000..95b99599e
--- /dev/null
+++ b/src/test/rustdoc-json/lifetime/longest.rs
@@ -0,0 +1,33 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @is longest.json "$.index[*][?(@.name=='longest')].inner.generics.params[0].name" \"\'a\"
+// @is - "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}'
+// @is - "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}'
+// @count - "$.index[*][?(@.name=='longest')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='longest')].inner.generics.where_predicates" []
+
+// @count - "$.index[*][?(@.name=='longest')].inner.decl.inputs[*]" 2
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][0]" '"l"'
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][0]" '"r"'
+
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.mutable" false
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.type" '{"inner": "str", "kind": "primitive"}'
+
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.mutable" false
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.type" '{"inner": "str", "kind": "primitive"}'
+
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.mutable" false
+// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.type" '{"inner": "str", "kind": "primitive"}'
+
+pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str {
+ if l.len() > r.len() { l } else { r }
+}
diff --git a/src/test/rustdoc-json/lifetime/outlives.rs b/src/test/rustdoc-json/lifetime/outlives.rs
new file mode 100644
index 000000000..096dd7f7a
--- /dev/null
+++ b/src/test/rustdoc-json/lifetime/outlives.rs
@@ -0,0 +1,23 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @count outlives.json "$.index[*][?(@.name=='foo')].inner.generics.params[*]" 3
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.where_predicates" []
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[0].name" \"\'a\"
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[1].name" \"\'b\"
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].name" '"T"'
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[0].kind.lifetime.outlives" []
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[1].kind.lifetime.outlives" [\"\'a\"]
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.default" null
+// @count - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[0].outlives" \"\'b\"
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.mutable" false
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.lifetime" \"\'b\"
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.mutable" false
+// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.type" '{"inner": "T", "kind": "generic"}'
+pub fn foo<'a, 'b: 'a, T: 'b>(_: &'a &'b T) {}
diff --git a/src/test/rustdoc-json/methods/abi.rs b/src/test/rustdoc-json/methods/abi.rs
new file mode 100644
index 000000000..07b01d03b
--- /dev/null
+++ b/src/test/rustdoc-json/methods/abi.rs
@@ -0,0 +1,55 @@
+// ignore-tidy-linelength
+
+#![feature(abi_vectorcall)]
+#![feature(c_unwind)]
+#![feature(no_core)]
+#![no_core]
+
+// @has abi.json "$.index[*][?(@.name=='Foo')]"
+pub struct Foo;
+
+impl Foo {
+ // @is - "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\"
+ pub fn abi_rust() {}
+
+ // @is - "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}'
+ pub extern "C" fn abi_c() {}
+
+ // @is - "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}'
+ pub extern "system" fn abi_system() {}
+
+ // @is - "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}'
+ pub extern "C-unwind" fn abi_c_unwind() {}
+
+ // @is - "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}'
+ pub extern "system-unwind" fn abi_system_unwind() {}
+
+ // @is - "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""'
+ pub extern "vectorcall" fn abi_vectorcall() {}
+
+ // @is - "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""'
+ pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
+}
+
+pub trait Bar {
+ // @is - "$.index[*][?(@.name=='trait_abi_rust')].inner.header.abi" \"Rust\"
+ fn trait_abi_rust() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_c')].inner.header.abi" '{"C": {"unwind": false}}'
+ extern "C" fn trait_abi_c() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_system')].inner.header.abi" '{"System": {"unwind": false}}'
+ extern "system" fn trait_abi_system() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}'
+ extern "C-unwind" fn trait_abi_c_unwind() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}'
+ extern "system-unwind" fn trait_abi_system_unwind() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""'
+ extern "vectorcall" fn trait_abi_vectorcall() {}
+
+ // @is - "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""'
+ extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {}
+}
diff --git a/src/test/rustdoc-json/methods/qualifiers.rs b/src/test/rustdoc-json/methods/qualifiers.rs
new file mode 100644
index 000000000..af36d36b6
--- /dev/null
+++ b/src/test/rustdoc-json/methods/qualifiers.rs
@@ -0,0 +1,37 @@
+// edition:2018
+
+pub struct Foo;
+
+impl Foo {
+ // @is qualifiers.json "$.index[*][?(@.name=='const_meth')].inner.header.async" false
+ // @is - "$.index[*][?(@.name=='const_meth')].inner.header.const" true
+ // @is - "$.index[*][?(@.name=='const_meth')].inner.header.unsafe" false
+ pub const fn const_meth() {}
+
+ // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.async" false
+ // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.const" false
+ // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.unsafe" false
+ pub fn nothing_meth() {}
+
+ // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.async" false
+ // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.const" false
+ // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.unsafe" true
+ pub unsafe fn unsafe_meth() {}
+
+ // @is - "$.index[*][?(@.name=='async_meth')].inner.header.async" true
+ // @is - "$.index[*][?(@.name=='async_meth')].inner.header.const" false
+ // @is - "$.index[*][?(@.name=='async_meth')].inner.header.unsafe" false
+ pub async fn async_meth() {}
+
+ // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.async" true
+ // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.const" false
+ // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.unsafe" true
+ pub async unsafe fn async_unsafe_meth() {}
+
+ // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.async" false
+ // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.const" true
+ // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.unsafe" true
+ pub const unsafe fn const_unsafe_meth() {}
+
+ // It's impossible for a method to be both const and async, so no test for that
+}
diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs
new file mode 100644
index 000000000..b0e717d8a
--- /dev/null
+++ b/src/test/rustdoc-json/nested.rs
@@ -0,0 +1,30 @@
+// edition:2018
+// compile-flags: --crate-version 1.0.0
+
+// @is nested.json "$.crate_version" \"1.0.0\"
+// @is - "$.index[*][?(@.name=='nested')].kind" \"module\"
+// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
+// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1
+
+// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
+// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false
+// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2
+pub mod l1 {
+
+ // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
+ // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false
+ // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1
+ // @set l3_id = - "$.index[*][?(@.name=='l3')].id"
+ // @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id
+ pub mod l3 {
+
+ // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
+ // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
+ // @set l4_id = - "$.index[*][?(@.name=='L4')].id"
+ // @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
+ pub struct L4;
+ }
+ // @is nested.json "$.index[*][?(@.inner.source=='l3::L4')].kind" \"import\"
+ // @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.glob" false
+ pub use l3::L4;
+}
diff --git a/src/test/rustdoc-json/output_generics.rs b/src/test/rustdoc-json/output_generics.rs
new file mode 100644
index 000000000..d80656c7f
--- /dev/null
+++ b/src/test/rustdoc-json/output_generics.rs
@@ -0,0 +1,38 @@
+// compile-flags: --document-private-items --document-hidden-items
+
+// This is a regression test for #98009.
+
+// @has output_generics.json
+// @has - "$.index[*][?(@.name=='this_compiles')]"
+// @has - "$.index[*][?(@.name=='this_does_not')]"
+// @has - "$.index[*][?(@.name=='Events')]"
+// @has - "$.index[*][?(@.name=='Other')]"
+// @has - "$.index[*][?(@.name=='Trait')]"
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+ fn handle(value: T) -> Self;
+}
+
+impl<T, U> Trait<U> for T where T: From<U> {
+ fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+ fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(&mut *value);
+ }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+ for _ in 0..3 {
+ Other::handle(value);
+ }
+}
diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs
new file mode 100644
index 000000000..b84c2f7c6
--- /dev/null
+++ b/src/test/rustdoc-json/primitive.rs
@@ -0,0 +1,14 @@
+// edition:2018
+
+#![feature(rustdoc_internals)]
+
+#[doc(primitive = "usize")]
+mod usize {}
+
+// @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id"
+
+// @has - "$.index[*][?(@.name=='log10')]"
+// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id
+// @has - "$.index[*][?(@.name=='checked_add')]"
+// @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id
+// @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]"
diff --git a/src/test/rustdoc-json/primitive_overloading.rs b/src/test/rustdoc-json/primitive_overloading.rs
new file mode 100644
index 000000000..a10d5a837
--- /dev/null
+++ b/src/test/rustdoc-json/primitive_overloading.rs
@@ -0,0 +1,17 @@
+// compile-flags: --document-private-items
+
+// Regression test for <https://github.com/rust-lang/rust/issues/98006>.
+
+#![feature(rustdoc_internals)]
+#![feature(no_core)]
+
+#![no_core]
+
+// @has primitive_overloading.json
+// @has - "$.index[*][?(@.name=='usize')]"
+// @has - "$.index[*][?(@.name=='prim')]"
+
+#[doc(primitive = "usize")]
+/// This is the built-in type `usize`.
+mod prim {
+}
diff --git a/src/test/rustdoc-json/primitives.rs b/src/test/rustdoc-json/primitives.rs
new file mode 100644
index 000000000..fd04f04da
--- /dev/null
+++ b/src/test/rustdoc-json/primitives.rs
@@ -0,0 +1,22 @@
+#![feature(never_type)]
+
+// @has primitives.json "$.index[*][?(@.name=='PrimNever')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\"
+// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\"
+pub type PrimNever = !;
+
+// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\"
+// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\"
+pub type PrimStr = str;
+
+// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\"
+// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\"
+pub type PrimBool = bool;
+
+// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\"
+// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\"
+pub type PrimChar = char;
+
+// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\"
+// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\"
+pub type PrimU8 = u8;
diff --git a/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs
new file mode 100644
index 000000000..4a835673a
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs
@@ -0,0 +1 @@
+pub struct Foo;
diff --git a/src/test/rustdoc-json/reexport/glob_extern.rs b/src/test/rustdoc-json/reexport/glob_extern.rs
new file mode 100644
index 000000000..ba1cfd8a0
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/glob_extern.rs
@@ -0,0 +1,18 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @is glob_extern.json "$.index[*][?(@.name=='mod1')].kind" \"module\"
+// @is glob_extern.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
+mod mod1 {
+ extern "C" {
+ // @has - "$.index[*][?(@.name=='public_fn')].id"
+ pub fn public_fn();
+ // @!has - "$.index[*][?(@.name=='private_fn')]"
+ fn private_fn();
+ }
+}
+
+// @is - "$.index[*][?(@.kind=='import')].inner.glob" true
+pub use mod1::*;
diff --git a/src/test/rustdoc-json/reexport/glob_private.rs b/src/test/rustdoc-json/reexport/glob_private.rs
new file mode 100644
index 000000000..e6a44748c
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/glob_private.rs
@@ -0,0 +1,32 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @is glob_private.json "$.index[*][?(@.name=='mod1')].kind" \"module\"
+// @is glob_private.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
+mod mod1 {
+ // @is - "$.index[*][?(@.name=='mod2')].kind" \"module\"
+ // @is - "$.index[*][?(@.name=='mod2')].inner.is_stripped" "true"
+ mod mod2 {
+ // @set m2pub_id = - "$.index[*][?(@.name=='Mod2Public')].id"
+ pub struct Mod2Public;
+
+ // @!has - "$.index[*][?(@.name=='Mod2Private')]"
+ struct Mod2Private;
+ }
+
+ // @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')]"
+ pub use self::mod2::*;
+
+ // @set m1pub_id = - "$.index[*][?(@.name=='Mod1Public')].id"
+ pub struct Mod1Public;
+ // @!has - "$.index[*][?(@.name=='Mod1Private')]"
+ struct Mod1Private;
+}
+
+// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')]"
+pub use mod1::*;
+
+// @has - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id
+// @has - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id
diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod.rs b/src/test/rustdoc-json/reexport/in_root_and_mod.rs
new file mode 100644
index 000000000..7bf10a986
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/in_root_and_mod.rs
@@ -0,0 +1,17 @@
+#![feature(no_core)]
+#![no_core]
+
+// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].kind" \"module\"
+// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].inner.is_stripped" "true"
+mod foo {
+ // @has - "$.index[*][?(@.name=='Foo')]"
+ pub struct Foo;
+}
+
+// @has - "$.index[*][?(@.kind=='import' && @.inner.source=='foo::Foo')]"
+pub use foo::Foo;
+
+pub mod bar {
+ // @has - "$.index[*][?(@.kind=='import' && @.inner.source=='crate::foo::Foo')]"
+ pub use crate::foo::Foo;
+}
diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
new file mode 100644
index 000000000..2daadf762
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
@@ -0,0 +1,20 @@
+#![feature(no_core)]
+#![no_core]
+
+pub mod foo {
+ // @set bar_id = in_root_and_mod_pub.json "$.index[*][?(@.name=='Bar')].id"
+ // @has - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id
+ pub struct Bar;
+}
+
+// @set root_import_id = - "$.index[*][?(@.inner.source=='foo::Bar')].id"
+// @is - "$.index[*][?(@.inner.source=='foo::Bar')].inner.id" $bar_id
+// @has - "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.items[*]" $root_import_id
+pub use foo::Bar;
+
+pub mod baz {
+ // @set baz_import_id = - "$.index[*][?(@.inner.source=='crate::foo::Bar')].id"
+ // @is - "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id
+ // @has - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id
+ pub use crate::foo::Bar;
+}
diff --git a/src/test/rustdoc-json/reexport/macro.rs b/src/test/rustdoc-json/reexport/macro.rs
new file mode 100644
index 000000000..b86614ffb
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/macro.rs
@@ -0,0 +1,17 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2
+
+// @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+// @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id
+pub use crate::repro as repro2;
diff --git a/src/test/rustdoc-json/reexport/private_twice_one_inline.rs b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs
new file mode 100644
index 000000000..327b0f45f
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs
@@ -0,0 +1,18 @@
+// aux-build:pub-struct.rs
+
+// Test for the ICE in rust/83057
+// Am external type re-exported with different attributes shouldn't cause an error
+
+#![no_core]
+#![feature(no_core)]
+
+extern crate pub_struct as foo;
+
+#[doc(inline)]
+pub use foo::Foo;
+
+pub mod bar {
+ pub use foo::Foo;
+}
+
+// @count private_twice_one_inline.json "$.index[*][?(@.kind=='import')]" 2
diff --git a/src/test/rustdoc-json/reexport/private_two_names.rs b/src/test/rustdoc-json/reexport/private_two_names.rs
new file mode 100644
index 000000000..36d6a50d3
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/private_two_names.rs
@@ -0,0 +1,17 @@
+// Test for the ICE in rust/83720
+// A pub-in-private type re-exported under two different names shouldn't cause an error
+
+#![no_core]
+#![feature(no_core)]
+
+// @is private_two_names.json "$.index[*][?(@.name=='style')].kind" \"module\"
+// @is private_two_names.json "$.index[*][?(@.name=='style')].inner.is_stripped" "true"
+mod style {
+ // @has - "$.index[*](?(@.name=='Color'))"
+ pub struct Color;
+}
+
+// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')]"
+pub use style::Color;
+// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')]"
+pub use style::Color as Colour;
diff --git a/src/test/rustdoc-json/reexport/rename_private.rs b/src/test/rustdoc-json/reexport/rename_private.rs
new file mode 100644
index 000000000..2476399bd
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/rename_private.rs
@@ -0,0 +1,14 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @is rename_private.json "$.index[*][?(@.name=='inner')].kind" \"module\"
+// @is rename_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true"
+mod inner {
+ // @has - "$.index[*][?(@.name=='Public')]"
+ pub struct Public;
+}
+
+// @is - "$.index[*][?(@.kind=='import')].inner.name" \"NewName\"
+pub use inner::Public as NewName;
diff --git a/src/test/rustdoc-json/reexport/rename_public.rs b/src/test/rustdoc-json/reexport/rename_public.rs
new file mode 100644
index 000000000..2dd438d22
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/rename_public.rs
@@ -0,0 +1,17 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @set inner_id = rename_public.json "$.index[*][?(@.name=='inner')].id"
+// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id
+pub mod inner {
+ // @set public_id = - "$.index[*][?(@.name=='Public')].id"
+ // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
+ pub struct Public;
+}
+// @set import_id = - "$.index[*][?(@.inner.name=='NewName')].id"
+// @!has - "$.index[*][?(@.inner.name=='Public')]"
+// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $import_id
+// @is - "$.index[*][?(@.inner.name=='NewName')].inner.source" \"inner::Public\"
+pub use inner::Public as NewName;
diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
new file mode 100644
index 000000000..eedddd6a7
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
@@ -0,0 +1,15 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/97432>.
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+// @has same_type_reexported_more_than_once.json
+// @has - "$.index[*][?(@.name=='Trait')]"
+pub use inner::Trait;
+// @has - "$.index[*].inner[?(@.name=='Reexport')].id"
+pub use inner::Trait as Reexport;
+
+mod inner {
+ pub trait Trait {}
+}
diff --git a/src/test/rustdoc-json/reexport/simple_private.rs b/src/test/rustdoc-json/reexport/simple_private.rs
new file mode 100644
index 000000000..5ec13e403
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/simple_private.rs
@@ -0,0 +1,15 @@
+// edition:2018
+#![no_core]
+#![feature(no_core)]
+
+// @is simple_private.json "$.index[*][?(@.name=='inner')].kind" \"module\"
+// @is simple_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true"
+mod inner {
+ // @set pub_id = - "$.index[*][?(@.name=='Public')].id"
+ pub struct Public;
+}
+
+// @is - "$.index[*][?(@.kind=='import')].inner.name" \"Public\"
+pub use inner::Public;
+
+// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
diff --git a/src/test/rustdoc-json/reexport/simple_public.rs b/src/test/rustdoc-json/reexport/simple_public.rs
new file mode 100644
index 000000000..2e4de301f
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/simple_public.rs
@@ -0,0 +1,18 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @set inner_id = simple_public.json "$.index[*][?(@.name=='inner')].id"
+// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $inner_id
+pub mod inner {
+
+ // @set public_id = - "$.index[*][?(@.name=='Public')].id"
+ // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
+ pub struct Public;
+}
+
+// @set import_id = - "$.index[*][?(@.inner.name=='Public')].id"
+// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id
+// @is - "$.index[*][?(@.inner.name=='Public')].inner.source" \"inner::Public\"
+pub use inner::Public;
diff --git a/src/test/rustdoc-json/return_private.rs b/src/test/rustdoc-json/return_private.rs
new file mode 100644
index 000000000..6b324d009
--- /dev/null
+++ b/src/test/rustdoc-json/return_private.rs
@@ -0,0 +1,15 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/96161>.
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+mod secret {
+ pub struct Secret;
+}
+
+// @is return_private.json "$.index[*][?(@.name=='get_secret')].kind" \"function\"
+// @is return_private.json "$.index[*][?(@.name=='get_secret')].inner.decl.output.inner.name" \"secret::Secret\"
+pub fn get_secret() -> secret::Secret {
+ secret::Secret
+}
diff --git a/src/test/rustdoc-json/stripped_modules.rs b/src/test/rustdoc-json/stripped_modules.rs
new file mode 100644
index 000000000..91f9f02ad
--- /dev/null
+++ b/src/test/rustdoc-json/stripped_modules.rs
@@ -0,0 +1,21 @@
+#![no_core]
+#![feature(no_core)]
+
+// @!has stripped_modules.json "$.index[*][?(@.name=='no_pub_inner')]"
+mod no_pub_inner {
+ fn priv_inner() {}
+}
+
+// @!has - "$.index[*][?(@.name=='pub_inner_unreachable')]"
+mod pub_inner_unreachable {
+ // @!has - "$.index[*][?(@.name=='pub_inner_1')]"
+ pub fn pub_inner_1() {}
+}
+
+// @has - "$.index[*][?(@.name=='pub_inner_reachable')]"
+mod pub_inner_reachable {
+ // @has - "$.index[*][?(@.name=='pub_inner_2')]"
+ pub fn pub_inner_2() {}
+}
+
+pub use pub_inner_reachable::pub_inner_2;
diff --git a/src/test/rustdoc-json/structs/plain_empty.rs b/src/test/rustdoc-json/structs/plain_empty.rs
new file mode 100644
index 000000000..a251caf4b
--- /dev/null
+++ b/src/test/rustdoc-json/structs/plain_empty.rs
@@ -0,0 +1,6 @@
+// @has plain_empty.json "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
+// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\"
+// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false
+// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.fields" []
+pub struct PlainEmpty {}
diff --git a/src/test/rustdoc-json/structs/tuple.rs b/src/test/rustdoc-json/structs/tuple.rs
new file mode 100644
index 000000000..4e510b398
--- /dev/null
+++ b/src/test/rustdoc-json/structs/tuple.rs
@@ -0,0 +1,5 @@
+// @has tuple.json "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
+// @has - "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\"
+// @has - "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true
+pub struct Tuple(u32, String);
diff --git a/src/test/rustdoc-json/structs/unit.rs b/src/test/rustdoc-json/structs/unit.rs
new file mode 100644
index 000000000..559d3068d
--- /dev/null
+++ b/src/test/rustdoc-json/structs/unit.rs
@@ -0,0 +1,5 @@
+// @has unit.json "$.index[*][?(@.name=='Unit')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='Unit')].kind" \"struct\"
+// @has - "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\"
+// @has - "$.index[*][?(@.name=='Unit')].inner.fields" []
+pub struct Unit;
diff --git a/src/test/rustdoc-json/structs/with_generics.rs b/src/test/rustdoc-json/structs/with_generics.rs
new file mode 100644
index 000000000..65cfe7eff
--- /dev/null
+++ b/src/test/rustdoc-json/structs/with_generics.rs
@@ -0,0 +1,14 @@
+use std::collections::HashMap;
+
+// @has with_generics.json "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\"
+// @has - "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true
+pub struct WithGenerics<T, U> {
+ stuff: Vec<T>,
+ things: HashMap<U, U>,
+}
diff --git a/src/test/rustdoc-json/structs/with_primitives.rs b/src/test/rustdoc-json/structs/with_primitives.rs
new file mode 100644
index 000000000..9e64317ec
--- /dev/null
+++ b/src/test/rustdoc-json/structs/with_primitives.rs
@@ -0,0 +1,10 @@
+// @has with_primitives.json "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
+// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
+// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
+// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
+// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
+pub struct WithPrimitives<'a> {
+ num: u32,
+ s: &'a str,
+}
diff --git a/src/test/rustdoc-json/traits/has_body.rs b/src/test/rustdoc-json/traits/has_body.rs
new file mode 100644
index 000000000..44dacb1ee
--- /dev/null
+++ b/src/test/rustdoc-json/traits/has_body.rs
@@ -0,0 +1,21 @@
+// @has has_body.json "$.index[*][?(@.name=='Foo')]"
+pub trait Foo {
+ // @has - "$.index[*][?(@.name=='no_self')].inner.has_body" false
+ fn no_self();
+ // @has - "$.index[*][?(@.name=='move_self')].inner.has_body" false
+ fn move_self(self);
+ // @has - "$.index[*][?(@.name=='ref_self')].inner.has_body" false
+ fn ref_self(&self);
+
+ // @has - "$.index[*][?(@.name=='no_self_def')].inner.has_body" true
+ fn no_self_def() {}
+ // @has - "$.index[*][?(@.name=='move_self_def')].inner.has_body" true
+ fn move_self_def(self) {}
+ // @has - "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true
+ fn ref_self_def(&self) {}
+}
+
+pub trait Bar: Clone {
+ // @has - "$.index[*][?(@.name=='method')].inner.has_body" false
+ fn method(&self, param: usize);
+}
diff --git a/src/test/rustdoc-json/traits/implementors.rs b/src/test/rustdoc-json/traits/implementors.rs
new file mode 100644
index 000000000..f7f03d987
--- /dev/null
+++ b/src/test/rustdoc-json/traits/implementors.rs
@@ -0,0 +1,19 @@
+#![feature(no_core)]
+#![no_core]
+
+// @set wham = implementors.json "$.index[*][?(@.name=='Wham')].id"
+// @count - "$.index[*][?(@.name=='Wham')].inner.implementations[*]" 1
+// @set gmWham = - "$.index[*][?(@.name=='Wham')].inner.implementations[0]"
+pub trait Wham {}
+
+// @count - "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[*]" 1
+// @is - "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[0]" $gmWham
+// @set gm = - "$.index[*][?(@.name=='Wham')].id"
+
+// jsonpath_lib isnt expressive enough (for now) to get the "impl" item, so we
+// just check it isn't pointing to the type, but when you port to jsondocck-ng
+// check what the impl item is
+// @!is - "$.index[*][?(@.name=='Wham')].inner.implementations[0]" $gm
+pub struct GeorgeMichael {}
+
+impl Wham for GeorgeMichael {}
diff --git a/src/test/rustdoc-json/traits/supertrait.rs b/src/test/rustdoc-json/traits/supertrait.rs
new file mode 100644
index 000000000..486a8e713
--- /dev/null
+++ b/src/test/rustdoc-json/traits/supertrait.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+// @set loud_id = supertrait.json "$.index[*][?(@.name=='Loud')].id"
+pub trait Loud {}
+
+// @set very_loud_id = - "$.index[*][?(@.name=='VeryLoud')].id"
+// @count - "$.index[*][?(@.name=='VeryLoud')].inner.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='VeryLoud')].inner.bounds[0].trait_bound.trait.inner.id" $loud_id
+pub trait VeryLoud: Loud {}
+
+// @set sounds_good_id = - "$.index[*][?(@.name=='SoundsGood')].id"
+pub trait SoundsGood {}
+
+// @count - "$.index[*][?(@.name=='MetalBand')].inner.bounds[*]" 2
+// @is - "$.index[*][?(@.name=='MetalBand')].inner.bounds[0].trait_bound.trait.inner.id" $very_loud_id
+// @is - "$.index[*][?(@.name=='MetalBand')].inner.bounds[1].trait_bound.trait.inner.id" $sounds_good_id
+pub trait MetalBand: VeryLoud + SoundsGood {}
+
+// @count - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[*]" 2
+// @is - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[1].trait_bound.trait.inner.id" $very_loud_id
+// @is - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[0].trait_bound.trait.inner.id" $sounds_good_id
+pub trait DnabLatem: SoundsGood + VeryLoud {}
diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs
new file mode 100644
index 000000000..f53dc03f4
--- /dev/null
+++ b/src/test/rustdoc-json/type/dyn.rs
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
+// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
+// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
+
+// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
+pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
diff --git a/src/test/rustdoc-json/type/fn_lifetime.rs b/src/test/rustdoc-json/type/fn_lifetime.rs
new file mode 100644
index 000000000..e0d1e9649
--- /dev/null
+++ b/src/test/rustdoc-json/type/fn_lifetime.rs
@@ -0,0 +1,28 @@
+// ignore-tidy-linelength
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\"
+
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
+// @has - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+
+pub type GenericFn<'a> = fn(&'a i32) -> &'a i32;
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='ForAll')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\"
+// @has - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+pub type ForAll = for<'a> fn(&'a i32) -> &'a i32;
diff --git a/src/test/rustdoc-json/type/generic_default.rs b/src/test/rustdoc-json/type/generic_default.rs
new file mode 100644
index 000000000..b6bb6dcc5
--- /dev/null
+++ b/src/test/rustdoc-json/type/generic_default.rs
@@ -0,0 +1,33 @@
+// ignore-tidy-linelength
+
+// @set result = generic_default.json "$.index[*][?(@.name=='Result')].id"
+pub enum Result<T, E> {
+ Ok(T),
+ Err(E),
+}
+
+// @set my_error = - "$.index[*][?(@.name=='MyError')].id"
+pub struct MyError {}
+
+// @is - "$.index[*][?(@.name=='MyResult')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\"
+// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type"
+// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" []
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\"
+pub type MyResult<T, E = MyError> = Result<T, E>;
diff --git a/src/test/rustdoc-json/unions/impl.rs b/src/test/rustdoc-json/unions/impl.rs
new file mode 100644
index 000000000..0388b4a8c
--- /dev/null
+++ b/src/test/rustdoc-json/unions/impl.rs
@@ -0,0 +1,15 @@
+#![no_std]
+
+// @has impl.json "$.index[*][?(@.name=='Ux')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='Ux')].kind" \"union\"
+pub union Ux {
+ a: u32,
+ b: u64
+}
+
+// @has - "$.index[*][?(@.name=='Num')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='Num')].kind" \"trait\"
+pub trait Num {}
+
+// @count - "$.index[*][?(@.name=='Ux')].inner.impls" 1
+impl Num for Ux {}
diff --git a/src/test/rustdoc-json/unions/union.rs b/src/test/rustdoc-json/unions/union.rs
new file mode 100644
index 000000000..ac2eb7977
--- /dev/null
+++ b/src/test/rustdoc-json/unions/union.rs
@@ -0,0 +1,7 @@
+// @has union.json "$.index[*][?(@.name=='Union')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='Union')].kind" \"union\"
+// @!has - "$.index[*][?(@.name=='Union')].inner.struct_type"
+pub union Union {
+ int: i32,
+ float: f32,
+}
diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
new file mode 100644
index 000000000..e58bba640
--- /dev/null
+++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
@@ -0,0 +1,16 @@
+// This test ensures that rustdoc does not panic on inherented associated types
+// that are referred to without fully-qualified syntax.
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+pub struct Struct;
+
+impl Struct {
+ pub type AssocTy = usize;
+ pub const AssocConst: Self::AssocTy = 42;
+ //~^ ERROR ambiguous associated type
+ //~| HELP use fully-qualified syntax
+ //~| ERROR ambiguous associated type
+ //~| HELP use fully-qualified syntax
+}
diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
new file mode 100644
index 000000000..b963b722f
--- /dev/null
+++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
@@ -0,0 +1,15 @@
+error[E0223]: ambiguous associated type
+ --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
+ |
+LL | pub const AssocConst: Self::AssocTy = 42;
+ | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
+
+error[E0223]: ambiguous associated type
+ --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
+ |
+LL | pub const AssocConst: Self::AssocTy = 42;
+ | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.rs b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs
new file mode 100644
index 000000000..0976515f4
--- /dev/null
+++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs
@@ -0,0 +1,22 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+#[derive(Debug)]
+/// Link to [`S::fmt`]
+//~^ ERROR unresolved link
+pub struct S;
+
+pub mod inner {
+ use std::fmt::Debug;
+ use super::S;
+
+ /// Link to [`S::fmt`]
+ pub fn f() {}
+}
+
+pub mod ambiguous {
+ use std::fmt::{Display, Debug};
+ use super::S;
+
+ /// Link to [`S::fmt`]
+ pub fn f() {}
+}
diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr
new file mode 100644
index 000000000..04594ad41
--- /dev/null
+++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr
@@ -0,0 +1,14 @@
+error: unresolved link to `S::fmt`
+ --> $DIR/assoc-item-not-in-scope.rs:4:15
+ |
+LL | /// Link to [`S::fmt`]
+ | ^^^^^^ the struct `S` has no field or associated item named `fmt`
+ |
+note: the lint level is defined here
+ --> $DIR/assoc-item-not-in-scope.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/auxiliary/empty-fn.rs b/src/test/rustdoc-ui/auxiliary/empty-fn.rs
new file mode 100644
index 000000000..877810f15
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/empty-fn.rs
@@ -0,0 +1,3 @@
+// no-prefer-dynamic
+#![crate_type = "lib"]
+pub fn empty() {}
diff --git a/src/test/rustdoc-ui/auxiliary/extern_macros.rs b/src/test/rustdoc-ui/auxiliary/extern_macros.rs
new file mode 100644
index 000000000..ee1fec4c5
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/extern_macros.rs
@@ -0,0 +1,7 @@
+#[macro_export]
+macro_rules! attrs_on_struct {
+ ( $( #[$attr:meta] )* ) => {
+ $( #[$attr] )*
+ pub struct ExpandedStruct;
+ }
+}
diff --git a/src/test/rustdoc-ui/auxiliary/issue-61592.rs b/src/test/rustdoc-ui/auxiliary/issue-61592.rs
new file mode 100644
index 000000000..57a365b3f
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/issue-61592.rs
@@ -0,0 +1,3 @@
+#![crate_name = "foo"]
+
+pub trait Foo {}
diff --git a/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs b/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs
new file mode 100644
index 000000000..9d6b52b95
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs
@@ -0,0 +1 @@
+//! [`long_cat`] is really long
diff --git a/src/test/rustdoc-ui/auxiliary/overflow.rs b/src/test/rustdoc-ui/auxiliary/overflow.rs
new file mode 100644
index 000000000..ff65936be
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/overflow.rs
@@ -0,0 +1,20 @@
+pub struct B0;
+pub struct B1;
+use std::ops::Shl;
+use std::ops::Sub;
+pub type Shleft<A, B> = <A as Shl<B>>::Output;
+pub type Sub1<A> = <A as Sub<B1>>::Output;
+pub struct UInt<U, B> {
+ pub(crate) msb: U,
+ pub(crate) lsb: B,
+}
+impl<U, B, Ur, Br> Shl<UInt<Ur, Br>> for UInt<U, B>
+where
+ UInt<Ur, Br>: Sub<B1>,
+ UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>,
+{
+ type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>;
+ fn shl(self, rhs: UInt<Ur, Br>) -> Self::Output {
+ unimplemented!()
+ }
+}
diff --git a/src/test/rustdoc-ui/auxiliary/panic-item.rs b/src/test/rustdoc-ui/auxiliary/panic-item.rs
new file mode 100644
index 000000000..17b26850d
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/panic-item.rs
@@ -0,0 +1,17 @@
+// no-prefer-dynamic
+#![crate_type = "lib"]
+#![no_std]
+#![feature(lang_items)]
+
+use core::panic::PanicInfo;
+use core::sync::atomic::{self, Ordering};
+
+#[panic_handler]
+fn panic(_info: &PanicInfo) -> ! {
+ loop {
+ atomic::compiler_fence(Ordering::SeqCst);
+ }
+}
+
+#[lang = "eh_personality"]
+fn foo() {}
diff --git a/src/test/rustdoc-ui/bare-urls.fixed b/src/test/rustdoc-ui/bare-urls.fixed
new file mode 100644
index 000000000..23aa5c44c
--- /dev/null
+++ b/src/test/rustdoc-ui/bare-urls.fixed
@@ -0,0 +1,60 @@
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// <https://somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://subdomain.example.com>
+//~^ ERROR not a hyperlink
+/// <https://somewhere.com?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// hey! <https://somewhere.com/a?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+ /// https://somewhere.com/a?hello=12&bye=11#xyz
+ pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/bare-urls.rs b/src/test/rustdoc-ui/bare-urls.rs
new file mode 100644
index 000000000..592f57343
--- /dev/null
+++ b/src/test/rustdoc-ui/bare-urls.rs
@@ -0,0 +1,60 @@
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// https://somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://subdomain.example.com
+//~^ ERROR not a hyperlink
+/// https://somewhere.com?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+ /// https://somewhere.com/a?hello=12&bye=11#xyz
+ pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/bare-urls.stderr b/src/test/rustdoc-ui/bare-urls.stderr
new file mode 100644
index 000000000..7097a8ddf
--- /dev/null
+++ b/src/test/rustdoc-ui/bare-urls.stderr
@@ -0,0 +1,143 @@
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:5:5
+ |
+LL | /// https://somewhere.com
+ | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+ |
+note: the lint level is defined here
+ --> $DIR/bare-urls.rs:3:9
+ |
+LL | #![deny(rustdoc::bare_urls)]
+ | ^^^^^^^^^^^^^^^^^^
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:7:5
+ |
+LL | /// https://somewhere.com/a
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:9:5
+ |
+LL | /// https://www.somewhere.com
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:11:5
+ |
+LL | /// https://www.somewhere.com/a
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:13:5
+ |
+LL | /// https://subdomain.example.com
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:15:5
+ |
+LL | /// https://somewhere.com?
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:17:5
+ |
+LL | /// https://somewhere.com/a?
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:19:5
+ |
+LL | /// https://somewhere.com?hello=12
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:21:5
+ |
+LL | /// https://somewhere.com/a?hello=12
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:23:5
+ |
+LL | /// https://example.com?hello=12#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:25:5
+ |
+LL | /// https://example.com/a?hello=12#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:27:5
+ |
+LL | /// https://example.com#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:29:5
+ |
+LL | /// https://example.com/a#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:31:5
+ |
+LL | /// https://somewhere.com?hello=12&bye=11
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:33:5
+ |
+LL | /// https://somewhere.com/a?hello=12&bye=11
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:35:5
+ |
+LL | /// https://somewhere.com?hello=12&bye=11#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+ --> $DIR/bare-urls.rs:37:10
+ |
+LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+ |
+ = note: bare URLs are not automatically turned into clickable links
+
+error: aborting due to 17 previous errors
+
diff --git a/src/test/rustdoc-ui/block-doc-comment.rs b/src/test/rustdoc-ui/block-doc-comment.rs
new file mode 100644
index 000000000..ce529916e
--- /dev/null
+++ b/src/test/rustdoc-ui/block-doc-comment.rs
@@ -0,0 +1,17 @@
+// check-pass
+// compile-flags:--test
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// This test ensures that no code block is detected in the doc comments.
+
+pub mod Wormhole {
+ /** # Returns
+ *
+ */
+ pub fn foofoo() {}
+ /**
+ * # Returns
+ *
+ */
+ pub fn barbar() {}
+}
diff --git a/src/test/rustdoc-ui/block-doc-comment.stdout b/src/test/rustdoc-ui/block-doc-comment.stdout
new file mode 100644
index 000000000..7326c0a25
--- /dev/null
+++ b/src/test/rustdoc-ui/block-doc-comment.stdout
@@ -0,0 +1,5 @@
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/bounded-hr-lifetime.rs b/src/test/rustdoc-ui/bounded-hr-lifetime.rs
new file mode 100644
index 000000000..b2e000b97
--- /dev/null
+++ b/src/test/rustdoc-ui/bounded-hr-lifetime.rs
@@ -0,0 +1,9 @@
+// This test ensures that rustdoc doesn't panic on higher-ranked lifetimes
+// with bounds, because an error should have already been emitted by rustc.
+
+pub fn hrlt<'b, 'c>()
+where
+ for<'a: 'b + 'c> &'a (): std::fmt::Debug,
+ //~^ ERROR lifetime bounds cannot be used in this context
+{
+}
diff --git a/src/test/rustdoc-ui/bounded-hr-lifetime.stderr b/src/test/rustdoc-ui/bounded-hr-lifetime.stderr
new file mode 100644
index 000000000..d8fcd6cb4
--- /dev/null
+++ b/src/test/rustdoc-ui/bounded-hr-lifetime.stderr
@@ -0,0 +1,10 @@
+error: lifetime bounds cannot be used in this context
+ --> $DIR/bounded-hr-lifetime.rs:6:13
+ |
+LL | for<'a: 'b + 'c> &'a (): std::fmt::Debug,
+ | ^^ ^^
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/c-help.rs b/src/test/rustdoc-ui/c-help.rs
new file mode 100644
index 000000000..e166edf8b
--- /dev/null
+++ b/src/test/rustdoc-ui/c-help.rs
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Chelp
+// check-stdout
+// regex-error-pattern: -C\s+incremental
+
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/c-help.stdout b/src/test/rustdoc-ui/c-help.stdout
new file mode 100644
index 000000000..75b2e2a2a
--- /dev/null
+++ b/src/test/rustdoc-ui/c-help.stdout
@@ -0,0 +1,51 @@
+ -C ar=val -- this option is deprecated and does nothing
+ -C code-model=val -- choose the code model to use (`rustc --print code-models` for details)
+ -C codegen-units=val -- divide crate into N units to optimize in parallel
+ -C control-flow-guard=val -- use Windows Control Flow Guard (default: no)
+ -C debug-assertions=val -- explicitly enable the `cfg(debug_assertions)` directive
+ -C debuginfo=val -- debug info emission level (0 = no debug info, 1 = line tables only, 2 = full debug info with variable and type information; default: 0)
+ -C default-linker-libraries=val -- allow the linker to link its default libraries (default: no)
+ -C embed-bitcode=val -- emit bitcode in rlibs (default: yes)
+ -C extra-filename=val -- extra data to put in each output filename
+ -C force-frame-pointers=val -- force use of the frame pointers
+ -C force-unwind-tables=val -- force use of unwind tables
+ -C incremental=val -- enable incremental compilation
+ -C inline-threshold=val -- set the threshold for inlining a function
+ -C instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are:
+ `=all` (implicit value)
+ `=except-unused-generics`
+ `=except-unused-functions`
+ `=off` (default)
+ -C link-arg=val -- a single extra argument to append to the linker invocation (can be used several times)
+ -C link-args=val -- extra arguments to append to the linker invocation (space separated)
+ -C link-dead-code=val -- keep dead code at link time (useful for code coverage) (default: no)
+ -C link-self-contained=val -- control whether to link Rust provided C objects/libraries or rely
+ on C toolchain installed in the system
+ -C linker=val -- system linker to link outputs with
+ -C linker-flavor=val -- linker flavor
+ -C linker-plugin-lto=val -- generate build artifacts that are compatible with linker-based LTO
+ -C llvm-args=val -- a list of arguments to pass to LLVM (space separated)
+ -C lto=val -- perform LLVM link-time optimizations
+ -C metadata=val -- metadata to mangle symbol names with
+ -C no-prepopulate-passes=val -- give an empty list of passes to the pass manager
+ -C no-redzone=val -- disable the use of the redzone
+ -C no-stack-check=val -- this option is deprecated and does nothing
+ -C no-vectorize-loops=val -- disable loop vectorization optimization passes
+ -C no-vectorize-slp=val -- disable LLVM's SLP vectorization pass
+ -C opt-level=val -- optimization level (0-3, s, or z; default: 0)
+ -C overflow-checks=val -- use overflow checks for integer arithmetic
+ -C panic=val -- panic strategy to compile crate with
+ -C passes=val -- a list of extra LLVM passes to run (space separated)
+ -C prefer-dynamic=val -- prefer dynamic linking to static linking (default: no)
+ -C profile-generate=val -- compile the program with profiling instrumentation
+ -C profile-use=val -- use the given `.profdata` file for profile-guided optimization
+ -C relocation-model=val -- control generation of position-independent code (PIC) (`rustc --print relocation-models` for details)
+ -C remark=val -- print remarks for these optimization passes (space separated, or "all")
+ -C rpath=val -- set rpath values in libs/exes (default: no)
+ -C save-temps=val -- save all temporary output files during compilation (default: no)
+ -C soft-float=val -- use soft float ABI (*eabihf targets only) (default: no)
+ -C split-debuginfo=val -- how to handle split-debuginfo, a platform-specific option
+ -C strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
+ -C symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
+ -C target-cpu=val -- select target processor (`rustc --print target-cpus` for details)
+ -C target-feature=val -- target specific attributes. (`rustc --print target-features` for details). This feature is unsafe.
diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs
new file mode 100644
index 000000000..d4ca92585
--- /dev/null
+++ b/src/test/rustdoc-ui/cfg-test.rs
@@ -0,0 +1,31 @@
+// check-pass
+// compile-flags:--test --test-args --test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// Crates like core have doctests gated on `cfg(not(test))` so we need to make
+// sure `cfg(test)` is not active when running `rustdoc --test`.
+
+/// this doctest will be ignored:
+///
+/// ```
+/// assert!(false);
+/// ```
+#[cfg(test)]
+pub struct Foo;
+
+/// this doctest will be tested:
+///
+/// ```
+/// assert!(true);
+/// ```
+#[cfg(not(test))]
+pub struct Foo;
+
+/// this doctest will be tested, but will not appear in documentation:
+///
+/// ```
+/// assert!(true)
+/// ```
+#[cfg(doctest)]
+pub struct Bar;
diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout
new file mode 100644
index 000000000..2960ff8d3
--- /dev/null
+++ b/src/test/rustdoc-ui/cfg-test.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test $DIR/cfg-test.rs - Bar (line 27) ... ok
+test $DIR/cfg-test.rs - Foo (line 19) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/check-attr-test.rs b/src/test/rustdoc-ui/check-attr-test.rs
new file mode 100644
index 000000000..e95547014
--- /dev/null
+++ b/src/test/rustdoc-ui/check-attr-test.rs
@@ -0,0 +1,31 @@
+// compile-flags:--test
+
+#![deny(rustdoc::invalid_codeblock_attributes)]
+
+/// foo
+///
+/// ```compile-fail,compilefail,comPile_fail
+/// boo
+/// ```
+pub fn foo() {}
+
+/// bar
+///
+/// ```should-panic,shouldpanic,shOuld_panic
+/// boo
+/// ```
+pub fn bar() {}
+
+/// foobar
+///
+/// ```no-run,norun,nO_run
+/// boo
+/// ```
+pub fn foobar() {}
+
+/// b
+///
+/// ```test-harness,testharness,tesT_harness
+/// boo
+/// ```
+pub fn b() {}
diff --git a/src/test/rustdoc-ui/check-attr-test.stderr b/src/test/rustdoc-ui/check-attr-test.stderr
new file mode 100644
index 000000000..b1fa9edf0
--- /dev/null
+++ b/src/test/rustdoc-ui/check-attr-test.stderr
@@ -0,0 +1,151 @@
+error: unknown attribute `compile-fail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr-test.rs:5:1
+ |
+5 | / /// foo
+6 | | ///
+7 | | /// ```compile-fail,compilefail,comPile_fail
+8 | | /// boo
+9 | | /// ```
+ | |_______^
+ |
+note: the lint level is defined here
+ --> $DIR/check-attr-test.rs:3:9
+ |
+3 | #![deny(rustdoc::invalid_codeblock_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `compilefail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr-test.rs:5:1
+ |
+5 | / /// foo
+6 | | ///
+7 | | /// ```compile-fail,compilefail,comPile_fail
+8 | | /// boo
+9 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `comPile_fail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr-test.rs:5:1
+ |
+5 | / /// foo
+6 | | ///
+7 | | /// ```compile-fail,compilefail,comPile_fail
+8 | | /// boo
+9 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `should-panic`. Did you mean `should_panic`?
+ --> $DIR/check-attr-test.rs:12:1
+ |
+12 | / /// bar
+13 | | ///
+14 | | /// ```should-panic,shouldpanic,shOuld_panic
+15 | | /// boo
+16 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `shouldpanic`. Did you mean `should_panic`?
+ --> $DIR/check-attr-test.rs:12:1
+ |
+12 | / /// bar
+13 | | ///
+14 | | /// ```should-panic,shouldpanic,shOuld_panic
+15 | | /// boo
+16 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `shOuld_panic`. Did you mean `should_panic`?
+ --> $DIR/check-attr-test.rs:12:1
+ |
+12 | / /// bar
+13 | | ///
+14 | | /// ```should-panic,shouldpanic,shOuld_panic
+15 | | /// boo
+16 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `no-run`. Did you mean `no_run`?
+ --> $DIR/check-attr-test.rs:19:1
+ |
+19 | / /// foobar
+20 | | ///
+21 | | /// ```no-run,norun,nO_run
+22 | | /// boo
+23 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `norun`. Did you mean `no_run`?
+ --> $DIR/check-attr-test.rs:19:1
+ |
+19 | / /// foobar
+20 | | ///
+21 | | /// ```no-run,norun,nO_run
+22 | | /// boo
+23 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `nO_run`. Did you mean `no_run`?
+ --> $DIR/check-attr-test.rs:19:1
+ |
+19 | / /// foobar
+20 | | ///
+21 | | /// ```no-run,norun,nO_run
+22 | | /// boo
+23 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `test-harness`. Did you mean `test_harness`?
+ --> $DIR/check-attr-test.rs:26:1
+ |
+26 | / /// b
+27 | | ///
+28 | | /// ```test-harness,testharness,tesT_harness
+29 | | /// boo
+30 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: unknown attribute `testharness`. Did you mean `test_harness`?
+ --> $DIR/check-attr-test.rs:26:1
+ |
+26 | / /// b
+27 | | ///
+28 | | /// ```test-harness,testharness,tesT_harness
+29 | | /// boo
+30 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
+ --> $DIR/check-attr-test.rs:26:1
+ |
+26 | / /// b
+27 | | ///
+28 | | /// ```test-harness,testharness,tesT_harness
+29 | | /// boo
+30 | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/rustdoc-ui/check-attr.rs b/src/test/rustdoc-ui/check-attr.rs
new file mode 100644
index 000000000..0b3f7bedd
--- /dev/null
+++ b/src/test/rustdoc-ui/check-attr.rs
@@ -0,0 +1,41 @@
+#![deny(rustdoc::invalid_codeblock_attributes)]
+
+/// foo
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+///
+/// ```compile-fail,compilefail,comPile_fail
+/// boo
+/// ```
+pub fn foo() {}
+
+/// bar
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+///
+/// ```should-panic,shouldpanic,sHould_panic
+/// boo
+/// ```
+pub fn bar() {}
+
+/// foobar
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+///
+/// ```no-run,norun,no_Run
+/// boo
+/// ```
+pub fn foobar() {}
+
+/// b
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+///
+/// ```test-harness,testharness,teSt_harness
+/// boo
+/// ```
+pub fn b() {}
diff --git a/src/test/rustdoc-ui/check-attr.stderr b/src/test/rustdoc-ui/check-attr.stderr
new file mode 100644
index 000000000..370b804c5
--- /dev/null
+++ b/src/test/rustdoc-ui/check-attr.stderr
@@ -0,0 +1,175 @@
+error: unknown attribute `compile-fail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr.rs:3:1
+ |
+LL | / /// foo
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+note: the lint level is defined here
+ --> $DIR/check-attr.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_codeblock_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `compilefail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr.rs:3:1
+ |
+LL | / /// foo
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `comPile_fail`. Did you mean `compile_fail`?
+ --> $DIR/check-attr.rs:3:1
+ |
+LL | / /// foo
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+
+error: unknown attribute `should-panic`. Did you mean `should_panic`?
+ --> $DIR/check-attr.rs:13:1
+ |
+LL | / /// bar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `shouldpanic`. Did you mean `should_panic`?
+ --> $DIR/check-attr.rs:13:1
+ |
+LL | / /// bar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `sHould_panic`. Did you mean `should_panic`?
+ --> $DIR/check-attr.rs:13:1
+ |
+LL | / /// bar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+
+error: unknown attribute `no-run`. Did you mean `no_run`?
+ --> $DIR/check-attr.rs:23:1
+ |
+LL | / /// foobar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `norun`. Did you mean `no_run`?
+ --> $DIR/check-attr.rs:23:1
+ |
+LL | / /// foobar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `no_Run`. Did you mean `no_run`?
+ --> $DIR/check-attr.rs:23:1
+ |
+LL | / /// foobar
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+
+error: unknown attribute `test-harness`. Did you mean `test_harness`?
+ --> $DIR/check-attr.rs:33:1
+ |
+LL | / /// b
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: unknown attribute `testharness`. Did you mean `test_harness`?
+ --> $DIR/check-attr.rs:33:1
+ |
+LL | / /// b
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: unknown attribute `teSt_harness`. Did you mean `test_harness`?
+ --> $DIR/check-attr.rs:33:1
+ |
+LL | / /// b
+LL | |
+LL | |
+LL | |
+... |
+LL | | /// boo
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/rustdoc-ui/check-cfg-test.rs b/src/test/rustdoc-ui/check-cfg-test.rs
new file mode 100644
index 000000000..626cc8387
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg-test.rs
@@ -0,0 +1,12 @@
+// check-pass
+// compile-flags: --test --nocapture --check-cfg=values(feature,"test") -Z unstable-options
+// normalize-stderr-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// The doctest will produce a warning because feature invalid is unexpected
+/// ```
+/// #[cfg(feature = "invalid")]
+/// assert!(false);
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-cfg-test.stderr b/src/test/rustdoc-ui/check-cfg-test.stderr
new file mode 100644
index 000000000..dc25205da
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg-test.stderr
@@ -0,0 +1,11 @@
+warning: unexpected `cfg` condition value
+ --> $DIR/check-cfg-test.rs:9:7
+ |
+LL | #[cfg(feature = "invalid")]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unexpected_cfgs)]` on by default
+ = note: expected values for `feature` are: test
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/check-cfg-test.stdout b/src/test/rustdoc-ui/check-cfg-test.stdout
new file mode 100644
index 000000000..b7db49bcf
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg-test.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/check-cfg-test.rs - Foo (line 8) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/check-cfg-unstable.rs b/src/test/rustdoc-ui/check-cfg-unstable.rs
new file mode 100644
index 000000000..5c500ce6c
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg-unstable.rs
@@ -0,0 +1,2 @@
+// check-fail
+// compile-flags: --check-cfg=names()
diff --git a/src/test/rustdoc-ui/check-cfg-unstable.stderr b/src/test/rustdoc-ui/check-cfg-unstable.stderr
new file mode 100644
index 000000000..9b27c2bc0
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg-unstable.stderr
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `check-cfg`
+
diff --git a/src/test/rustdoc-ui/check-cfg.rs b/src/test/rustdoc-ui/check-cfg.rs
new file mode 100644
index 000000000..fa8789ad3
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg.rs
@@ -0,0 +1,7 @@
+// check-pass
+// compile-flags: --check-cfg=names() -Z unstable-options
+
+/// uniz is nor a builtin nor pass as arguments so is unexpected
+#[cfg(uniz)]
+//~^ WARNING unexpected `cfg` condition name
+pub struct Bar;
diff --git a/src/test/rustdoc-ui/check-cfg.stderr b/src/test/rustdoc-ui/check-cfg.stderr
new file mode 100644
index 000000000..1db8e1d91
--- /dev/null
+++ b/src/test/rustdoc-ui/check-cfg.stderr
@@ -0,0 +1,10 @@
+warning: unexpected `cfg` condition name
+ --> $DIR/check-cfg.rs:5:7
+ |
+LL | #[cfg(uniz)]
+ | ^^^^ help: did you mean: `unix`
+ |
+ = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr-location.rs b/src/test/rustdoc-ui/check-doc-alias-attr-location.rs
new file mode 100644
index 000000000..6de1960e2
--- /dev/null
+++ b/src/test/rustdoc-ui/check-doc-alias-attr-location.rs
@@ -0,0 +1,23 @@
+pub struct Bar;
+pub trait Foo {
+ type X;
+ fn foo() -> Self::X;
+}
+
+#[doc(alias = "foo")] //~ ERROR
+extern "C" {}
+
+#[doc(alias = "bar")] //~ ERROR
+impl Bar {
+ #[doc(alias = "const")]
+ pub const A: u32 = 0;
+}
+
+#[doc(alias = "foobar")] //~ ERROR
+impl Foo for Bar {
+ #[doc(alias = "assoc")] //~ ERROR
+ type X = i32;
+ fn foo() -> Self::X {
+ 0
+ }
+}
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
new file mode 100644
index 000000000..85c951623
--- /dev/null
+++ b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
@@ -0,0 +1,26 @@
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
+ --> $DIR/check-doc-alias-attr-location.rs:7:7
+ |
+LL | #[doc(alias = "foo")]
+ | ^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on implementation block
+ --> $DIR/check-doc-alias-attr-location.rs:10:7
+ |
+LL | #[doc(alias = "bar")]
+ | ^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on implementation block
+ --> $DIR/check-doc-alias-attr-location.rs:16:7
+ |
+LL | #[doc(alias = "foobar")]
+ | ^^^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block
+ --> $DIR/check-doc-alias-attr-location.rs:18:11
+ |
+LL | #[doc(alias = "assoc")]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
new file mode 100644
index 000000000..719b98604
--- /dev/null
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs
@@ -0,0 +1,28 @@
+#![crate_type = "lib"]
+
+#[doc(alias = "foo")] // ok!
+#[doc(alias("bar", "baz"))] // ok!
+pub struct Bar;
+
+#[doc(alias)] //~ ERROR
+#[doc(alias = 0)] //~ ERROR
+#[doc(alias = "\"")] //~ ERROR
+#[doc(alias = "\n")] //~ ERROR
+#[doc(alias = "
+")] //~^ ERROR
+#[doc(alias = "\t")] //~ ERROR
+#[doc(alias = " hello")] //~ ERROR
+#[doc(alias = "hello ")] //~ ERROR
+#[doc(alias = "")] //~ ERROR
+pub struct Foo;
+
+#[doc(alias(0))] //~ ERROR
+#[doc(alias("\""))] //~ ERROR
+#[doc(alias("\n"))] //~ ERROR
+#[doc(alias("
+"))] //~^ ERROR
+#[doc(alias("\t"))] //~ ERROR
+#[doc(alias(" hello"))] //~ ERROR
+#[doc(alias("hello "))] //~ ERROR
+#[doc(alias(""))] //~ ERROR
+pub struct Foo2;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
new file mode 100644
index 000000000..250568be3
--- /dev/null
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
@@ -0,0 +1,108 @@
+error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
+ --> $DIR/check-doc-alias-attr.rs:7:7
+ |
+LL | #[doc(alias)]
+ | ^^^^^
+
+error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
+ --> $DIR/check-doc-alias-attr.rs:8:7
+ |
+LL | #[doc(alias = 0)]
+ | ^^^^^^^^^
+
+error: '"' character isn't allowed in `#[doc(alias = "...")]`
+ --> $DIR/check-doc-alias-attr.rs:9:15
+ |
+LL | #[doc(alias = "\"")]
+ | ^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+ --> $DIR/check-doc-alias-attr.rs:10:15
+ |
+LL | #[doc(alias = "\n")]
+ | ^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+ --> $DIR/check-doc-alias-attr.rs:11:15
+ |
+LL | #[doc(alias = "
+ | _______________^
+LL | | ")]
+ | |_^
+
+error: '\t' character isn't allowed in `#[doc(alias = "...")]`
+ --> $DIR/check-doc-alias-attr.rs:13:15
+ |
+LL | #[doc(alias = "\t")]
+ | ^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+ --> $DIR/check-doc-alias-attr.rs:14:15
+ |
+LL | #[doc(alias = " hello")]
+ | ^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+ --> $DIR/check-doc-alias-attr.rs:15:15
+ |
+LL | #[doc(alias = "hello ")]
+ | ^^^^^^^^
+
+error: `#[doc(alias = "...")]` attribute cannot have empty value
+ --> $DIR/check-doc-alias-attr.rs:16:15
+ |
+LL | #[doc(alias = "")]
+ | ^^
+
+error: `#[doc(alias("a"))]` expects string literals
+ --> $DIR/check-doc-alias-attr.rs:19:13
+ |
+LL | #[doc(alias(0))]
+ | ^
+
+error: '"' character isn't allowed in `#[doc(alias("..."))]`
+ --> $DIR/check-doc-alias-attr.rs:20:13
+ |
+LL | #[doc(alias("\""))]
+ | ^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias("..."))]`
+ --> $DIR/check-doc-alias-attr.rs:21:13
+ |
+LL | #[doc(alias("\n"))]
+ | ^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias("..."))]`
+ --> $DIR/check-doc-alias-attr.rs:22:13
+ |
+LL | #[doc(alias("
+ | _____________^
+LL | | "))]
+ | |_^
+
+error: '\t' character isn't allowed in `#[doc(alias("..."))]`
+ --> $DIR/check-doc-alias-attr.rs:24:13
+ |
+LL | #[doc(alias("\t"))]
+ | ^^^^
+
+error: `#[doc(alias("..."))]` cannot start or end with ' '
+ --> $DIR/check-doc-alias-attr.rs:25:13
+ |
+LL | #[doc(alias(" hello"))]
+ | ^^^^^^^^
+
+error: `#[doc(alias("..."))]` cannot start or end with ' '
+ --> $DIR/check-doc-alias-attr.rs:26:13
+ |
+LL | #[doc(alias("hello "))]
+ | ^^^^^^^^
+
+error: `#[doc(alias("..."))]` attribute cannot have empty value
+ --> $DIR/check-doc-alias-attr.rs:27:13
+ |
+LL | #[doc(alias(""))]
+ | ^^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/test/rustdoc-ui/check-fail.rs b/src/test/rustdoc-ui/check-fail.rs
new file mode 100644
index 000000000..2355d6a3d
--- /dev/null
+++ b/src/test/rustdoc-ui/check-fail.rs
@@ -0,0 +1,21 @@
+// compile-flags: -Z unstable-options --check
+
+#![deny(missing_docs)]
+#![deny(rustdoc::all)]
+
+//! ```rust,testharness
+//~^ ERROR
+//! let x = 12;
+//! ```
+
+pub fn foo() {}
+//~^ ERROR
+//~^^ ERROR
+
+/// hello
+//~^ ERROR
+///
+/// ```rust,testharness
+/// let x = 12;
+/// ```
+pub fn bar() {}
diff --git a/src/test/rustdoc-ui/check-fail.stderr b/src/test/rustdoc-ui/check-fail.stderr
new file mode 100644
index 000000000..5d46dc720
--- /dev/null
+++ b/src/test/rustdoc-ui/check-fail.stderr
@@ -0,0 +1,52 @@
+error: missing documentation for a function
+ --> $DIR/check-fail.rs:11:1
+ |
+LL | pub fn foo() {}
+ | ^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/check-fail.rs:3:9
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/check-fail.rs:11:1
+ |
+LL | pub fn foo() {}
+ | ^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/check-fail.rs:4:9
+ |
+LL | #![deny(rustdoc::all)]
+ | ^^^^^^^^^^^^
+ = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]`
+
+error: unknown attribute `testharness`. Did you mean `test_harness`?
+ --> $DIR/check-fail.rs:6:1
+ |
+LL | / //! ```rust,testharness
+LL | |
+LL | | //! let x = 12;
+LL | | //! ```
+ | |_______^
+ |
+ = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc::all)]`
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: unknown attribute `testharness`. Did you mean `test_harness`?
+ --> $DIR/check-fail.rs:15:1
+ |
+LL | / /// hello
+LL | |
+LL | | ///
+LL | | /// ```rust,testharness
+LL | | /// let x = 12;
+LL | | /// ```
+ | |_______^
+ |
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/check.rs b/src/test/rustdoc-ui/check.rs
new file mode 100644
index 000000000..2b44ba24b
--- /dev/null
+++ b/src/test/rustdoc-ui/check.rs
@@ -0,0 +1,12 @@
+// check-pass
+// compile-flags: -Z unstable-options --check
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+
+#![warn(missing_docs)]
+//~^ WARN
+//~^^ WARN
+#![warn(rustdoc::all)]
+
+pub fn foo() {}
+//~^ WARN
+//~^^ WARN
diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr
new file mode 100644
index 000000000..06e607fbe
--- /dev/null
+++ b/src/test/rustdoc-ui/check.stderr
@@ -0,0 +1,55 @@
+warning: missing documentation for the crate
+ --> $DIR/check.rs:5:1
+ |
+LL | / #![warn(missing_docs)]
+LL | |
+LL | |
+LL | | #![warn(rustdoc::all)]
+LL | |
+LL | | pub fn foo() {}
+ | |_______________^
+ |
+note: the lint level is defined here
+ --> $DIR/check.rs:5:9
+ |
+LL | #![warn(missing_docs)]
+ | ^^^^^^^^^^^^
+
+warning: missing documentation for a function
+ --> $DIR/check.rs:10:1
+ |
+LL | pub fn foo() {}
+ | ^^^^^^^^^^^^
+
+warning: no documentation found for this crate's top-level module
+ |
+note: the lint level is defined here
+ --> $DIR/check.rs:8:9
+ |
+LL | #![warn(rustdoc::all)]
+ | ^^^^^^^^^^^^
+ = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
+ = help: The following guide may be of use:
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
+
+warning: missing code example in this documentation
+ --> $DIR/check.rs:5:1
+ |
+LL | / #![warn(missing_docs)]
+LL | |
+LL | |
+LL | | #![warn(rustdoc::all)]
+LL | |
+LL | | pub fn foo() {}
+ | |_______________^
+ |
+ = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
+
+warning: missing code example in this documentation
+ --> $DIR/check.rs:10:1
+ |
+LL | pub fn foo() {}
+ | ^^^^^^^^^^^^^^^
+
+warning: 5 warnings emitted
+
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.args b/src/test/rustdoc-ui/commandline-argfile-badutf8.args
new file mode 100644
index 000000000..c070b0c24
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.args
@@ -0,0 +1,2 @@
+--cfg
+unbroken \ No newline at end of file
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.rs b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs
new file mode 100644
index 000000000..e2984e3ca
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs
@@ -0,0 +1,12 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr
new file mode 100644
index 000000000..9af6fc0a5
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr
@@ -0,0 +1,2 @@
+error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args
+
diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.rs b/src/test/rustdoc-ui/commandline-argfile-missing.rs
new file mode 100644
index 000000000..5a6465bd0
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile-missing.rs
@@ -0,0 +1,14 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
+// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.stderr b/src/test/rustdoc-ui/commandline-argfile-missing.stderr
new file mode 100644
index 000000000..179ad8310
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile-missing.stderr
@@ -0,0 +1,2 @@
+error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)
+
diff --git a/src/test/rustdoc-ui/commandline-argfile.args b/src/test/rustdoc-ui/commandline-argfile.args
new file mode 100644
index 000000000..972938bf6
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile.args
@@ -0,0 +1,2 @@
+--cfg
+unbroken \ No newline at end of file
diff --git a/src/test/rustdoc-ui/commandline-argfile.rs b/src/test/rustdoc-ui/commandline-argfile.rs
new file mode 100644
index 000000000..cc8c8722c
--- /dev/null
+++ b/src/test/rustdoc-ui/commandline-argfile.rs
@@ -0,0 +1,13 @@
+// Check to see if we can get parameters from an @argsfile file
+//
+// check-pass
+// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args
+
+#[cfg(not(cmdline_set))]
+compile_error!("cmdline_set not set");
+
+#[cfg(not(unbroken))]
+compile_error!("unbroken not set");
+
+fn main() {
+}
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
new file mode 100644
index 000000000..c771c09da
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
@@ -0,0 +1,41 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! Make sure to have some docs on your crate root
+
+#[allow(missing_docs)]
+pub mod mod_foo {
+ pub struct Bar;
+}
+
+/// This is a struct with an `#[allow(missing_docs)]`
+pub struct AllowTheMissingDocs {
+ #[allow(missing_docs)]
+ pub empty_str: String,
+
+ /// This has
+ #[allow(missing_docs)]
+ /// but also has documentation comments
+ pub hello: usize,
+
+ /// The doc id just to create a boilerplate comment
+ pub doc_id: Vec<u8>,
+}
+
+/// A function that has a documentation
+pub fn this_is_func() {}
+
+#[allow(missing_docs)]
+pub struct DemoStruct {
+ something: usize,
+}
+
+#[allow(missing_docs)]
+pub mod bar {
+ #[warn(missing_docs)]
+ pub struct Bar { //~ WARN
+ pub f: u32, //~ WARN
+ }
+
+ pub struct NeedsNoDocs;
+}
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
new file mode 100644
index 000000000..3d5b512d1
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
@@ -0,0 +1,20 @@
+warning: missing documentation for a struct
+ --> $DIR/allow_missing_docs.rs:36:5
+ |
+LL | pub struct Bar {
+ | ^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/allow_missing_docs.rs:35:12
+ |
+LL | #[warn(missing_docs)]
+ | ^^^^^^^^^^^^
+
+warning: missing documentation for a struct field
+ --> $DIR/allow_missing_docs.rs:37:9
+ |
+LL | pub f: u32,
+ | ^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
new file mode 100644
index 000000000..17e8ee9e2
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...i/coverage/allow_missing_docs.rs | 5 | 71.4% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 5 | 71.4% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/basic.rs b/src/test/rustdoc-ui/coverage/basic.rs
new file mode 100644
index 000000000..6c26b751c
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/basic.rs
@@ -0,0 +1,50 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+#![feature(extern_types)]
+
+//! Make sure to have some docs on your crate root
+
+/// This struct is documented, but its fields are not.
+///
+/// However, one field is private, so it shouldn't show in the total.
+pub struct SomeStruct {
+ pub some_field: usize,
+ other_field: usize,
+}
+
+impl SomeStruct {
+ /// Method with docs
+ pub fn this_fn(&self) {}
+
+ // Method without docs
+ pub fn other_method(&self) {}
+}
+
+// struct without docs
+pub struct OtherStruct;
+
+// function with no docs
+pub fn some_fn() {}
+
+/// Function with docs
+pub fn other_fn() {}
+
+pub enum SomeEnum {
+ /// Some of these variants are documented...
+ VarOne,
+ /// ...but some of them are not.
+ VarTwo,
+ // (like this one)
+ VarThree,
+}
+
+/// There's a macro here, too
+#[macro_export]
+macro_rules! some_macro {
+ () => {};
+}
+
+extern "C" {
+ pub type ExternType;
+}
diff --git a/src/test/rustdoc-ui/coverage/basic.stdout b/src/test/rustdoc-ui/coverage/basic.stdout
new file mode 100644
index 000000000..3c602b3da
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/basic.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/basic.rs | 7 | 50.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 7 | 50.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.rs b/src/test/rustdoc-ui/coverage/doc-examples-json.rs
new file mode 100644
index 000000000..1da181379
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/doc-examples-json.rs
@@ -0,0 +1,13 @@
+// check-pass
+// compile-flags:-Z unstable-options --output-format json --show-coverage
+
+// This check ensures that only one doc example is counted since they're "optional" on
+// certain items.
+
+/// ```
+/// let x = 12;
+/// ```
+pub const Foo: u32 = 0;
+
+/// doc
+pub const Bar: u32 = 0;
diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.stdout b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout
new file mode 100644
index 000000000..92f585569
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout
@@ -0,0 +1 @@
+{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":2,"with_examples":1}}
diff --git a/src/test/rustdoc-ui/coverage/doc-examples.rs b/src/test/rustdoc-ui/coverage/doc-examples.rs
new file mode 100644
index 000000000..cd718f8a3
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/doc-examples.rs
@@ -0,0 +1,27 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! This test ensure that only rust code examples are counted.
+
+/// Doc
+///
+/// ```
+/// let x = 2;
+/// ```
+pub struct Foo;
+
+/// Doc
+///
+/// ```text
+/// yolo
+/// ```
+pub trait Bar {}
+
+/// Doc
+///
+/// ```ignore (just for the sake of this test)
+/// let x = 2;
+/// ```
+pub fn foo<T: Bar, D: ::std::fmt::Debug>(a: Foo, b: u32, c: T, d: D) -> u32 {
+ 0
+}
diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout
new file mode 100644
index 000000000..8188740f8
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 4 | 100.0% | 1 | 25.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/empty.rs b/src/test/rustdoc-ui/coverage/empty.rs
new file mode 100644
index 000000000..55a87e9d9
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/empty.rs
@@ -0,0 +1,4 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+// an empty crate still has one item to document: the crate root
diff --git a/src/test/rustdoc-ui/coverage/empty.stdout b/src/test/rustdoc-ui/coverage/empty.stdout
new file mode 100644
index 000000000..890a7d56e
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/empty.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/empty.rs | 0 | 0.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 0 | 0.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs
new file mode 100644
index 000000000..e9c165b19
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs
@@ -0,0 +1,37 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+// The point of this test is to ensure that the number of "documented" items
+// is higher than in `enum-tuple.rs`.
+
+//! (remember the crate root is still a module)
+
+/// so check out this enum here
+pub enum ThisEnum {
+ /// VarOne.
+ VarOne(
+ /// hello!
+ String,
+ ),
+ /// Var Two.
+ VarTwo(
+ /// Hello
+ String,
+ /// Bis repetita.
+ String,
+ ),
+}
+
+/// Struct.
+pub struct ThisStruct(
+ /// hello
+ u32,
+);
+
+/// Struct.
+pub struct ThisStruct2(
+ /// hello
+ u32,
+ /// Bis repetita.
+ u8,
+);
diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout
new file mode 100644
index 000000000..82c98f43f
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...overage/enum-tuple-documented.rs | 9 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 9 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.rs b/src/test/rustdoc-ui/coverage/enum-tuple.rs
new file mode 100644
index 000000000..5fb205450
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enum-tuple.rs
@@ -0,0 +1,18 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! (remember the crate root is still a module)
+
+/// so check out this enum here
+pub enum ThisEnum {
+ /// No need to document the field if there is only one in a tuple variant!
+ VarOne(String),
+ /// But if there is more than one... still fine!
+ VarTwo(String, String),
+}
+
+/// Struct.
+pub struct ThisStruct(u32);
+
+/// Struct.
+pub struct ThisStruct2(u32, u8);
diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.stdout b/src/test/rustdoc-ui/coverage/enum-tuple.stdout
new file mode 100644
index 000000000..a3377d59c
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enum-tuple.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...ustdoc-ui/coverage/enum-tuple.rs | 6 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 6 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/enums.rs b/src/test/rustdoc-ui/coverage/enums.rs
new file mode 100644
index 000000000..a4ae36d68
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enums.rs
@@ -0,0 +1,22 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! (remember the crate root is still a module)
+
+/// so check out this enum here
+pub enum ThisEnum {
+ /// this variant has some weird stuff going on
+ VarOne {
+ /// like, it has some named fields inside
+ field_one: usize,
+ // (these show up as struct fields)
+ field_two: usize,
+ },
+ /// here's another variant for you
+ VarTwo(String),
+ // but not all of them need to be documented as thoroughly
+ VarThree,
+}
+
+/// uninhabited enums? sure, let's throw one of those around
+pub enum OtherEnum {}
diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout
new file mode 100644
index 000000000..64c012c1f
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/enums.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 6 | 75.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/exotic.rs b/src/test/rustdoc-ui/coverage/exotic.rs
new file mode 100644
index 000000000..72b70d698
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/exotic.rs
@@ -0,0 +1,15 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+#![feature(rustdoc_internals)]
+
+//! the features only used in std also have entries in the table, so make sure those get pulled out
+//! properly as well
+
+/// woo, check it out, we can write our own primitive docs lol
+#[doc(primitive="unit")]
+mod prim_unit {}
+
+/// keywords? sure, pile them on
+#[doc(keyword="where")]
+mod where_keyword {}
diff --git a/src/test/rustdoc-ui/coverage/exotic.stdout b/src/test/rustdoc-ui/coverage/exotic.stdout
new file mode 100644
index 000000000..27798b813
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/exotic.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/exotic.rs | 3 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 3 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/html.rs b/src/test/rustdoc-ui/coverage/html.rs
new file mode 100644
index 000000000..181cb4c50
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/html.rs
@@ -0,0 +1,4 @@
+// compile-flags:-Z unstable-options --output-format html --show-coverage
+
+/// Foo
+pub struct Xo;
diff --git a/src/test/rustdoc-ui/coverage/html.stderr b/src/test/rustdoc-ui/coverage/html.stderr
new file mode 100644
index 000000000..adca375d4
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/html.stderr
@@ -0,0 +1,2 @@
+error: html output format isn't supported for the --show-coverage option
+
diff --git a/src/test/rustdoc-ui/coverage/json.rs b/src/test/rustdoc-ui/coverage/json.rs
new file mode 100644
index 000000000..a591cd5db
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/json.rs
@@ -0,0 +1,65 @@
+// check-pass
+// compile-flags:-Z unstable-options --output-format json --show-coverage
+
+pub mod foo {
+ /// Hello!
+ pub struct Foo;
+ /// Bar
+ pub enum Bar { A }
+}
+
+/// X
+pub struct X;
+
+/// Bar
+///
+/// ```
+/// let x = 12;
+/// ```
+pub mod bar {
+ /// bar
+ pub struct Bar;
+ /// X
+ pub enum X {
+ /// ```
+ /// let x = "should be ignored!";
+ /// ```
+ Y
+ }
+}
+
+/// yolo
+///
+/// ```text
+/// should not be counted as a code example!
+/// ```
+pub enum Yolo { X }
+
+impl Yolo {
+ /// ```
+ /// let x = "should be ignored!";
+ /// ```
+ pub const Const: u32 = 0;
+}
+
+pub struct Xo<T: Clone> {
+ /// ```
+ /// let x = "should be ignored!";
+ /// ```
+ x: T,
+}
+
+/// ```
+/// let x = "should be ignored!";
+/// ```
+pub static StaticFoo: u32 = 0;
+
+/// ```
+/// let x = "should be ignored!";
+/// ```
+pub const ConstFoo: u32 = 0;
+
+/// ```
+/// let x = "should be ignored!";
+/// ```
+pub type TypeFoo = u32;
diff --git a/src/test/rustdoc-ui/coverage/json.stdout b/src/test/rustdoc-ui/coverage/json.stdout
new file mode 100644
index 000000000..c2be73ce3
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/json.stdout
@@ -0,0 +1 @@
+{"$DIR/json.rs":{"total":17,"with_docs":12,"total_examples":15,"with_examples":6}}
diff --git a/src/test/rustdoc-ui/coverage/private.rs b/src/test/rustdoc-ui/coverage/private.rs
new file mode 100644
index 000000000..2a0271727
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/private.rs
@@ -0,0 +1,21 @@
+// compile-flags:-Z unstable-options --show-coverage --document-private-items
+// check-pass
+
+#![allow(unused)]
+
+//! when `--document-private-items` is passed, nothing is safe. everything must have docs or your
+//! score will suffer the consequences
+
+mod this_mod {
+ fn private_fn() {}
+}
+
+/// See, our public items have docs!
+pub struct SomeStruct {
+ /// Look, all perfectly documented!
+ pub field: usize,
+ other: usize,
+}
+
+/// Nothing shady going on here. Just a bunch of well-documented code. (cough)
+pub fn public_fn() {}
diff --git a/src/test/rustdoc-ui/coverage/private.stdout b/src/test/rustdoc-ui/coverage/private.stdout
new file mode 100644
index 000000000..37a0f5187
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/private.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...t/rustdoc-ui/coverage/private.rs | 4 | 57.1% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 4 | 57.1% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/statics-consts.rs b/src/test/rustdoc-ui/coverage/statics-consts.rs
new file mode 100644
index 000000000..5a35260fa
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/statics-consts.rs
@@ -0,0 +1,23 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! gotta make sure we can count statics and consts correctly, too
+
+/// static like electricity, right?
+pub static THIS_STATIC: usize = 0;
+
+/// (it's not electricity, is it)
+pub const THIS_CONST: usize = 1;
+
+/// associated consts show up separately, but let's throw them in as well
+pub trait SomeTrait {
+ /// just like that, yeah
+ const ASSOC_CONST: usize;
+}
+
+pub struct SomeStruct;
+
+impl SomeStruct {
+ /// wait, structs can have them too, can't forget those
+ pub const ASSOC_CONST: usize = 100;
+}
diff --git a/src/test/rustdoc-ui/coverage/statics-consts.stdout b/src/test/rustdoc-ui/coverage/statics-consts.stdout
new file mode 100644
index 000000000..dbea3a3ea
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/statics-consts.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...oc-ui/coverage/statics-consts.rs | 6 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 6 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/traits.rs b/src/test/rustdoc-ui/coverage/traits.rs
new file mode 100644
index 000000000..daa08ec25
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/traits.rs
@@ -0,0 +1,38 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+#![feature(trait_alias)]
+#![feature(type_alias_impl_trait)]
+
+/// look at this trait right here
+pub trait ThisTrait {
+ /// that's a trait all right
+ fn right_here(&self);
+
+ /// even the provided functions show up as trait methods
+ fn aww_yeah(&self) {}
+
+ /// gotta check those associated types, they're slippery
+ type SomeType;
+}
+
+/// so what happens if we take some struct...
+#[derive(Clone)]
+pub struct SomeStruct;
+
+/// ...and slap this trait on it?
+impl ThisTrait for SomeStruct {
+ /// nothing! trait impls are totally ignored in this calculation, sorry.
+ fn right_here(&self) {}
+
+ type SomeType = String;
+}
+
+/// but what about those aliases? i hear they're pretty exotic
+pub trait MyAlias = ThisTrait + Send + Sync;
+
+/// woah, getting all opaque in here
+pub type ThisExists = impl ThisTrait;
+
+/// why don't we get a little more concrete
+pub fn defines() -> ThisExists { SomeStruct {} }
diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout
new file mode 100644
index 000000000..5053d0209
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/traits.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File | Documented | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/traits.rs | 8 | 88.9% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total | 8 | 88.9% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs
new file mode 100644
index 000000000..09da124b1
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// [v2] //~ ERROR
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
new file mode 100644
index 000000000..67d9c3989
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `v2`
+ --> $DIR/deny-intra-link-resolution-failure.rs:3:6
+ |
+LL | /// [v2]
+ | ^^ no item named `v2` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/deny-intra-link-resolution-failure.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.rs b/src/test/rustdoc-ui/deny-missing-docs-crate.rs
new file mode 100644
index 000000000..b74eba3f6
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-missing-docs-crate.rs
@@ -0,0 +1,3 @@
+#![deny(missing_docs)] //~ ERROR
+
+pub struct Foo; //~ ERROR
diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
new file mode 100644
index 000000000..5025b0b0c
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
@@ -0,0 +1,22 @@
+error: missing documentation for the crate
+ --> $DIR/deny-missing-docs-crate.rs:1:1
+ |
+LL | / #![deny(missing_docs)]
+LL | |
+LL | | pub struct Foo;
+ | |_______________^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-missing-docs-crate.rs:1:9
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^
+
+error: missing documentation for a struct
+ --> $DIR/deny-missing-docs-crate.rs:3:1
+ |
+LL | pub struct Foo;
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.rs b/src/test/rustdoc-ui/deny-missing-docs-macro.rs
new file mode 100644
index 000000000..b1c125317
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-missing-docs-macro.rs
@@ -0,0 +1,8 @@
+//! foo
+
+#![deny(missing_docs)]
+
+#[macro_export]
+macro_rules! foo { //~ ERROR
+ () => {}
+}
diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr
new file mode 100644
index 000000000..0867b0818
--- /dev/null
+++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr
@@ -0,0 +1,14 @@
+error: missing documentation for a macro
+ --> $DIR/deny-missing-docs-macro.rs:6:1
+ |
+LL | macro_rules! foo {
+ | ^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-missing-docs-macro.rs:3:9
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/deprecated-attrs.rs b/src/test/rustdoc-ui/deprecated-attrs.rs
new file mode 100644
index 000000000..4f6a14fc2
--- /dev/null
+++ b/src/test/rustdoc-ui/deprecated-attrs.rs
@@ -0,0 +1,16 @@
+// check-pass
+// compile-flags: --passes unknown-pass
+// error-pattern: the `passes` flag no longer functions
+
+#![doc(no_default_passes)]
+//~^ WARNING attribute is deprecated
+//~| NOTE see issue #44136
+//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+#![doc(passes = "collapse-docs unindent-comments")]
+//~^ WARNING attribute is deprecated
+//~| NOTE see issue #44136
+//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+#![doc(plugins = "xxx")]
+//~^ WARNING attribute is deprecated
+//~| NOTE see issue #44136
+//~| WARNING no longer functions; see CVE
diff --git a/src/test/rustdoc-ui/deprecated-attrs.stderr b/src/test/rustdoc-ui/deprecated-attrs.stderr
new file mode 100644
index 000000000..45b20ce70
--- /dev/null
+++ b/src/test/rustdoc-ui/deprecated-attrs.stderr
@@ -0,0 +1,34 @@
+warning: the `passes` flag no longer functions
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+ = help: you may want to use --document-private-items
+
+warning: the `#![doc(no_default_passes)]` attribute is deprecated
+ --> $DIR/deprecated-attrs.rs:5:8
+ |
+LL | #![doc(no_default_passes)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+ = help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`
+
+warning: the `#![doc(passes = "...")]` attribute is deprecated
+ --> $DIR/deprecated-attrs.rs:9:8
+ |
+LL | #![doc(passes = "collapse-docs unindent-comments")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+ = help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]`
+
+warning: the `#![doc(plugins = "...")]` attribute is deprecated
+ --> $DIR/deprecated-attrs.rs:13:8
+ |
+LL | #![doc(plugins = "xxx")]
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+ = warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
+
+warning: 3 warnings emitted
+
diff --git a/src/test/rustdoc-ui/deref-generic.rs b/src/test/rustdoc-ui/deref-generic.rs
new file mode 100644
index 000000000..bc64beb1b
--- /dev/null
+++ b/src/test/rustdoc-ui/deref-generic.rs
@@ -0,0 +1,15 @@
+// check-pass
+// #81395: Fix ICE when recursing into Deref target only differing in type args
+
+pub struct Generic<T>(T);
+
+impl<'a> std::ops::Deref for Generic<&'a mut ()> {
+ type Target = Generic<&'a ()>;
+ fn deref(&self) -> &Self::Target {
+ unimplemented!()
+ }
+}
+
+impl<'a> Generic<&'a ()> {
+ pub fn some_method(&self) {}
+}
diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs
new file mode 100644
index 000000000..61961d5ec
--- /dev/null
+++ b/src/test/rustdoc-ui/diagnostic-width.rs
@@ -0,0 +1,5 @@
+// compile-flags: -Zunstable-options --diagnostic-width=10
+#![deny(rustdoc::bare_urls)]
+
+/// This is a long line that contains a http://link.com
+pub struct Foo; //~^ ERROR
diff --git a/src/test/rustdoc-ui/diagnostic-width.stderr b/src/test/rustdoc-ui/diagnostic-width.stderr
new file mode 100644
index 000000000..fed049d2b
--- /dev/null
+++ b/src/test/rustdoc-ui/diagnostic-width.stderr
@@ -0,0 +1,15 @@
+error: this URL is not a hyperlink
+ --> $DIR/diagnostic-width.rs:4:41
+ |
+LL | ... a http://link.com
+ | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>`
+ |
+note: the lint level is defined here
+ --> $DIR/diagnostic-width.rs:2:9
+ |
+LL | ...ny(rustdoc::bare_url...
+ | ^^^^^^^^^^^^^^^^^^
+ = note: bare URLs are not automatically turned into clickable links
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/display-output.rs b/src/test/rustdoc-ui/display-output.rs
new file mode 100644
index 000000000..ec27a9f6b
--- /dev/null
+++ b/src/test/rustdoc-ui/display-output.rs
@@ -0,0 +1,15 @@
+// Test that `--show-output` has an effect and `allow(unused)` can be overridden.
+
+// check-pass
+// edition:2018
+// compile-flags:--test --test-args=--show-output
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// #![warn(unused)]
+/// let x = 12;
+///
+/// fn foo(x: &dyn std::fmt::Display) {}
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/display-output.stdout b/src/test/rustdoc-ui/display-output.stdout
new file mode 100644
index 000000000..ad25d1ce5
--- /dev/null
+++ b/src/test/rustdoc-ui/display-output.stdout
@@ -0,0 +1,43 @@
+
+running 1 test
+test $DIR/display-output.rs - foo (line 9) ... ok
+
+successes:
+
+---- $DIR/display-output.rs - foo (line 9) stdout ----
+warning: unused variable: `x`
+ --> $DIR/display-output.rs:11:5
+ |
+LL | let x = 12;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `x`
+ --> $DIR/display-output.rs:13:8
+ |
+LL | fn foo(x: &dyn std::fmt::Display) {}
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+warning: function `foo` is never used
+ --> $DIR/display-output.rs:13:4
+ |
+LL | fn foo(x: &dyn std::fmt::Display) {}
+ | ^^^
+ |
+ = note: `#[warn(dead_code)]` implied by `#[warn(unused)]`
+
+warning: 3 warnings emitted
+
+
+
+successes:
+ $DIR/display-output.rs - foo (line 9)
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.rs b/src/test/rustdoc-ui/doc-alias-assoc-const.rs
new file mode 100644
index 000000000..d95324734
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-assoc-const.rs
@@ -0,0 +1,21 @@
+#![feature(trait_alias)]
+
+pub struct Foo;
+
+pub trait Bar {
+ const BAZ: u8;
+}
+
+impl Bar for Foo {
+ #[doc(alias = "CONST_BAZ")] //~ ERROR
+ const BAZ: u8 = 0;
+}
+
+impl Foo {
+ #[doc(alias = "CONST_FOO")] // ok!
+ pub const FOO: u8 = 0;
+
+ pub fn bar() -> u8 {
+ Self::FOO
+ }
+}
diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.stderr b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr
new file mode 100644
index 000000000..cbca40e13
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr
@@ -0,0 +1,8 @@
+error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block
+ --> $DIR/doc-alias-assoc-const.rs:10:11
+ |
+LL | #[doc(alias = "CONST_BAZ")]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.rs b/src/test/rustdoc-ui/doc-alias-crate-level.rs
new file mode 100644
index 000000000..70618ac01
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-crate-level.rs
@@ -0,0 +1,4 @@
+#![doc(alias = "crate-level-not-working")] //~ ERROR
+
+#[doc(alias = "shouldn't work!")] //~ ERROR
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.stderr b/src/test/rustdoc-ui/doc-alias-crate-level.stderr
new file mode 100644
index 000000000..fc8095e03
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-crate-level.stderr
@@ -0,0 +1,14 @@
+error: '\'' character isn't allowed in `#[doc(alias = "...")]`
+ --> $DIR/doc-alias-crate-level.rs:3:15
+ |
+LL | #[doc(alias = "shouldn't work!")]
+ | ^^^^^^^^^^^^^^^^^
+
+error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute
+ --> $DIR/doc-alias-crate-level.rs:1:8
+ |
+LL | #![doc(alias = "crate-level-not-working")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/doc-alias-same-name.rs b/src/test/rustdoc-ui/doc-alias-same-name.rs
new file mode 100644
index 000000000..da97c2676
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-same-name.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+
+#[doc(alias = "Foo")] //~ ERROR
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/doc-alias-same-name.stderr b/src/test/rustdoc-ui/doc-alias-same-name.stderr
new file mode 100644
index 000000000..5ba09a2ea
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-same-name.stderr
@@ -0,0 +1,8 @@
+error: `#[doc(alias = "...")]` is the same as the item's name
+ --> $DIR/doc-alias-same-name.rs:3:7
+ |
+LL | #[doc(alias = "Foo")]
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/doc-attr.rs b/src/test/rustdoc-ui/doc-attr.rs
new file mode 100644
index 000000000..980d1c0e2
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-attr.rs
@@ -0,0 +1,25 @@
+#![crate_type = "lib"]
+#![deny(warnings)]
+#![doc(as_ptr)]
+//~^ ERROR unknown `doc` attribute
+//~^^ WARN
+
+#[doc(as_ptr)]
+//~^ ERROR unknown `doc` attribute
+//~^^ WARN
+pub fn foo() {}
+
+#[doc(123)]
+//~^ ERROR invalid `doc` attribute
+//~| WARN
+#[doc("hello", "bar")]
+//~^ ERROR invalid `doc` attribute
+//~| WARN
+//~| ERROR invalid `doc` attribute
+//~| WARN
+#[doc(foo::bar, crate::bar::baz = "bye")]
+//~^ ERROR unknown `doc` attribute
+//~| WARN
+//~| ERROR unknown `doc` attribute
+//~| WARN
+fn bar() {}
diff --git a/src/test/rustdoc-ui/doc-attr.stderr b/src/test/rustdoc-ui/doc-attr.stderr
new file mode 100644
index 000000000..cc2494c92
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-attr.stderr
@@ -0,0 +1,71 @@
+error: unknown `doc` attribute `as_ptr`
+ --> $DIR/doc-attr.rs:7:7
+ |
+LL | #[doc(as_ptr)]
+ | ^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/doc-attr.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: invalid `doc` attribute
+ --> $DIR/doc-attr.rs:12:7
+ |
+LL | #[doc(123)]
+ | ^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: invalid `doc` attribute
+ --> $DIR/doc-attr.rs:15:7
+ |
+LL | #[doc("hello", "bar")]
+ | ^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: invalid `doc` attribute
+ --> $DIR/doc-attr.rs:15:16
+ |
+LL | #[doc("hello", "bar")]
+ | ^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: unknown `doc` attribute `foo::bar`
+ --> $DIR/doc-attr.rs:20:7
+ |
+LL | #[doc(foo::bar, crate::bar::baz = "bye")]
+ | ^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: unknown `doc` attribute `crate::bar::baz`
+ --> $DIR/doc-attr.rs:20:17
+ |
+LL | #[doc(foo::bar, crate::bar::baz = "bye")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: unknown `doc` attribute `as_ptr`
+ --> $DIR/doc-attr.rs:3:8
+ |
+LL | #![doc(as_ptr)]
+ | ^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/rustdoc-ui/doc-cfg.rs b/src/test/rustdoc-ui/doc-cfg.rs
new file mode 100644
index 000000000..354d76bc3
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-cfg.rs
@@ -0,0 +1,9 @@
+#![feature(doc_cfg)]
+
+#[doc(cfg(), cfg(foo, bar))]
+//~^ ERROR
+//~^^ ERROR
+#[doc(cfg(foo), cfg(bar))] // ok!
+#[doc(cfg())] //~ ERROR
+#[doc(cfg(foo, bar))] //~ ERROR
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr
new file mode 100644
index 000000000..b379f6feb
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-cfg.stderr
@@ -0,0 +1,26 @@
+error: `cfg` predicate is not specified
+ --> $DIR/doc-cfg.rs:3:7
+ |
+LL | #[doc(cfg(), cfg(foo, bar))]
+ | ^^^^^
+
+error: multiple `cfg` predicates are specified
+ --> $DIR/doc-cfg.rs:3:23
+ |
+LL | #[doc(cfg(), cfg(foo, bar))]
+ | ^^^
+
+error: `cfg` predicate is not specified
+ --> $DIR/doc-cfg.rs:7:7
+ |
+LL | #[doc(cfg())]
+ | ^^^^^
+
+error: multiple `cfg` predicates are specified
+ --> $DIR/doc-cfg.rs:8:16
+ |
+LL | #[doc(cfg(foo, bar))]
+ | ^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs
new file mode 100644
index 000000000..97259f782
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs
@@ -0,0 +1,11 @@
+// Regression test for #97440: Multiline inner attribute triggers ICE during doctest
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// check-pass
+
+//! ```rust
+//! #![deny(
+//! unused_parens,
+//! )]
+//! ```
diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout
new file mode 100644
index 000000000..e47edbd2a
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/doc-comment-multi-line-attr.rs - (line 7) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs
new file mode 100644
index 000000000..b2a8133c9
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs
@@ -0,0 +1,12 @@
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// check-pass
+
+/// ```
+/// # #![cfg_attr(not(dox), deny(missing_abi,
+/// # non_ascii_idents))]
+///
+/// pub struct Bar;
+/// ```
+pub struct Bar;
diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout
new file mode 100644
index 000000000..bf3521e4f
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/doc-comment-multi-line-cfg-attr.rs - Bar (line 6) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doc-include-suggestion.rs b/src/test/rustdoc-ui/doc-include-suggestion.rs
new file mode 100644
index 000000000..0c0100735
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-include-suggestion.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#[doc(include = "external-cross-doc.md")]
+//~^ WARNING unknown `doc` attribute `include`
+//~| HELP use `doc = include_str!` instead
+// FIXME(#85497): make this a deny instead so it's more clear what's happening
+//~| NOTE on by default
+//~| WARNING previously accepted
+//~| NOTE see issue #82730
+pub struct NeedMoreDocs;
diff --git a/src/test/rustdoc-ui/doc-include-suggestion.stderr b/src/test/rustdoc-ui/doc-include-suggestion.stderr
new file mode 100644
index 000000000..870b7efa2
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-include-suggestion.stderr
@@ -0,0 +1,12 @@
+warning: unknown `doc` attribute `include`
+ --> $DIR/doc-include-suggestion.rs:3:7
+ |
+LL | #[doc(include = "external-cross-doc.md")]
+ | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
+ |
+ = note: `#[warn(invalid_doc_attributes)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/doc-spotlight.fixed b/src/test/rustdoc-ui/doc-spotlight.fixed
new file mode 100644
index 000000000..4b58778ea
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-spotlight.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+#![deny(warnings)]
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+//~^ ERROR unknown `doc` attribute `spotlight`
+//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+trait MyTrait {}
diff --git a/src/test/rustdoc-ui/doc-spotlight.rs b/src/test/rustdoc-ui/doc-spotlight.rs
new file mode 100644
index 000000000..16e387245
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-spotlight.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+#![deny(warnings)]
+#![feature(doc_notable_trait)]
+
+#[doc(spotlight)]
+//~^ ERROR unknown `doc` attribute `spotlight`
+//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+trait MyTrait {}
diff --git a/src/test/rustdoc-ui/doc-spotlight.stderr b/src/test/rustdoc-ui/doc-spotlight.stderr
new file mode 100644
index 000000000..8e7831139
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-spotlight.stderr
@@ -0,0 +1,19 @@
+error: unknown `doc` attribute `spotlight`
+ --> $DIR/doc-spotlight.rs:5:7
+ |
+LL | #[doc(spotlight)]
+ | ^^^^^^^^^ help: use `notable_trait` instead
+ |
+note: the lint level is defined here
+ --> $DIR/doc-spotlight.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: `doc(spotlight)` was renamed to `doc(notable_trait)`
+ = note: `doc(spotlight)` is now a no-op
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/doc-test-attr-pass.rs b/src/test/rustdoc-ui/doc-test-attr-pass.rs
new file mode 100644
index 000000000..12608f244
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-attr-pass.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+#![crate_type = "lib"]
+#![deny(invalid_doc_attributes)]
+#![doc(test(no_crate_inject))]
+#![doc(test(attr(deny(warnings))))]
+
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/doc-test-attr.rs b/src/test/rustdoc-ui/doc-test-attr.rs
new file mode 100644
index 000000000..46178ad86
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-attr.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+#![deny(invalid_doc_attributes)]
+
+#![doc(test)]
+//~^ ERROR `#[doc(test(...)]` takes a list of attributes
+//~^^ WARN this was previously accepted by the compiler
+#![doc(test = "hello")]
+//~^ ERROR `#[doc(test(...)]` takes a list of attributes
+//~^^ WARN this was previously accepted by the compiler
+#![doc(test(a))]
+//~^ ERROR unknown `doc(test)` attribute `a`
+//~^^ WARN this was previously accepted by the compiler
+
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/doc-test-attr.stderr b/src/test/rustdoc-ui/doc-test-attr.stderr
new file mode 100644
index 000000000..7f5e2d6bc
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-attr.stderr
@@ -0,0 +1,34 @@
+error: `#[doc(test(...)]` takes a list of attributes
+ --> $DIR/doc-test-attr.rs:4:8
+ |
+LL | #![doc(test)]
+ | ^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/doc-test-attr.rs:2:9
+ |
+LL | #![deny(invalid_doc_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: `#[doc(test(...)]` takes a list of attributes
+ --> $DIR/doc-test-attr.rs:7:8
+ |
+LL | #![doc(test = "hello")]
+ | ^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: unknown `doc(test)` attribute `a`
+ --> $DIR/doc-test-attr.rs:10:13
+ |
+LL | #![doc(test(a))]
+ | ^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.rs b/src/test/rustdoc-ui/doc-test-doctest-feature.rs
new file mode 100644
index 000000000..0b79aaece
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-doctest-feature.rs
@@ -0,0 +1,13 @@
+// check-pass
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// Make sure `cfg(doctest)` is set when finding doctests but not inside
+// the doctests.
+
+/// ```
+/// assert!(!cfg!(doctest));
+/// ```
+#[cfg(doctest)]
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.stdout b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout
new file mode 100644
index 000000000..d7de1f105
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/doc-test-doctest-feature.rs - Foo (line 9) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs
new file mode 100644
index 000000000..bf334c67e
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs
@@ -0,0 +1,15 @@
+// check-pass
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+#![feature(doc_cfg)]
+
+// Make sure `cfg(doc)` is set when finding doctests but not inside the doctests.
+
+/// ```
+/// #![feature(doc_cfg)]
+/// assert!(!cfg!(doc));
+/// ```
+#[cfg(doc)]
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout
new file mode 100644
index 000000000..5b07fc4c8
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/doc-test-rustdoc-feature.rs - Foo (line 10) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs
new file mode 100644
index 000000000..315fca195
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-without-codeblock.rs
@@ -0,0 +1,22 @@
+#![deny(rustdoc::missing_doc_code_examples)] //~ ERROR missing code example in this documentation
+
+/// Some docs.
+//~^ ERROR missing code example in this documentation
+pub struct Foo;
+
+/// And then, the princess died.
+//~^ ERROR missing code example in this documentation
+pub mod foo {
+ /// Or maybe not because she saved herself!
+ //~^ ERROR missing code example in this documentation
+ pub fn bar() {}
+}
+
+// This impl is here to ensure the lint isn't emitted for foreign traits implementations.
+impl std::ops::Neg for Foo {
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ Self
+ }
+}
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
new file mode 100644
index 000000000..1c1380441
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -0,0 +1,38 @@
+error: missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:1:1
+ |
+LL | / #![deny(rustdoc::missing_doc_code_examples)]
+LL | |
+LL | | /// Some docs.
+LL | |
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> $DIR/doc-without-codeblock.rs:1:9
+ |
+LL | #![deny(rustdoc::missing_doc_code_examples)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:7:1
+ |
+LL | /// And then, the princess died.
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:10:5
+ |
+LL | /// Or maybe not because she saved herself!
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:3:1
+ |
+LL | /// Some docs.
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs
new file mode 100644
index 000000000..b0787be97
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-edition.rs
@@ -0,0 +1,16 @@
+// edition:2021
+
+#![deny(rustdoc::invalid_rust_codeblocks)]
+//~^ NOTE lint level is defined here
+
+// By default, rustdoc should use the edition of the crate.
+//! ```
+//! foo'b'
+//! ```
+//~^^^ ERROR could not parse
+//~| NOTE prefix `foo` is unknown
+
+// Rustdoc should respect `edition2018` when highlighting syntax.
+//! ```edition2018
+//! foo'b'
+//! ```
diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr
new file mode 100644
index 000000000..1643d6053
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-edition.stderr
@@ -0,0 +1,22 @@
+error: could not parse code block as Rust code
+ --> $DIR/doctest-edition.rs:7:5
+ |
+LL | //! ```
+ | _____^
+LL | | //! foo'b'
+LL | | //! ```
+ | |_______^
+ |
+note: the lint level is defined here
+ --> $DIR/doctest-edition.rs:3:9
+ |
+LL | #![deny(rustdoc::invalid_rust_codeblocks)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: error from rustc: prefix `foo` is unknown
+help: mark blocks that do not contain Rust code as text
+ |
+LL | //! ```text
+ | ++++
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs
new file mode 100644
index 000000000..a30472ac5
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs
@@ -0,0 +1,10 @@
+// compile-flags:--test --test-args=--test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// check-pass
+
+/// ```
+/// #![deprecated(since = "5.2", note = "foo was rarely used. \
+/// Users should instead use bar")]
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout
new file mode 100644
index 000000000..07a4f657d
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/doctest-multiline-crate-attribute.rs - f (line 6) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs
new file mode 100644
index 000000000..2670fa572
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-output.rs
@@ -0,0 +1,28 @@
+// edition:2018
+// aux-build:extern_macros.rs
+// compile-flags:--test --test-args=--test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// check-pass
+
+//! ```
+//! assert_eq!(1 + 1, 2);
+//! ```
+
+extern crate extern_macros as macros;
+
+use macros::attrs_on_struct;
+
+pub mod foo {
+
+ /// ```
+ /// assert_eq!(1 + 1, 2);
+ /// ```
+ pub fn bar() {}
+}
+
+attrs_on_struct! {
+ /// ```
+ /// assert!(true);
+ /// ```
+}
diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout
new file mode 100644
index 000000000..35b0e366f
--- /dev/null
+++ b/src/test/rustdoc-ui/doctest-output.stdout
@@ -0,0 +1,8 @@
+
+running 3 tests
+test $DIR/doctest-output.rs - (line 8) ... ok
+test $DIR/doctest-output.rs - ExpandedStruct (line 24) ... ok
+test $DIR/doctest-output.rs - foo::bar (line 18) ... ok
+
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md
new file mode 100644
index 000000000..1176a4a8c
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md
@@ -0,0 +1,7 @@
+Each of these needs to be in a separate file,
+because the `delay_span_bug` ICE in rustdoc won't be triggerred
+if even a single other error was emitted.
+
+However, conceptually they are all testing basically the same thing.
+See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128
+for more details.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs
new file mode 100644
index 000000000..cda53bff0
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs
@@ -0,0 +1,7 @@
+// edition:2018
+// check-pass
+
+/// Should compile fine
+pub async fn a() -> u32 {
+ error::_in::async_fn()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
new file mode 100644
index 000000000..f1fd85bb2
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
@@ -0,0 +1,5 @@
+// check-pass
+// manually desugared version of an `async fn` (but with a closure instead of a generator)
+pub fn a() -> impl Fn() -> u32 {
+ || content::doesnt::matter()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs b/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs
new file mode 100644
index 000000000..ed62f0208
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs
@@ -0,0 +1,23 @@
+// check-pass
+// edition:2018
+trait ValidTrait {}
+
+/// This has docs
+pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> {
+ loop {}
+}
+
+pub trait Trait<const N: usize> {}
+impl Trait<1> for u8 {}
+impl Trait<2> for u8 {}
+impl<const N: usize> Trait<N> for [u8; N] {}
+
+/// This also has docs
+pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
+ loop {}
+}
+
+/// Document all the functions
+pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
+ loop {}
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
new file mode 100644
index 000000000..dcec379d4
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
@@ -0,0 +1,7 @@
+// check-pass
+trait ValidTrait {}
+
+/// This has docs
+pub fn f() -> impl ValidTrait {
+ Vec::<DoesNotExist>::new()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
new file mode 100644
index 000000000..b935b0832
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
@@ -0,0 +1,6 @@
+// check-pass
+pub trait ValidTrait {}
+/// This returns impl trait
+pub fn g() -> impl ValidTrait {
+ (|| error::_in::impl_trait::alias::nested::closure())()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
new file mode 100644
index 000000000..701126f87
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
@@ -0,0 +1,6 @@
+// check-pass
+pub trait ValidTrait {}
+/// This returns impl trait
+pub fn g() -> impl ValidTrait {
+ error::_in::impl_trait()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
new file mode 100644
index 000000000..248575d35
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
@@ -0,0 +1,28 @@
+// edition:2018
+// check-pass
+
+mod windows {
+ pub trait WinFoo {
+ fn foo(&self) {}
+ }
+
+ impl WinFoo for () {}
+}
+
+#[cfg(any(windows, doc))]
+use windows::*;
+
+mod unix {
+ pub trait UnixFoo {
+ fn foo(&self) {}
+ }
+
+ impl UnixFoo for () {}
+}
+
+#[cfg(any(unix, doc))]
+use unix::*;
+
+async fn bar() {
+ ().foo()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
new file mode 100644
index 000000000..31dd786cb
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
@@ -0,0 +1,10 @@
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait ValidTrait {}
+type ImplTrait = impl ValidTrait;
+
+/// This returns impl trait, but using a type alias
+pub fn h() -> ImplTrait {
+ (|| error::_in::impl_trait::alias::nested::closure())()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
new file mode 100644
index 000000000..c18a024af
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
@@ -0,0 +1,10 @@
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait ValidTrait {}
+type ImplTrait = impl ValidTrait;
+
+/// This returns impl trait, but using a type alias
+pub fn h() -> ImplTrait {
+ error::_in::impl_trait::alias()
+}
diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs
new file mode 100644
index 000000000..0901ac364
--- /dev/null
+++ b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs
@@ -0,0 +1,157 @@
+// check-pass
+#![feature(lint_reasons)]
+
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files as well.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+
+#![expect(rustdoc::missing_crate_level_docs)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+
+mod rustc_ok {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42.0;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5.0 => {}
+ 6.0 => {}
+ _ => {}
+ }
+ }
+}
+
+mod rustc_warn {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5 => {}
+ 6 => {}
+ _ => {}
+ }
+ }
+}
+
+pub mod rustdoc_ok {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`Nonexistent`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// http://example.org
+ pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// I want to link to [`bar`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// <h1></h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// <http://example.org>
+ pub fn baz() {}
+}
+
+mod clippy_ok {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ b = a;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".bytes().nth(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 42
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+
+ if a && b || a {}
+ }
+}
+
+mod clippy_warn {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".as_bytes().get(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 33
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+ let c = false;
+
+ if a && b || c {}
+ }
+}
+
+fn main() {
+ rustc_warn::rustc_lints();
+}
diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr
new file mode 100644
index 000000000..efc5f349f
--- /dev/null
+++ b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr
@@ -0,0 +1,28 @@
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:16:11
+ |
+LL | #![expect(rustdoc::missing_crate_level_docs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:71:14
+ |
+LL | #[expect(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:76:14
+ |
+LL | #[expect(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:81:14
+ |
+LL | #[expect(rustdoc::bare_urls)]
+ | ^^^^^^^^^^^^^^^^^^
+
+warning: 4 warnings emitted
+
diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs
new file mode 100644
index 000000000..6f2ff5d70
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs
@@ -0,0 +1,12 @@
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+/// ```compile_fail
+/// println!("Hello");
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
new file mode 100644
index 000000000..af3a90a74
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
@@ -0,0 +1,14 @@
+
+running 1 test
+test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-compile-fail.rs - Foo (line 9) stdout ----
+Test compiled successfully, but it's marked `compile_fail`.
+
+failures:
+ $DIR/failed-doctest-compile-fail.rs - Foo (line 9)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs
new file mode 100644
index 000000000..16d737106
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs
@@ -0,0 +1,18 @@
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+/// <https://github.com/rust-lang/rust/issues/91014>
+///
+/// ```rust
+/// struct S {}; // unexpected semicolon after struct def
+///
+/// fn main() {
+/// assert_eq!(0, 1);
+/// }
+/// ```
+mod m {}
diff --git a/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout
new file mode 100644
index 000000000..61468b6c7
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout
@@ -0,0 +1,24 @@
+
+running 1 test
+test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) stdout ----
+error: expected item, found `;`
+ --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12
+ |
+LL | struct S {}; // unexpected semicolon after struct def
+ | ^ help: remove this semicolon
+ |
+ = help: braced struct declarations are not followed by a semicolon
+
+error: aborting due to previous error
+
+Couldn't compile the test.
+
+failures:
+ $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs
new file mode 100644
index 000000000..57b70b478
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs
@@ -0,0 +1,12 @@
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+/// ```compile_fail,E0004
+/// let x: () = 5i32;
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
new file mode 100644
index 000000000..bacbb47b5
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
@@ -0,0 +1,25 @@
+
+running 1 test
+test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-missing-codes.rs - Foo (line 9) stdout ----
+error[E0308]: mismatched types
+ --> $DIR/failed-doctest-missing-codes.rs:10:13
+ |
+LL | let x: () = 5i32;
+ | -- ^^^^ expected `()`, found `i32`
+ | |
+ | expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
+Some expected error codes were not found: ["E0004"]
+
+failures:
+ $DIR/failed-doctest-missing-codes.rs - Foo (line 9)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.rs b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
new file mode 100644
index 000000000..4cd9993d8
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
@@ -0,0 +1,28 @@
+// only-windows
+// There's a parallel generic version of this test for non-windows platforms.
+
+// Issue #51162: A failed doctest was not printing its stdout/stderr
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test --test-args --test-threads=1
+// rustc-env:RUST_BACKTRACE=0
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+// doctest fails at runtime
+/// ```
+/// println!("stdout 1");
+/// eprintln!("stderr 1");
+/// println!("stdout 2");
+/// eprintln!("stderr 2");
+/// panic!("oh no");
+/// ```
+pub struct SomeStruct;
+
+// doctest fails at compile time
+/// ```
+/// no
+/// ```
+pub struct OtherStruct;
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.stdout b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
new file mode 100644
index 000000000..6c147054d
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
@@ -0,0 +1,39 @@
+
+running 2 tests
+test $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) stdout ----
+error[E0425]: cannot find value `no` in this scope
+ --> $DIR/failed-doctest-output-windows.rs:26:1
+ |
+LL | no
+ | ^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
+Couldn't compile the test.
+---- $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit code: 101).
+
+stdout:
+stdout 1
+stdout 2
+
+stderr:
+stderr 1
+stderr 2
+thread 'main' panicked at 'oh no', $DIR/failed-doctest-output-windows.rs:7:1
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+
+failures:
+ $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25)
+ $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15)
+
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs
new file mode 100644
index 000000000..42de954d0
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output.rs
@@ -0,0 +1,28 @@
+// ignore-windows
+// There's a parallel version of this test for Windows.
+
+// Issue #51162: A failed doctest was not printing its stdout/stderr
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test --test-args --test-threads=1
+// rustc-env:RUST_BACKTRACE=0
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+// doctest fails at runtime
+/// ```
+/// println!("stdout 1");
+/// eprintln!("stderr 1");
+/// println!("stdout 2");
+/// eprintln!("stderr 2");
+/// panic!("oh no");
+/// ```
+pub struct SomeStruct;
+
+// doctest fails at compile time
+/// ```
+/// no
+/// ```
+pub struct OtherStruct;
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
new file mode 100644
index 000000000..630198a56
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -0,0 +1,39 @@
+
+running 2 tests
+test $DIR/failed-doctest-output.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 15) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 25) stdout ----
+error[E0425]: cannot find value `no` in this scope
+ --> $DIR/failed-doctest-output.rs:26:1
+ |
+LL | no
+ | ^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
+Couldn't compile the test.
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit status: 101).
+
+stdout:
+stdout 1
+stdout 2
+
+stderr:
+stderr 1
+stderr 2
+thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+
+failures:
+ $DIR/failed-doctest-output.rs - OtherStruct (line 25)
+ $DIR/failed-doctest-output.rs - SomeStruct (line 15)
+
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.rs b/src/test/rustdoc-ui/failed-doctest-should-panic.rs
new file mode 100644
index 000000000..2b8bb3168
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-should-panic.rs
@@ -0,0 +1,12 @@
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+/// ```should_panic
+/// println!("Hello, world!");
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout
new file mode 100644
index 000000000..57a20092a
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout
@@ -0,0 +1,14 @@
+
+running 1 test
+test $DIR/failed-doctest-should-panic.rs - Foo (line 9) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-should-panic.rs - Foo (line 9) stdout ----
+Test executable succeeded, but it's marked `should_panic`.
+
+failures:
+ $DIR/failed-doctest-should-panic.rs - Foo (line 9)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs
new file mode 100644
index 000000000..17812018b
--- /dev/null
+++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs
@@ -0,0 +1,7 @@
+#![doc(cfg_hide(test))]
+//~^ ERROR `#[doc(cfg_hide)]` is experimental
+
+#[cfg(not(test))]
+pub fn public_fn() {}
+#[cfg(test)]
+pub fn internal_use_only() {}
diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr
new file mode 100644
index 000000000..ba42c7bbb
--- /dev/null
+++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr
@@ -0,0 +1,14 @@
+error[E0658]: `#[doc(cfg_hide)]` is experimental
+ --> $DIR/feature-gate-doc_cfg_hide.rs:1:1
+ |
+LL | #![doc(cfg_hide(test))]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
+ = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs
new file mode 100644
index 000000000..87620d74e
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used on nightly.
+
+// compile-flags: --generate-link-to-definition
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr
new file mode 100644
index 000000000..a8ddf91bc
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `generate-link-to-definition`
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs
new file mode 100644
index 000000000..8f4f561b4
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --output-format json
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr
new file mode 100644
index 000000000..4c8c607e7
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs
new file mode 100644
index 000000000..da5142087
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --show-coverage
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr
new file mode 100644
index 000000000..4c8c607e7
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc-ui/ignore-block-help.rs b/src/test/rustdoc-ui/ignore-block-help.rs
new file mode 100644
index 000000000..86f6a2868
--- /dev/null
+++ b/src/test/rustdoc-ui/ignore-block-help.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+/// ```ignore (to-prevent-tidy-error)
+/// let heart = '❤️';
+/// ```
+//~^^^ WARNING could not parse code block
+//~| NOTE on by default
+//~| NOTE character literal may only contain one codepoint
+//~| HELP `ignore` code blocks require valid Rust code
+pub struct X;
diff --git a/src/test/rustdoc-ui/ignore-block-help.stderr b/src/test/rustdoc-ui/ignore-block-help.stderr
new file mode 100644
index 000000000..9c02ff11d
--- /dev/null
+++ b/src/test/rustdoc-ui/ignore-block-help.stderr
@@ -0,0 +1,19 @@
+warning: could not parse code block as Rust code
+ --> $DIR/ignore-block-help.rs:3:5
+ |
+LL | /// ```ignore (to-prevent-tidy-error)
+ | _____^
+LL | | /// let heart = '❤️';
+LL | | /// ```
+ | |_______^
+ |
+ = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
+help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text
+ --> $DIR/ignore-block-help.rs:3:5
+ |
+LL | /// ```ignore (to-prevent-tidy-error)
+ | ^^^
+ = note: error from rustc: character literal may only contain one codepoint
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs
new file mode 100644
index 000000000..a927f6bd7
--- /dev/null
+++ b/src/test/rustdoc-ui/impl-fn-nesting.rs
@@ -0,0 +1,49 @@
+// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve.
+// See https://github.com/rust-lang/rust/pull/73566
+pub struct ValidType;
+pub trait ValidTrait {}
+pub trait NeedsBody {
+ type Item;
+ fn f();
+}
+
+/// This function has docs
+pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+//~^ ERROR cannot find trait `UnknownBound` in this scope
+//~| ERROR cannot find type `UnknownType` in this scope
+ impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait`
+ impl<T: UnknownBound> UnknownTrait for T {}
+ //~^ ERROR cannot find trait `UnknownBound` in this scope
+ //~| ERROR cannot find trait `UnknownTrait` in this scope
+ impl ValidTrait for UnknownType {}
+ //~^ ERROR cannot find type `UnknownType` in this scope
+ impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+ //~^ ERROR cannot find trait `UnknownBound` in this scope
+
+ /// This impl has documentation
+ impl NeedsBody for ValidType {
+ type Item = UnknownType;
+ //~^ ERROR cannot find type `UnknownType` in this scope
+
+ /// This function has documentation
+ fn f() {
+ <UnknownTypeShouldBeIgnored>::a();
+ content::shouldnt::matter();
+ unknown_macro!();
+ //~^ ERROR cannot find macro `unknown_macro` in this scope
+
+ /// This is documentation for a macro
+ macro_rules! can_define_macros_here_too {
+ () => {
+ this::content::should::also::be::ignored()
+ }
+ }
+ can_define_macros_here_too!();
+
+ /// This also is documented.
+ pub fn doubly_nested(c: UnknownType) {
+ //~^ ERROR cannot find type `UnknownType` in this scope
+ }
+ }
+ }
+}
diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr
new file mode 100644
index 000000000..608749af8
--- /dev/null
+++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr
@@ -0,0 +1,66 @@
+error: cannot find macro `unknown_macro` in this scope
+ --> $DIR/impl-fn-nesting.rs:32:13
+ |
+LL | unknown_macro!();
+ | ^^^^^^^^^^^^^
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+ --> $DIR/impl-fn-nesting.rs:11:13
+ |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+ | ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+ --> $DIR/impl-fn-nesting.rs:11:30
+ |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+ | ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+ --> $DIR/impl-fn-nesting.rs:14:10
+ |
+LL | impl UnknownTrait for ValidType {}
+ | ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+ --> $DIR/impl-fn-nesting.rs:15:27
+ |
+LL | impl<T: UnknownBound> UnknownTrait for T {}
+ | ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+ --> $DIR/impl-fn-nesting.rs:15:13
+ |
+LL | impl<T: UnknownBound> UnknownTrait for T {}
+ | ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+ --> $DIR/impl-fn-nesting.rs:18:25
+ |
+LL | impl ValidTrait for UnknownType {}
+ | ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+ --> $DIR/impl-fn-nesting.rs:20:53
+ |
+LL | impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+ | ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+ --> $DIR/impl-fn-nesting.rs:25:21
+ |
+LL | type Item = UnknownType;
+ | ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+ --> $DIR/impl-fn-nesting.rs:44:37
+ |
+LL | pub fn doubly_nested(c: UnknownType) {
+ | ^^^^^^^^^^^ not found in this scope
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0405, E0412.
+For more information about an error, try `rustc --explain E0405`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
new file mode 100644
index 000000000..2319de556
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
@@ -0,0 +1,15 @@
+// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
+// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
+// edition:2018
+
+pub async fn f() -> impl std::fmt::Debug {
+ #[derive(Debug)]
+ enum E {
+ //~^ ERROR recursive type `f::{closure#0}::E` has infinite size
+ This(E),
+ Unit,
+ }
+ E::Unit
+}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
new file mode 100644
index 000000000..aa39d26fe
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `DEF_ID` has infinite size
+ --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
+ |
+LL | enum E {
+ | ^^^^^^ recursive type has infinite size
+LL |
+LL | This(E),
+ | - recursive without indirection
+ |
+help: insert some indirection (e.g., a `DEF_ID` representable
+ |
+LL | This(Box<E>),
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `DEF_ID`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
new file mode 100644
index 000000000..b3a7ee563
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
@@ -0,0 +1,7 @@
+fn f() -> impl Sized {
+ enum E {
+ //~^ ERROR recursive type `f::E` has infinite size
+ V(E),
+ }
+ unimplemented!()
+}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
new file mode 100644
index 000000000..009bedec5
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `f::E` has infinite size
+ --> $DIR/infinite-recursive-type-impl-trait.rs:2:5
+ |
+LL | enum E {
+ | ^^^^^^ recursive type has infinite size
+LL |
+LL | V(E),
+ | - recursive without indirection
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `f::E` representable
+ |
+LL | V(Box<E>),
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs
new file mode 100644
index 000000000..32793fc4f
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type.rs
@@ -0,0 +1,4 @@
+enum E {
+//~^ ERROR recursive type `E` has infinite size
+ V(E),
+}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr
new file mode 100644
index 000000000..b33aba446
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `E` has infinite size
+ --> $DIR/infinite-recursive-type.rs:1:1
+ |
+LL | enum E {
+ | ^^^^^^ recursive type has infinite size
+LL |
+LL | V(E),
+ | - recursive without indirection
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable
+ |
+LL | V(Box<E>),
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.rs b/src/test/rustdoc-ui/intra-doc/alias-ice.rs
new file mode 100644
index 000000000..51922caeb
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/alias-ice.rs
@@ -0,0 +1,6 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub type TypeAlias = usize;
+
+/// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+pub fn some_public_item() {}
diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.stderr b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr
new file mode 100644
index 000000000..5e7ffeeb8
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr
@@ -0,0 +1,14 @@
+error: unresolved link to `TypeAlias::hoge`
+ --> $DIR/alias-ice.rs:5:30
+ |
+LL | /// [broken cross-reference](TypeAlias::hoge)
+ | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge`
+ |
+note: the lint level is defined here
+ --> $DIR/alias-ice.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.rs b/src/test/rustdoc-ui/intra-doc/ambiguity.rs
new file mode 100644
index 000000000..1f3dc722e
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/ambiguity.rs
@@ -0,0 +1,40 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+pub fn ambiguous() {}
+
+pub struct ambiguous {}
+
+#[macro_export]
+macro_rules! multi_conflict { () => {} }
+
+#[allow(non_camel_case_types)]
+pub struct multi_conflict {}
+
+pub fn multi_conflict() {}
+
+pub mod type_and_value {}
+
+pub const type_and_value: i32 = 0;
+
+pub mod foo {
+ pub enum bar {}
+
+ pub fn bar() {}
+}
+
+/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous`
+///
+/// [ambiguous] is ambiguous. //~ERROR ambiguous
+///
+/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+///
+/// Ambiguous [type_and_value]. //~ERROR type_and_value
+///
+/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
+pub struct Docs {}
+
+/// [true] //~ ERROR `true` is both a module and a builtin type
+/// [primitive@true]
+pub mod r#true {}
diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.stderr b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr
new file mode 100644
index 000000000..7974796e4
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr
@@ -0,0 +1,101 @@
+error: `true` is both a module and a builtin type
+ --> $DIR/ambiguity.rs:38:6
+ |
+LL | /// [true]
+ | ^^^^ ambiguous link
+ |
+note: the lint level is defined here
+ --> $DIR/ambiguity.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// [mod@true]
+ | ++++
+help: to link to the builtin type, prefix with `prim@`
+ |
+LL | /// [prim@true]
+ | +++++
+
+error: `ambiguous` is both a struct and a function
+ --> $DIR/ambiguity.rs:27:7
+ |
+LL | /// [`ambiguous`] is ambiguous.
+ | ^^^^^^^^^ ambiguous link
+ |
+help: to link to the struct, prefix with `struct@`
+ |
+LL | /// [`struct@ambiguous`] is ambiguous.
+ | +++++++
+help: to link to the function, add parentheses
+ |
+LL | /// [`ambiguous()`] is ambiguous.
+ | ++
+
+error: `ambiguous` is both a struct and a function
+ --> $DIR/ambiguity.rs:29:6
+ |
+LL | /// [ambiguous] is ambiguous.
+ | ^^^^^^^^^ ambiguous link
+ |
+help: to link to the struct, prefix with `struct@`
+ |
+LL | /// [struct@ambiguous] is ambiguous.
+ | +++++++
+help: to link to the function, add parentheses
+ |
+LL | /// [ambiguous()] is ambiguous.
+ | ++
+
+error: `multi_conflict` is a struct, a function, and a macro
+ --> $DIR/ambiguity.rs:31:7
+ |
+LL | /// [`multi_conflict`] is a three-way conflict.
+ | ^^^^^^^^^^^^^^ ambiguous link
+ |
+help: to link to the struct, prefix with `struct@`
+ |
+LL | /// [`struct@multi_conflict`] is a three-way conflict.
+ | +++++++
+help: to link to the function, add parentheses
+ |
+LL | /// [`multi_conflict()`] is a three-way conflict.
+ | ++
+help: to link to the macro, add an exclamation mark
+ |
+LL | /// [`multi_conflict!`] is a three-way conflict.
+ | +
+
+error: `type_and_value` is both a module and a constant
+ --> $DIR/ambiguity.rs:33:16
+ |
+LL | /// Ambiguous [type_and_value].
+ | ^^^^^^^^^^^^^^ ambiguous link
+ |
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// Ambiguous [mod@type_and_value].
+ | ++++
+help: to link to the constant, prefix with `const@`
+ |
+LL | /// Ambiguous [const@type_and_value].
+ | ++++++
+
+error: `foo::bar` is both an enum and a function
+ --> $DIR/ambiguity.rs:35:43
+ |
+LL | /// Ambiguous non-implied shortcut link [`foo::bar`].
+ | ^^^^^^^^ ambiguous link
+ |
+help: to link to the enum, prefix with `enum@`
+ |
+LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`].
+ | +++++
+help: to link to the function, add parentheses
+ |
+LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
+ | ++
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/anchors.rs b/src/test/rustdoc-ui/intra-doc/anchors.rs
new file mode 100644
index 000000000..34e11c7c7
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/anchors.rs
@@ -0,0 +1,39 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// A few tests on anchors.
+
+/// Hello people.
+///
+/// You can anchors? Here's one!
+///
+/// # hola
+///
+/// Isn't it amazing?
+pub struct Foo {
+ pub f: u8,
+}
+
+pub enum Enum {
+ A,
+ B,
+}
+
+/// Have you heard about stuff?
+///
+/// Like [Foo#hola].
+///
+/// Or maybe [Foo::f#hola].
+//~^ ERROR `Foo::f#hola` contains an anchor
+pub fn foo() {}
+
+/// Empty.
+///
+/// Another anchor error: [hello#people#!].
+//~^ ERROR `hello#people#!` contains multiple anchors
+pub fn bar() {}
+
+/// Empty?
+///
+/// Damn enum's variants: [Enum::A#whatever].
+//~^ ERROR `Enum::A#whatever` contains an anchor
+pub fn enum_link() {}
diff --git a/src/test/rustdoc-ui/intra-doc/anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr
new file mode 100644
index 000000000..0d226b277
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr
@@ -0,0 +1,32 @@
+error: `Foo::f#hola` contains an anchor, but links to fields are already anchored
+ --> $DIR/anchors.rs:25:15
+ |
+LL | /// Or maybe [Foo::f#hola].
+ | ^^^^^^-----
+ | |
+ | invalid anchor
+ |
+note: the lint level is defined here
+ --> $DIR/anchors.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `hello#people#!` contains multiple anchors
+ --> $DIR/anchors.rs:31:28
+ |
+LL | /// Another anchor error: [hello#people#!].
+ | ^^^^^^^^^^^^--
+ | |
+ | invalid anchor
+
+error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored
+ --> $DIR/anchors.rs:37:28
+ |
+LL | /// Damn enum's variants: [Enum::A#whatever].
+ | ^^^^^^^---------
+ | |
+ | invalid anchor
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/assoc-field.rs b/src/test/rustdoc-ui/intra-doc/assoc-field.rs
new file mode 100644
index 000000000..e18404e44
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/assoc-field.rs
@@ -0,0 +1,26 @@
+// Traits in scope are collected for doc links in field attributes.
+
+// check-pass
+// aux-build: assoc-field-dep.rs
+
+extern crate assoc_field_dep;
+pub use assoc_field_dep::*;
+
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod mod1 {
+ pub struct Fields {
+ /// [crate::Struct::clone]
+ pub field: u8,
+ }
+}
+
+pub mod mod2 {
+ pub enum Fields {
+ V {
+ /// [crate::Struct::clone]
+ field: u8,
+ },
+ }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs b/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs
new file mode 100644
index 000000000..b4ce3443c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs
@@ -0,0 +1,19 @@
+// Traits in scope are collected for doc links in both outer and inner module attributes.
+
+// check-pass
+// aux-build: assoc-mod-inner-outer-dep.rs
+
+extern crate assoc_mod_inner_outer_dep;
+pub use assoc_mod_inner_outer_dep::*;
+
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod outer1 {
+ /// [crate::Struct::clone]
+ pub mod inner {}
+}
+
+pub mod outer2 {
+ //! [crate::Struct::clone]
+}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs
new file mode 100644
index 000000000..cfb24fc2c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs
@@ -0,0 +1,18 @@
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod dep_mod1 {
+ pub struct Fields {
+ /// [crate::Struct::clone]
+ pub field: u8,
+ }
+}
+
+pub mod dep_mod2 {
+ pub enum Fields {
+ V {
+ /// [crate::Struct::clone]
+ field: u8,
+ },
+ }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs
new file mode 100644
index 000000000..7a11a1657
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs
@@ -0,0 +1,11 @@
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod dep_outer1 {
+ /// [crate::Struct::clone]
+ pub mod inner {}
+}
+
+pub mod dep_outer2 {
+ //! [crate::Struct::clone]
+}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs
new file mode 100644
index 000000000..31a8310d4
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs
@@ -0,0 +1,4 @@
+#![crate_name = "intra_doc_broken"]
+
+/// [not_found]
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs
new file mode 100644
index 000000000..0a3dc57f1
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs
@@ -0,0 +1,4 @@
+#![feature(intra_doc_pointers)]
+#![crate_name = "inner"]
+/// Link to [some pointer](*const::to_raw_parts)
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs
new file mode 100644
index 000000000..5c4a01ee3
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![crate_name="some_macros"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ item // This doesn't erase the spans.
+}
+
+#[proc_macro_attribute]
+pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ // Make a new `TokenStream` to erase the spans:
+ let mut out: TokenStream = TokenStream::new();
+ out.extend(item);
+ out
+}
diff --git a/src/test/rustdoc-ui/intra-doc/broken-reexport.rs b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs
new file mode 100644
index 000000000..862faa50b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs
@@ -0,0 +1,8 @@
+// aux-build:intra-doc-broken.rs
+// check-pass
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate intra_doc_broken;
+
+pub use intra_doc_broken::foo;
diff --git a/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs
new file mode 100644
index 000000000..ceecfa681
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs
@@ -0,0 +1,5 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// [crate::DoesNotExist]
+//~^ ERROR unresolved link to `crate::DoesNotExist`
+pub struct Item;
diff --git a/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr
new file mode 100644
index 000000000..a69b1c52a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr
@@ -0,0 +1,14 @@
+error: unresolved link to `crate::DoesNotExist`
+ --> $DIR/crate-nonexistent.rs:3:6
+ |
+LL | /// [crate::DoesNotExist]
+ | ^^^^^^^^^^^^^^^^^^^ no item named `DoesNotExist` in module `crate_nonexistent`
+ |
+note: the lint level is defined here
+ --> $DIR/crate-nonexistent.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
new file mode 100644
index 000000000..2d6656611
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
@@ -0,0 +1,81 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+//~^ NOTE lint level is defined
+pub enum S {}
+fn S() {}
+
+#[macro_export]
+macro_rules! m {
+ () => {};
+}
+
+static s: usize = 0;
+const c: usize = 0;
+
+trait T {}
+
+/// Link to [struct@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP prefix with `enum@`
+
+/// Link to [mod@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP prefix with `enum@`
+
+/// Link to [union@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP prefix with `enum@`
+
+/// Link to [trait@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP prefix with `enum@`
+
+/// Link to [struct@T]
+//~^ ERROR incompatible link kind for `T`
+//~| NOTE this link resolved
+//~| HELP prefix with `trait@`
+
+/// Link to [derive@m]
+//~^ ERROR incompatible link kind for `m`
+//~| NOTE this link resolved
+//~| HELP add an exclamation mark
+
+/// Link to [m()]
+//~^ ERROR unresolved link to `m`
+//~| NOTE this link resolves to the macro `m`
+//~| HELP add an exclamation mark
+/// and to [m!()]
+
+/// Link to [const@s]
+//~^ ERROR incompatible link kind for `s`
+//~| NOTE this link resolved
+//~| HELP prefix with `static@`
+
+/// Link to [static@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP prefix with `const@`
+
+/// Link to [fn@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP prefix with `const@`
+
+/// Link to [c()]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP prefix with `const@`
+
+/// Link to [const@f]
+//~^ ERROR incompatible link kind for `f`
+//~| NOTE this link resolved
+//~| HELP add parentheses
+
+/// Link to [fn@std]
+//~^ ERROR unresolved link to `std`
+//~| NOTE this link resolves to the crate `std`
+//~| HELP to link to the crate, prefix with `mod@`
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
new file mode 100644
index 000000000..ee35749ce
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
@@ -0,0 +1,153 @@
+error: incompatible link kind for `S`
+ --> $DIR/disambiguator-mismatch.rs:16:14
+ |
+LL | /// Link to [struct@S]
+ | ^^^^^^^^ this link resolved to an enum, which is not a struct
+ |
+note: the lint level is defined here
+ --> $DIR/disambiguator-mismatch.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the enum, prefix with `enum@`
+ |
+LL | /// Link to [enum@S]
+ | ~~~~~
+
+error: incompatible link kind for `S`
+ --> $DIR/disambiguator-mismatch.rs:21:14
+ |
+LL | /// Link to [mod@S]
+ | ^^^^^ this link resolved to an enum, which is not a module
+ |
+help: to link to the enum, prefix with `enum@`
+ |
+LL | /// Link to [enum@S]
+ | ~~~~~
+
+error: incompatible link kind for `S`
+ --> $DIR/disambiguator-mismatch.rs:26:14
+ |
+LL | /// Link to [union@S]
+ | ^^^^^^^ this link resolved to an enum, which is not a union
+ |
+help: to link to the enum, prefix with `enum@`
+ |
+LL | /// Link to [enum@S]
+ | ~~~~~
+
+error: incompatible link kind for `S`
+ --> $DIR/disambiguator-mismatch.rs:31:14
+ |
+LL | /// Link to [trait@S]
+ | ^^^^^^^ this link resolved to an enum, which is not a trait
+ |
+help: to link to the enum, prefix with `enum@`
+ |
+LL | /// Link to [enum@S]
+ | ~~~~~
+
+error: incompatible link kind for `T`
+ --> $DIR/disambiguator-mismatch.rs:36:14
+ |
+LL | /// Link to [struct@T]
+ | ^^^^^^^^ this link resolved to a trait, which is not a struct
+ |
+help: to link to the trait, prefix with `trait@`
+ |
+LL | /// Link to [trait@T]
+ | ~~~~~~
+
+error: incompatible link kind for `m`
+ --> $DIR/disambiguator-mismatch.rs:41:14
+ |
+LL | /// Link to [derive@m]
+ | ^^^^^^^^ this link resolved to a macro, which is not a derive macro
+ |
+help: to link to the macro, add an exclamation mark
+ |
+LL - /// Link to [derive@m]
+LL + /// Link to [m!]
+ |
+
+error: unresolved link to `m`
+ --> $DIR/disambiguator-mismatch.rs:46:14
+ |
+LL | /// Link to [m()]
+ | ^^^ this link resolves to the macro `m`, which is not in the value namespace
+ |
+help: to link to the macro, add an exclamation mark
+ |
+LL | /// Link to [m!()]
+ | +
+
+error: incompatible link kind for `s`
+ --> $DIR/disambiguator-mismatch.rs:52:14
+ |
+LL | /// Link to [const@s]
+ | ^^^^^^^ this link resolved to a static, which is not a constant
+ |
+help: to link to the static, prefix with `static@`
+ |
+LL | /// Link to [static@s]
+ | ~~~~~~~
+
+error: incompatible link kind for `c`
+ --> $DIR/disambiguator-mismatch.rs:57:14
+ |
+LL | /// Link to [static@c]
+ | ^^^^^^^^ this link resolved to a constant, which is not a static
+ |
+help: to link to the constant, prefix with `const@`
+ |
+LL | /// Link to [const@c]
+ | ~~~~~~
+
+error: incompatible link kind for `c`
+ --> $DIR/disambiguator-mismatch.rs:62:14
+ |
+LL | /// Link to [fn@c]
+ | ^^^^ this link resolved to a constant, which is not a function
+ |
+help: to link to the constant, prefix with `const@`
+ |
+LL | /// Link to [const@c]
+ | ~~~~~~
+
+error: incompatible link kind for `c`
+ --> $DIR/disambiguator-mismatch.rs:67:14
+ |
+LL | /// Link to [c()]
+ | ^^^ this link resolved to a constant, which is not a function
+ |
+help: to link to the constant, prefix with `const@`
+ |
+LL - /// Link to [c()]
+LL + /// Link to [const@c]
+ |
+
+error: incompatible link kind for `f`
+ --> $DIR/disambiguator-mismatch.rs:72:14
+ |
+LL | /// Link to [const@f]
+ | ^^^^^^^ this link resolved to a function, which is not a constant
+ |
+help: to link to the function, add parentheses
+ |
+LL - /// Link to [const@f]
+LL + /// Link to [f()]
+ |
+
+error: unresolved link to `std`
+ --> $DIR/disambiguator-mismatch.rs:77:14
+ |
+LL | /// Link to [fn@std]
+ | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
+ |
+help: to link to the crate, prefix with `mod@`
+ |
+LL | /// Link to [mod@std]
+ | ~~~~
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/double-anchor.rs b/src/test/rustdoc-ui/intra-doc/double-anchor.rs
new file mode 100644
index 000000000..a01211c4f
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/double-anchor.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+// regression test for #73264
+// should only give one error
+/// docs [label][with#anchor#error]
+//~^ WARNING multiple anchors
+pub struct S;
diff --git a/src/test/rustdoc-ui/intra-doc/double-anchor.stderr b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr
new file mode 100644
index 000000000..6addb010e
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr
@@ -0,0 +1,12 @@
+warning: `with#anchor#error` contains multiple anchors
+ --> $DIR/double-anchor.rs:5:18
+ |
+LL | /// docs [label][with#anchor#error]
+ | ^^^^^^^^^^^------
+ | |
+ | invalid anchor
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
new file mode 100644
index 000000000..7a5156e81
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
@@ -0,0 +1,7 @@
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+// check-pass
+#![deny(warnings)]
+
+//! Email me at <hello@localhost>.
+
+//! This should *not* warn: <hello@example.com>.
diff --git a/src/test/rustdoc-ui/intra-doc/errors.rs b/src/test/rustdoc-ui/intra-doc/errors.rs
new file mode 100644
index 000000000..b29f7c29b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/errors.rs
@@ -0,0 +1,105 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+//~^ NOTE lint level is defined
+
+// FIXME: this should say that it was skipped (maybe an allowed by default lint?)
+/// [invalid intra-doc syntax!!]
+
+/// [path::to::nonexistent::module]
+//~^ ERROR unresolved link
+//~| NOTE no item named `path` in scope
+
+/// [path::to::nonexistent::macro!]
+//~^ ERROR unresolved link
+//~| NOTE no item named `path` in scope
+
+/// [type@path::to::nonexistent::type]
+//~^ ERROR unresolved link
+//~| NOTE no item named `path` in scope
+
+/// [std::io::not::here]
+//~^ ERROR unresolved link
+//~| NOTE no item named `not` in module `io`
+
+/// [type@std::io::not::here]
+//~^ ERROR unresolved link
+//~| NOTE no item named `not` in module `io`
+
+/// [std::io::Error::x]
+//~^ ERROR unresolved link
+//~| NOTE the struct `Error` has no field
+
+/// [std::io::ErrorKind::x]
+//~^ ERROR unresolved link
+//~| NOTE the enum `ErrorKind` has no variant
+
+/// [f::A]
+//~^ ERROR unresolved link
+//~| NOTE `f` is a function, not a module
+
+/// [f::A!]
+//~^ ERROR unresolved link
+//~| NOTE `f` is a function, not a module
+
+/// [S::A]
+//~^ ERROR unresolved link
+//~| NOTE struct `S` has no field or associated item
+
+/// [S::fmt]
+//~^ ERROR unresolved link
+//~| NOTE struct `S` has no field or associated item
+
+/// [E::D]
+//~^ ERROR unresolved link
+//~| NOTE enum `E` has no variant or associated item
+
+/// [u8::not_found]
+//~^ ERROR unresolved link
+//~| NOTE the builtin type `u8` has no associated item named `not_found`
+
+/// [std::primitive::u8::not_found]
+//~^ ERROR unresolved link
+//~| NOTE the builtin type `u8` has no associated item named `not_found`
+
+/// [type@Vec::into_iter]
+//~^ ERROR unresolved link
+//~| HELP to link to the associated function, add parentheses
+//~| NOTE this link resolves to the associated function `into_iter`
+
+/// [S!]
+//~^ ERROR unresolved link
+//~| HELP to link to the struct, prefix with `struct@`
+//~| NOTE this link resolves to the struct `S`
+pub fn f() {}
+#[derive(Debug)]
+pub struct S;
+
+pub enum E { A, B, C }
+
+/// [type@S::h]
+//~^ ERROR unresolved link
+//~| HELP to link to the associated function
+//~| NOTE not in the type namespace
+impl S {
+ pub fn h() {}
+}
+
+/// [type@T::g]
+//~^ ERROR unresolved link
+//~| HELP to link to the associated function
+//~| NOTE not in the type namespace
+
+/// [T::h!]
+//~^ ERROR unresolved link
+//~| NOTE `T` has no macro named `h`
+pub trait T {
+ fn g() {}
+}
+
+/// [m()]
+//~^ ERROR unresolved link
+//~| HELP to link to the macro
+//~| NOTE not in the value namespace
+#[macro_export]
+macro_rules! m {
+ () => {};
+}
diff --git a/src/test/rustdoc-ui/intra-doc/errors.stderr b/src/test/rustdoc-ui/intra-doc/errors.stderr
new file mode 100644
index 000000000..9a1896fb0
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/errors.stderr
@@ -0,0 +1,157 @@
+error: unresolved link to `path::to::nonexistent::module`
+ --> $DIR/errors.rs:7:6
+ |
+LL | /// [path::to::nonexistent::module]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/errors.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `path::to::nonexistent::macro`
+ --> $DIR/errors.rs:11:6
+ |
+LL | /// [path::to::nonexistent::macro!]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
+
+error: unresolved link to `path::to::nonexistent::type`
+ --> $DIR/errors.rs:15:6
+ |
+LL | /// [type@path::to::nonexistent::type]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
+
+error: unresolved link to `std::io::not::here`
+ --> $DIR/errors.rs:19:6
+ |
+LL | /// [std::io::not::here]
+ | ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
+
+error: unresolved link to `std::io::not::here`
+ --> $DIR/errors.rs:23:6
+ |
+LL | /// [type@std::io::not::here]
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
+
+error: unresolved link to `std::io::Error::x`
+ --> $DIR/errors.rs:27:6
+ |
+LL | /// [std::io::Error::x]
+ | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x`
+
+error: unresolved link to `std::io::ErrorKind::x`
+ --> $DIR/errors.rs:31:6
+ |
+LL | /// [std::io::ErrorKind::x]
+ | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x`
+
+error: unresolved link to `f::A`
+ --> $DIR/errors.rs:35:6
+ |
+LL | /// [f::A]
+ | ^^^^ `f` is a function, not a module or type, and cannot have associated items
+
+error: unresolved link to `f::A`
+ --> $DIR/errors.rs:39:6
+ |
+LL | /// [f::A!]
+ | ^^^^^ `f` is a function, not a module or type, and cannot have associated items
+
+error: unresolved link to `S::A`
+ --> $DIR/errors.rs:43:6
+ |
+LL | /// [S::A]
+ | ^^^^ the struct `S` has no field or associated item named `A`
+
+error: unresolved link to `S::fmt`
+ --> $DIR/errors.rs:47:6
+ |
+LL | /// [S::fmt]
+ | ^^^^^^ the struct `S` has no field or associated item named `fmt`
+
+error: unresolved link to `E::D`
+ --> $DIR/errors.rs:51:6
+ |
+LL | /// [E::D]
+ | ^^^^ the enum `E` has no variant or associated item named `D`
+
+error: unresolved link to `u8::not_found`
+ --> $DIR/errors.rs:55:6
+ |
+LL | /// [u8::not_found]
+ | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
+
+error: unresolved link to `std::primitive::u8::not_found`
+ --> $DIR/errors.rs:59:6
+ |
+LL | /// [std::primitive::u8::not_found]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
+
+error: unresolved link to `Vec::into_iter`
+ --> $DIR/errors.rs:63:6
+ |
+LL | /// [type@Vec::into_iter]
+ | ^^^^^^^^^^^^^^^^^^^ this link resolves to the associated function `into_iter`, which is not in the type namespace
+ |
+help: to link to the associated function, add parentheses
+ |
+LL - /// [type@Vec::into_iter]
+LL + /// [Vec::into_iter()]
+ |
+
+error: unresolved link to `S`
+ --> $DIR/errors.rs:68:6
+ |
+LL | /// [S!]
+ | ^^ this link resolves to the struct `S`, which is not in the macro namespace
+ |
+help: to link to the struct, prefix with `struct@`
+ |
+LL - /// [S!]
+LL + /// [struct@S]
+ |
+
+error: unresolved link to `S::h`
+ --> $DIR/errors.rs:78:6
+ |
+LL | /// [type@S::h]
+ | ^^^^^^^^^ this link resolves to the associated function `h`, which is not in the type namespace
+ |
+help: to link to the associated function, add parentheses
+ |
+LL - /// [type@S::h]
+LL + /// [S::h()]
+ |
+
+error: unresolved link to `T::g`
+ --> $DIR/errors.rs:86:6
+ |
+LL | /// [type@T::g]
+ | ^^^^^^^^^ this link resolves to the associated function `g`, which is not in the type namespace
+ |
+help: to link to the associated function, add parentheses
+ |
+LL - /// [type@T::g]
+LL + /// [T::g()]
+ |
+
+error: unresolved link to `T::h`
+ --> $DIR/errors.rs:91:6
+ |
+LL | /// [T::h!]
+ | ^^^^^ the trait `T` has no macro named `h`
+
+error: unresolved link to `m`
+ --> $DIR/errors.rs:98:6
+ |
+LL | /// [m()]
+ | ^^^ this link resolves to the macro `m`, which is not in the value namespace
+ |
+help: to link to the macro, add an exclamation mark
+ |
+LL | /// [m!()]
+ | +
+
+error: aborting due to 20 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs
new file mode 100644
index 000000000..438c56aa5
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs
@@ -0,0 +1,26 @@
+// check-pass
+// aux-crate:dep1=dep1.rs
+// aux-crate:dep2=dep2.rs
+// aux-crate:dep3=dep3.rs
+// aux-crate:dep4=dep4.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Trait {
+ /// [dep1]
+ type Item;
+}
+
+pub struct S {
+ /// [dep2]
+ pub x: usize,
+}
+
+extern "C" {
+ /// [dep3]
+ pub fn printf();
+}
+
+pub enum E {
+ /// [dep4]
+ A
+}
diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs
new file mode 100644
index 000000000..3cfac942c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs
@@ -0,0 +1,6 @@
+//! [pointer::add]
+//~^ ERROR: experimental
+//! [pointer::wrapping_add]
+//~^ ERROR: experimental
+//! [pointer] // This is explicitly allowed
+//! [reference] // This is explicitly allowed
diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr
new file mode 100644
index 000000000..2c946ed48
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr
@@ -0,0 +1,23 @@
+error[E0658]: linking to associated items of raw pointers is experimental
+ --> $DIR/feature-gate-intra-doc-pointers.rs:1:6
+ |
+LL | //! [pointer::add]
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information
+ = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable
+ = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does
+
+error[E0658]: linking to associated items of raw pointers is experimental
+ --> $DIR/feature-gate-intra-doc-pointers.rs:3:6
+ |
+LL | //! [pointer::wrapping_add]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information
+ = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable
+ = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/rustdoc-ui/intra-doc/field-ice.rs b/src/test/rustdoc-ui/intra-doc/field-ice.rs
new file mode 100644
index 000000000..c5d501e38
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/field-ice.rs
@@ -0,0 +1,11 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+//~^NOTE the lint level is defined here
+
+/// [`Foo::bar`]
+/// [`Foo::bar()`]
+//~^ERROR incompatible link kind for `Foo::bar`
+//~|HELP to link to the field, remove the disambiguator
+//~|NOTE this link resolved to a field, which is not a function
+pub struct Foo {
+ pub bar: u8
+}
diff --git a/src/test/rustdoc-ui/intra-doc/field-ice.stderr b/src/test/rustdoc-ui/intra-doc/field-ice.stderr
new file mode 100644
index 000000000..f45a3ca61
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/field-ice.stderr
@@ -0,0 +1,18 @@
+error: incompatible link kind for `Foo::bar`
+ --> $DIR/field-ice.rs:5:7
+ |
+LL | /// [`Foo::bar()`]
+ | ^^^^^^^^^^ this link resolved to a field, which is not a function
+ |
+note: the lint level is defined here
+ --> $DIR/field-ice.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the field, remove the disambiguator
+ |
+LL | /// [`Foo::bar`]
+ | ~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/global-path.rs b/src/test/rustdoc-ui/intra-doc/global-path.rs
new file mode 100644
index 000000000..cc7a5fa1c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/global-path.rs
@@ -0,0 +1,8 @@
+// Doc link path with empty prefix that resolves to "extern prelude" instead of a module.
+
+// check-pass
+// edition:2018
+
+/// [::Unresolved]
+//~^ WARN unresolved link to `::Unresolved`
+pub struct Item;
diff --git a/src/test/rustdoc-ui/intra-doc/global-path.stderr b/src/test/rustdoc-ui/intra-doc/global-path.stderr
new file mode 100644
index 000000000..02379cd6c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/global-path.stderr
@@ -0,0 +1,10 @@
+warning: unresolved link to `::Unresolved`
+ --> $DIR/global-path.rs:6:6
+ |
+LL | /// [::Unresolved]
+ | ^^^^^^^^^^^^ no item named `` in scope
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs
new file mode 100644
index 000000000..b5470c859
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs
@@ -0,0 +1,25 @@
+#![deny(rustdoc::invalid_html_tags)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct ExistentStruct<T>(T);
+
+/// This [test][ExistentStruct<i32>] thing!
+pub struct NoError;
+
+/// This [ExistentStruct<i32>] thing!
+//~^ ERROR unclosed HTML tag `i32`
+pub struct PartialErrorOnlyHtml;
+
+/// This [test][NonExistentStruct<i32>] thing!
+//~^ ERROR unresolved link
+pub struct PartialErrorOnlyResolve;
+
+/// This [NonExistentStruct2<i32>] thing!
+//~^ ERROR unclosed HTML tag `i32`
+//~| ERROR unresolved link
+pub struct YesError;
+
+/// This [NonExistentStruct3<i32>][] thing!
+//~^ ERROR unclosed HTML tag `i32`
+//~| ERROR unresolved link
+pub struct YesErrorCollapsed;
diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr
new file mode 100644
index 000000000..00fe229da
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr
@@ -0,0 +1,69 @@
+error: unresolved link to `NonExistentStruct`
+ --> $DIR/html-as-generics-intra-doc.rs:13:17
+ |
+LL | /// This [test][NonExistentStruct<i32>] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-intra-doc.rs:2:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `NonExistentStruct2`
+ --> $DIR/html-as-generics-intra-doc.rs:17:11
+ |
+LL | /// This [NonExistentStruct2<i32>] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `NonExistentStruct3`
+ --> $DIR/html-as-generics-intra-doc.rs:22:11
+ |
+LL | /// This [NonExistentStruct3<i32>][] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct3` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:9:25
+ |
+LL | /// This [ExistentStruct<i32>] thing!
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-intra-doc.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try marking as source code
+ |
+LL | /// This [`ExistentStruct<i32>`] thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:17:29
+ |
+LL | /// This [NonExistentStruct2<i32>] thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [`NonExistentStruct2<i32>`] thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:22:29
+ |
+LL | /// This [NonExistentStruct3<i32>][] thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [`NonExistentStruct3<i32>`][] thing!
+ | + +
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs
new file mode 100644
index 000000000..3088bcd46
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs
@@ -0,0 +1,3 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+//! [static@u8::MIN]
+//~^ ERROR incompatible link kind
diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr
new file mode 100644
index 000000000..c43cda3eb
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr
@@ -0,0 +1,18 @@
+error: incompatible link kind for `u8::MIN`
+ --> $DIR/incompatible-primitive-disambiguator.rs:2:6
+ |
+LL | //! [static@u8::MIN]
+ | ^^^^^^^^^^^^^^ this link resolved to an associated constant, which is not a static
+ |
+note: the lint level is defined here
+ --> $DIR/incompatible-primitive-disambiguator.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the associated constant, prefix with `const@`
+ |
+LL | //! [const@u8::MIN]
+ | ~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs
new file mode 100644
index 000000000..8490584c1
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs
@@ -0,0 +1,26 @@
+// `macro_rules` scopes are respected during doc link resolution.
+
+// compile-flags: --document-private-items
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+mod no_escape {
+ macro_rules! before_but_limited_to_module {
+ () => {};
+ }
+}
+
+/// [before_but_limited_to_module]
+//~^ ERROR unresolved link to `before_but_limited_to_module`
+/// [after]
+//~^ ERROR unresolved link to `after`
+/// [str]
+fn check() {}
+
+macro_rules! after {
+ () => {};
+}
+
+macro_rules! str {
+ () => {};
+}
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr
new file mode 100644
index 000000000..8e17323fd
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr
@@ -0,0 +1,23 @@
+error: unresolved link to `before_but_limited_to_module`
+ --> $DIR/macro-rules-error.rs:13:6
+ |
+LL | /// [before_but_limited_to_module]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/macro-rules-error.rs:5:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location
+
+error: unresolved link to `after`
+ --> $DIR/macro-rules-error.rs:15:6
+ |
+LL | /// [after]
+ | ^^^^^ no item named `after` in scope
+ |
+ = note: `macro_rules` named `after` exists in this crate, but it is not in scope at this link's location
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules.rs b/src/test/rustdoc-ui/intra-doc/macro-rules.rs
new file mode 100644
index 000000000..3aeb370ef
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/macro-rules.rs
@@ -0,0 +1,24 @@
+// check-pass
+#![allow(rustdoc::private_intra_doc_links)]
+
+macro_rules! foo {
+ () => {};
+}
+
+/// [foo!]
+pub fn baz() {}
+
+#[macro_use]
+mod macros {
+ macro_rules! escaping {
+ () => {};
+ }
+}
+
+pub mod inner {
+ /// [foo!]
+ /// [escaping]
+ pub fn baz() {
+ foo!();
+ }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
new file mode 100644
index 000000000..15e02925e
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
@@ -0,0 +1,19 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! [Vec<] //~ ERROR
+//! [Vec<Box<T] //~ ERROR
+//! [Vec<Box<T>] //~ ERROR
+//! [Vec<Box<T>>>] //~ ERROR
+//! [Vec<T>>>] //~ ERROR
+//! [<Vec] //~ ERROR
+//! [Vec::<] //~ ERROR
+//! [<T>] //~ ERROR
+//! [<invalid syntax>] //~ ERROR
+//! [Vec:<T>:new()] //~ ERROR
+//! [Vec<<T>>] //~ ERROR
+//! [Vec<>] //~ ERROR
+//! [Vec<<>>] //~ ERROR
+
+// FIXME(#74563) support UFCS
+//! [<Vec as IntoIterator>::into_iter] //~ ERROR
+//! [<Vec<T> as IntoIterator>::iter] //~ ERROR
diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
new file mode 100644
index 000000000..5bc0f84e2
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
@@ -0,0 +1,102 @@
+error: unresolved link to `Vec<`
+ --> $DIR/malformed-generics.rs:3:6
+ |
+LL | //! [Vec<]
+ | ^^^^ unbalanced angle brackets
+ |
+note: the lint level is defined here
+ --> $DIR/malformed-generics.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `Vec<Box<T`
+ --> $DIR/malformed-generics.rs:4:6
+ |
+LL | //! [Vec<Box<T]
+ | ^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>`
+ --> $DIR/malformed-generics.rs:5:6
+ |
+LL | //! [Vec<Box<T>]
+ | ^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>>>`
+ --> $DIR/malformed-generics.rs:6:6
+ |
+LL | //! [Vec<Box<T>>>]
+ | ^^^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<T>>>`
+ --> $DIR/malformed-generics.rs:7:6
+ |
+LL | //! [Vec<T>>>]
+ | ^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<Vec`
+ --> $DIR/malformed-generics.rs:8:6
+ |
+LL | //! [<Vec]
+ | ^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec::<`
+ --> $DIR/malformed-generics.rs:9:6
+ |
+LL | //! [Vec::<]
+ | ^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<T>`
+ --> $DIR/malformed-generics.rs:10:6
+ |
+LL | //! [<T>]
+ | ^^^ missing type for generic parameters
+
+error: unresolved link to `<invalid syntax>`
+ --> $DIR/malformed-generics.rs:11:6
+ |
+LL | //! [<invalid syntax>]
+ | ^^^^^^^^^^^^^^^^ missing type for generic parameters
+
+error: unresolved link to `Vec:<T>:new`
+ --> $DIR/malformed-generics.rs:12:6
+ |
+LL | //! [Vec:<T>:new()]
+ | ^^^^^^^^^^^^^ has invalid path separator
+
+error: unresolved link to `Vec<<T>>`
+ --> $DIR/malformed-generics.rs:13:6
+ |
+LL | //! [Vec<<T>>]
+ | ^^^^^^^^ too many angle brackets
+
+error: unresolved link to `Vec<>`
+ --> $DIR/malformed-generics.rs:14:6
+ |
+LL | //! [Vec<>]
+ | ^^^^^ empty angle brackets
+
+error: unresolved link to `Vec<<>>`
+ --> $DIR/malformed-generics.rs:15:6
+ |
+LL | //! [Vec<<>>]
+ | ^^^^^^^ too many angle brackets
+
+error: unresolved link to `<Vec as IntoIterator>::into_iter`
+ --> $DIR/malformed-generics.rs:18:6
+ |
+LL | //! [<Vec as IntoIterator>::into_iter]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+ |
+ = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: unresolved link to `<Vec<T> as IntoIterator>::iter`
+ --> $DIR/malformed-generics.rs:19:6
+ |
+LL | //! [<Vec<T> as IntoIterator>::iter]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+ |
+ = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
new file mode 100644
index 000000000..587cbad68
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
@@ -0,0 +1,34 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
+// These are links that could reasonably expected to work, but don't.
+
+// `[]` isn't supported because it had too many false positives.
+//! [X]([T]::not_here)
+//! [Y](&[]::not_here)
+//! [X]([]::not_here)
+//! [Y]([T;N]::not_here)
+
+// These don't work because markdown syntax doesn't allow it.
+//! [[T]::rotate_left] //~ ERROR unresolved link to `T`
+//! [&[]::not_here]
+//![Z]([T; N]::map) //~ ERROR unresolved link to `Z`
+//! [`[T; N]::map`]
+//! [[]::map]
+//! [Z][] //~ ERROR unresolved link to `Z`
+//!
+//! [Z]: [T; N]::map //~ ERROR unresolved link to `Z`
+
+// `()` isn't supported because it had too many false positives.
+//! [()::not_here]
+//! [X]((,)::not_here)
+//! [(,)::not_here]
+
+// FIXME: Associated items on some primitives aren't working, because the impls
+// are part of the compiler instead of being part of the source code.
+//! [unit::eq] //~ ERROR unresolved
+//! [tuple::eq] //~ ERROR unresolved
+//! [fn::eq] //~ ERROR unresolved
+
+// FIXME(#78800): This breaks because it's a blanket impl
+// (I think? Might break for other reasons too.)
+//! [reference::deref] //~ ERROR unresolved
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
new file mode 100644
index 000000000..4828a3044
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
@@ -0,0 +1,63 @@
+error: unresolved link to `T`
+ --> $DIR/non-path-primitives.rs:12:7
+ |
+LL | //! [[T]::rotate_left]
+ | ^ no item named `T` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/non-path-primitives.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:14:5
+ |
+LL | //![Z]([T; N]::map)
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:17:6
+ |
+LL | //! [Z][]
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:19:6
+ |
+LL | //! [Z]: [T; N]::map
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `unit::eq`
+ --> $DIR/non-path-primitives.rs:28:6
+ |
+LL | //! [unit::eq]
+ | ^^^^^^^^ the builtin type `unit` has no associated item named `eq`
+
+error: unresolved link to `tuple::eq`
+ --> $DIR/non-path-primitives.rs:29:6
+ |
+LL | //! [tuple::eq]
+ | ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq`
+
+error: unresolved link to `fn::eq`
+ --> $DIR/non-path-primitives.rs:30:6
+ |
+LL | //! [fn::eq]
+ | ^^^^^^ the builtin type `fn` has no associated item named `eq`
+
+error: unresolved link to `reference::deref`
+ --> $DIR/non-path-primitives.rs:34:6
+ |
+LL | //! [reference::deref]
+ | ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs b/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs
new file mode 100644
index 000000000..8654a8e1b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs
@@ -0,0 +1,4 @@
+// aux-build:pointer-reexports-allowed.rs
+// check-pass
+extern crate inner;
+pub use inner::foo;
diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.rs b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs
new file mode 100644
index 000000000..2c1a8b535
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs
@@ -0,0 +1,30 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+//~^ NOTE lint level is defined
+
+/// [char]
+//~^ ERROR both a module and a builtin type
+//~| NOTE ambiguous link
+//~| HELP to link to the module
+//~| HELP to link to the builtin type
+
+/// [type@char]
+//~^ ERROR both a module and a builtin type
+//~| NOTE ambiguous link
+//~| HELP to link to the module
+//~| HELP to link to the builtin type
+
+/// [mod@char] // ok
+/// [prim@char] // ok
+
+/// [struct@char]
+//~^ ERROR incompatible link
+//~| HELP prefix with `mod@`
+//~| NOTE resolved to a module
+pub mod char {}
+
+pub mod inner {
+ //! [struct@char]
+ //~^ ERROR incompatible link
+ //~| HELP prefix with `prim@`
+ //~| NOTE resolved to a builtin type
+}
diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr
new file mode 100644
index 000000000..6ef3b7eab
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr
@@ -0,0 +1,59 @@
+error: `char` is both a module and a builtin type
+ --> $DIR/prim-conflict.rs:4:6
+ |
+LL | /// [char]
+ | ^^^^ ambiguous link
+ |
+note: the lint level is defined here
+ --> $DIR/prim-conflict.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// [mod@char]
+ | ++++
+help: to link to the builtin type, prefix with `prim@`
+ |
+LL | /// [prim@char]
+ | +++++
+
+error: `char` is both a module and a builtin type
+ --> $DIR/prim-conflict.rs:10:6
+ |
+LL | /// [type@char]
+ | ^^^^^^^^^ ambiguous link
+ |
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// [mod@char]
+ | ~~~~
+help: to link to the builtin type, prefix with `prim@`
+ |
+LL | /// [prim@char]
+ | ~~~~~
+
+error: incompatible link kind for `char`
+ --> $DIR/prim-conflict.rs:19:6
+ |
+LL | /// [struct@char]
+ | ^^^^^^^^^^^ this link resolved to a module, which is not a struct
+ |
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// [mod@char]
+ | ~~~~
+
+error: incompatible link kind for `char`
+ --> $DIR/prim-conflict.rs:26:10
+ |
+LL | //! [struct@char]
+ | ^^^^^^^^^^^ this link resolved to a builtin type, which is not a struct
+ |
+help: to link to the builtin type, prefix with `prim@`
+ |
+LL | //! [prim@char]
+ | ~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs
new file mode 100644
index 000000000..e429e75b2
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs
@@ -0,0 +1,6 @@
+// check-pass
+
+//! [my_module]
+//~^ WARN public documentation for `private_from_crate_level` links to private item `my_module`
+
+mod my_module {}
diff --git a/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr
new file mode 100644
index 000000000..6172cd2e3
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr
@@ -0,0 +1,11 @@
+warning: public documentation for `private_from_crate_level` links to private item `my_module`
+ --> $DIR/private-from-crate-level.rs:3:6
+ |
+LL | //! [my_module]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/private.private.stderr b/src/test/rustdoc-ui/intra-doc/private.private.stderr
new file mode 100644
index 000000000..392321f9c
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/private.private.stderr
@@ -0,0 +1,27 @@
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/private.rs:7:11
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: public documentation for `DocMe` links to private item `DontDocMe::f`
+ --> $DIR/private.rs:7:23
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^^^^ this item is private
+ |
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: public documentation for `DocMe` links to private item `DontDocMe::x`
+ --> $DIR/private.rs:7:38
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^^^^ this item is private
+ |
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 3 warnings emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/private.public.stderr b/src/test/rustdoc-ui/intra-doc/private.public.stderr
new file mode 100644
index 000000000..5d1c34b91
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/private.public.stderr
@@ -0,0 +1,27 @@
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/private.rs:7:11
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
+
+warning: public documentation for `DocMe` links to private item `DontDocMe::f`
+ --> $DIR/private.rs:7:23
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^^^^ this item is private
+ |
+ = note: this link will resolve properly if you pass `--document-private-items`
+
+warning: public documentation for `DocMe` links to private item `DontDocMe::x`
+ --> $DIR/private.rs:7:38
+ |
+LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+ | ^^^^^^^^^^^^ this item is private
+ |
+ = note: this link will resolve properly if you pass `--document-private-items`
+
+warning: 3 warnings emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/private.rs b/src/test/rustdoc-ui/intra-doc/private.rs
new file mode 100644
index 000000000..525332dda
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/private.rs
@@ -0,0 +1,18 @@
+// check-pass
+// revisions: public private
+// [private]compile-flags: --document-private-items
+
+// make sure to update `rustdoc/intra-doc/private.rs` if you update this file
+
+/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
+//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::x`
+//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::f`
+pub struct DocMe;
+struct DontDocMe {
+ x: usize,
+}
+
+impl DontDocMe {
+ fn f() {}
+}
diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs
new file mode 100644
index 000000000..041ec2932
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs
@@ -0,0 +1,13 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to
+// attempt to slice in the middle of a multibyte character. See
+// https://github.com/rust-lang/rust/issues/55723
+
+/// ## For example:
+///
+/// (arr[i])
+//~^ ERROR `i`
+pub fn test_ice() {
+ unimplemented!();
+}
diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr
new file mode 100644
index 000000000..bf4ab9fdd
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `i`
+ --> $DIR/span-ice-55723.rs:9:10
+ |
+LL | /// (arr[i])
+ | ^ no item named `i` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/span-ice-55723.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs
new file mode 100644
index 000000000..7628c3928
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs
@@ -0,0 +1,18 @@
+// check-pass
+// aux-build:through-proc-macro-aux.rs
+// build-aux-docs
+
+// Ensure rustdoc doesn't panic on this code.
+
+#![warn(rustdoc::broken_intra_doc_links)]
+
+extern crate some_macros;
+
+#[some_macros::second]
+pub enum Boom {
+ /// [Oooops]
+ //~^ WARNING unresolved link to `Oooops`
+ Bam,
+}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr
new file mode 100644
index 000000000..f0a7ed178
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr
@@ -0,0 +1,15 @@
+warning: unresolved link to `Oooops`
+ --> $DIR/through-proc-macro.rs:13:10
+ |
+LL | /// [Oooops]
+ | ^^^^^^ no item named `Oooops` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/through-proc-macro.rs:7:9
+ |
+LL | #![warn(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs
new file mode 100644
index 000000000..0aa1e5a41
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs
@@ -0,0 +1,14 @@
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+#![deny(warnings)]
+
+//! Linking to [foo@banana] and [`bar@banana!()`].
+//~^ ERROR unknown disambiguator `foo`
+//~| ERROR unknown disambiguator `bar`
+//! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+//~^ ERROR unknown disambiguator ``
+//~| ERROR unknown disambiguator ``
+//! And with weird backticks: [``foo@hello``] [foo`@`hello].
+//~^ ERROR unknown disambiguator `foo`
+//~| ERROR unknown disambiguator `foo`
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
new file mode 100644
index 000000000..d280e6497
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
@@ -0,0 +1,56 @@
+error: unknown disambiguator `foo`
+ --> $DIR/unknown-disambiguator.rs:4:17
+ |
+LL | //! Linking to [foo@banana] and [`bar@banana!()`].
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/unknown-disambiguator.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: unknown disambiguator `bar`
+ --> $DIR/unknown-disambiguator.rs:4:35
+ |
+LL | //! Linking to [foo@banana] and [`bar@banana!()`].
+ | ^^^
+ |
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: unknown disambiguator `foo`
+ --> $DIR/unknown-disambiguator.rs:10:34
+ |
+LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
+ | ^^^
+ |
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: unknown disambiguator `foo`
+ --> $DIR/unknown-disambiguator.rs:10:48
+ |
+LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
+ | ^^^
+ |
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: unknown disambiguator ``
+ --> $DIR/unknown-disambiguator.rs:7:31
+ |
+LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+ | ^
+ |
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: unknown disambiguator ``
+ --> $DIR/unknown-disambiguator.rs:7:57
+ |
+LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+ | ^
+ |
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs
new file mode 100644
index 000000000..c71e5bee1
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs
@@ -0,0 +1,6 @@
+// Regression test for issue #95879.
+
+use unresolved_crate::module::Name; //~ ERROR failed to resolve
+
+/// [Name]
+pub struct S;
diff --git a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr
new file mode 100644
index 000000000..b54f82006
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr
@@ -0,0 +1,13 @@
+error[E0433]: failed to resolve: maybe a missing crate `unresolved_crate`?
+ --> $DIR/unresolved-import-recovery.rs:3:5
+ |
+LL | use unresolved_crate::module::Name;
+ | ^^^^^^^^^^^^^^^^ maybe a missing crate `unresolved_crate`?
+ |
+ = help: consider adding `extern crate unresolved_crate` to use the `unresolved_crate` crate
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs
new file mode 100644
index 000000000..956583093
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs
@@ -0,0 +1,5 @@
+// compile-flags: --extern zip=whatever.rlib
+#![deny(rustdoc::broken_intra_doc_links)]
+/// See [zip] crate.
+//~^ ERROR unresolved
+pub struct ArrayZip;
diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr
new file mode 100644
index 000000000..5c0df1d1b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `zip`
+ --> $DIR/unused-extern-crate.rs:3:10
+ |
+LL | /// See [zip] crate.
+ | ^^^ no item named `zip` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/unused-extern-crate.rs:2:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-doc/warning-crlf.rs b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs
new file mode 100644
index 000000000..ceb62f6d1
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-cr
+// check-pass
+
+// This file checks the spans of intra-link warnings in a file with CRLF line endings. The
+// .gitattributes file in this directory should enforce it.
+
+/// [error]
+pub struct A;
+//~^^ WARNING `error`
+
+///
+/// docs [error1]
+//~^ WARNING `error1`
+
+/// docs [error2]
+///
+pub struct B;
+//~^^^ WARNING `error2`
+
+/**
+ * This is a multi-line comment.
+ *
+ * It also has an [error].
+ */
+pub struct C;
+//~^^^ WARNING `error`
diff --git a/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr
new file mode 100644
index 000000000..d46df9264
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr
@@ -0,0 +1,35 @@
+warning: unresolved link to `error`
+ --> $DIR/warning-crlf.rs:7:6
+ |
+LL | /// [error]
+ | ^^^^^ no item named `error` in scope
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error1`
+ --> $DIR/warning-crlf.rs:12:11
+ |
+LL | /// docs [error1]
+ | ^^^^^^ no item named `error1` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error2`
+ --> $DIR/warning-crlf.rs:15:11
+ |
+LL | /// docs [error2]
+ | ^^^^^^ no item named `error2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error`
+ --> $DIR/warning-crlf.rs:23:20
+ |
+LL | * It also has an [error].
+ | ^^^^^ no item named `error` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: 4 warnings emitted
+
diff --git a/src/test/rustdoc-ui/intra-doc/warning.rs b/src/test/rustdoc-ui/intra-doc/warning.rs
new file mode 100644
index 000000000..eab1f0348
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/warning.rs
@@ -0,0 +1,84 @@
+// check-pass
+
+ //! Test with [Foo::baz], [Bar::foo], ...
+//~^ WARNING `Foo::baz`
+//~| WARNING `Bar::foo`
+ //! , [Uniooon::X] and [Qux::Z].
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
+ //!
+ //! , [Uniooon::X] and [Qux::Z].
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
+
+ /// [Qux:Y]
+//~^ WARNING `Qux:Y`
+pub struct Foo {
+ pub bar: usize,
+}
+
+/// Foo
+/// bar [BarA] bar //~ WARNING `BarA`
+/// baz
+pub fn a() {}
+
+/**
+ * Foo
+ * bar [BarB] bar //~ WARNING `BarB`
+ * baz
+ */
+pub fn b() {}
+
+/** Foo
+
+bar [BarC] bar //~ WARNING `BarC`
+baz
+
+ let bar_c_1 = 0;
+ let bar_c_2 = 0;
+ let g = [bar_c_1];
+ let h = g[bar_c_2];
+
+*/
+pub fn c() {}
+
+#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD`
+pub fn d() {}
+
+macro_rules! f {
+ ($f:expr) => {
+ #[doc = $f] //~ WARNING `BarF`
+ pub fn f() {}
+ }
+}
+f!("Foo\nbar [BarF] bar\nbaz");
+
+/** # for example,
+ *
+ * time to introduce a link [error]*/ //~ WARNING `error`
+pub struct A;
+
+/**
+ * # for example,
+ *
+ * time to introduce a link [error] //~ WARNING `error`
+ */
+pub struct B;
+
+#[doc = "single line [error]"] //~ WARNING `error`
+pub struct C;
+
+#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error`
+pub struct D;
+
+/// Item docs. //~ WARNING `error`
+#[doc="Hello there!"]
+/// [error]
+pub struct E;
+
+///
+/// docs [error1] //~ WARNING `error1`
+
+/// docs [error2] //~ WARNING `error2`
+///
+pub struct F;
diff --git a/src/test/rustdoc-ui/intra-doc/warning.stderr b/src/test/rustdoc-ui/intra-doc/warning.stderr
new file mode 100644
index 000000000..19399a0df
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/warning.stderr
@@ -0,0 +1,175 @@
+warning: unresolved link to `Foo::baz`
+ --> $DIR/warning.rs:3:23
+ |
+LL | //! Test with [Foo::baz], [Bar::foo], ...
+ | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz`
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: unresolved link to `Bar::foo`
+ --> $DIR/warning.rs:3:35
+ |
+LL | //! Test with [Foo::baz], [Bar::foo], ...
+ | ^^^^^^^^ no item named `Bar` in scope
+
+warning: unresolved link to `Uniooon::X`
+ --> $DIR/warning.rs:6:13
+ |
+LL | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^^^^^ no item named `Uniooon` in scope
+
+warning: unresolved link to `Qux::Z`
+ --> $DIR/warning.rs:6:30
+ |
+LL | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^ no item named `Qux` in scope
+
+warning: unresolved link to `Uniooon::X`
+ --> $DIR/warning.rs:10:14
+ |
+LL | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^^^^^ no item named `Uniooon` in scope
+
+warning: unresolved link to `Qux::Z`
+ --> $DIR/warning.rs:10:31
+ |
+LL | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^ no item named `Qux` in scope
+
+warning: unresolved link to `Qux:Y`
+ --> $DIR/warning.rs:14:13
+ |
+LL | /// [Qux:Y]
+ | ^^^^^ no item named `Qux:Y` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarA`
+ --> $DIR/warning.rs:21:10
+ |
+LL | /// bar [BarA] bar
+ | ^^^^ no item named `BarA` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarB`
+ --> $DIR/warning.rs:27:9
+ |
+LL | * bar [BarB] bar
+ | ^^^^ no item named `BarB` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarC`
+ --> $DIR/warning.rs:34:6
+ |
+LL | bar [BarC] bar
+ | ^^^^ no item named `BarC` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarD`
+ --> $DIR/warning.rs:45:1
+ |
+LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the link appears in this line:
+
+ bar [BarD] bar
+ ^^^^
+ = note: no item named `BarD` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarF`
+ --> $DIR/warning.rs:50:9
+ |
+LL | #[doc = $f]
+ | ^^^^^^^^^^^
+...
+LL | f!("Foo\nbar [BarF] bar\nbaz");
+ | ------------------------------ in this macro invocation
+ |
+ = note: the link appears in this line:
+
+ bar [BarF] bar
+ ^^^^
+ = note: no item named `BarF` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+ = note: this warning originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: unresolved link to `error`
+ --> $DIR/warning.rs:58:30
+ |
+LL | * time to introduce a link [error]*/
+ | ^^^^^ no item named `error` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error`
+ --> $DIR/warning.rs:64:30
+ |
+LL | * time to introduce a link [error]
+ | ^^^^^ no item named `error` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error`
+ --> $DIR/warning.rs:68:1
+ |
+LL | #[doc = "single line [error]"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the link appears in this line:
+
+ single line [error]
+ ^^^^^
+ = note: no item named `error` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error`
+ --> $DIR/warning.rs:71:1
+ |
+LL | #[doc = "single line with \"escaping\" [error]"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the link appears in this line:
+
+ single line with "escaping" [error]
+ ^^^^^
+ = note: no item named `error` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error`
+ --> $DIR/warning.rs:74:1
+ |
+LL | / /// Item docs.
+LL | | #[doc="Hello there!"]
+LL | | /// [error]
+ | |___________^
+ |
+ = note: the link appears in this line:
+
+ [error]
+ ^^^^^
+ = note: no item named `error` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error1`
+ --> $DIR/warning.rs:80:11
+ |
+LL | /// docs [error1]
+ | ^^^^^^ no item named `error1` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `error2`
+ --> $DIR/warning.rs:82:11
+ |
+LL | /// docs [error2]
+ | ^^^^^^ no item named `error2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: 19 warnings emitted
+
diff --git a/src/test/rustdoc-ui/invalid-cfg.rs b/src/test/rustdoc-ui/invalid-cfg.rs
new file mode 100644
index 000000000..d237b8605
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-cfg.rs
@@ -0,0 +1,4 @@
+#![feature(doc_cfg)]
+#[doc(cfg = "x")] //~ ERROR not followed by parentheses
+#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates
+struct S {}
diff --git a/src/test/rustdoc-ui/invalid-cfg.stderr b/src/test/rustdoc-ui/invalid-cfg.stderr
new file mode 100644
index 000000000..dae238b05
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-cfg.stderr
@@ -0,0 +1,14 @@
+error: `cfg` is not followed by parentheses
+ --> $DIR/invalid-cfg.rs:2:7
+ |
+LL | #[doc(cfg = "x")]
+ | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+
+error: multiple `cfg` predicates are specified
+ --> $DIR/invalid-cfg.rs:3:14
+ |
+LL | #[doc(cfg(x, y))]
+ | ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/invalid-doc-attr.rs b/src/test/rustdoc-ui/invalid-doc-attr.rs
new file mode 100644
index 000000000..de004b41e
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-doc-attr.rs
@@ -0,0 +1,32 @@
+#![crate_type = "lib"]
+#![deny(warnings)]
+
+#[doc(test(no_crate_inject))]
+//~^ ERROR can only be applied at the crate level
+//~| WARN is being phased out
+//~| HELP to apply to the crate, use an inner attribute
+//~| SUGGESTION #![doc(test(no_crate_inject))]
+#[doc(inline)]
+//~^ ERROR can only be applied to a `use` item
+//~| WARN is being phased out
+pub fn foo() {}
+
+pub mod bar {
+ #![doc(test(no_crate_inject))]
+ //~^ ERROR can only be applied at the crate level
+ //~| WARN is being phased out
+
+ #[doc(test(no_crate_inject))]
+ //~^ ERROR can only be applied at the crate level
+ //~| WARN is being phased out
+ #[doc(inline)]
+ //~^ ERROR can only be applied to a `use` item
+ //~| WARN is being phased out
+ pub fn baz() {}
+}
+
+#[doc(inline)]
+#[doc(no_inline)]
+//~^^ ERROR conflicting doc inlining attributes
+//~| HELP remove one of the conflicting attributes
+pub use bar::baz;
diff --git a/src/test/rustdoc-ui/invalid-doc-attr.stderr b/src/test/rustdoc-ui/invalid-doc-attr.stderr
new file mode 100644
index 000000000..a4fa38179
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-doc-attr.stderr
@@ -0,0 +1,78 @@
+error: this attribute can only be applied at the crate level
+ --> $DIR/invalid-doc-attr.rs:4:7
+ |
+LL | #[doc(test(no_crate_inject))]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/invalid-doc-attr.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
+help: to apply to the crate, use an inner attribute
+ |
+LL | #![doc(test(no_crate_inject))]
+ |
+
+error: this attribute can only be applied to a `use` item
+ --> $DIR/invalid-doc-attr.rs:9:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^ only applicable on `use` items
+...
+LL | pub fn foo() {}
+ | ------------ not a `use` item
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
+
+error: this attribute can only be applied at the crate level
+ --> $DIR/invalid-doc-attr.rs:15:12
+ |
+LL | #![doc(test(no_crate_inject))]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
+
+error: conflicting doc inlining attributes
+ --> $DIR/invalid-doc-attr.rs:28:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^ this attribute...
+LL | #[doc(no_inline)]
+ | ^^^^^^^^^ ...conflicts with this attribute
+ |
+ = help: remove one of the conflicting attributes
+
+error: this attribute can only be applied at the crate level
+ --> $DIR/invalid-doc-attr.rs:19:11
+ |
+LL | #[doc(test(no_crate_inject))]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
+
+error: this attribute can only be applied to a `use` item
+ --> $DIR/invalid-doc-attr.rs:22:11
+ |
+LL | #[doc(inline)]
+ | ^^^^^^ only applicable on `use` items
+...
+LL | pub fn baz() {}
+ | ------------ not a `use` item
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+ = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs
new file mode 100644
index 000000000..0f9d2e4b3
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.rs
@@ -0,0 +1,116 @@
+#![deny(rustdoc::invalid_html_tags)]
+
+//! <p>💩<p>
+//~^ ERROR unclosed HTML tag `p`
+//~^^ ERROR unclosed HTML tag `p`
+
+/// <img><input>
+/// <script>
+/// <img><input>
+/// </script>
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+/// < ok
+/// <script>
+//~^ ERROR unclosed HTML tag `script`
+pub fn foo() {}
+
+/// <h1>
+/// <h2>
+//~^ ERROR unclosed HTML tag `h2`
+/// <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// </h1>
+/// </hello>
+//~^ ERROR unopened HTML tag `hello`
+pub fn bar() {}
+
+/// <div>
+/// <br/> <p>
+//~^ ERROR unclosed HTML tag `p`
+/// </div>
+pub fn a() {}
+
+/// <div>
+/// <p>
+/// <div></div>
+/// </p>
+/// </div>
+pub fn b() {}
+
+/// <div style="hello">
+//~^ ERROR unclosed HTML tag `div`
+/// <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// <script
+//~^ ERROR unclosed HTML tag `script`
+pub fn c() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <script> elem.
+/// <script>
+/// <h3><div>
+/// </script>
+/// <script>
+/// <div>
+/// <p>
+/// </div>
+/// </script>
+pub fn d() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <style> elem.
+/// <style>
+/// <h3><div>
+/// </style>
+/// <stYle>
+/// <div>
+/// <p>
+/// </div>
+/// </style>
+pub fn e() {}
+
+// Closing tags need to have ">" at the end, otherwise it's not a closing tag!
+/// <div></div >
+/// <div></div
+//~^ ERROR unclosed HTML tag `div`
+pub fn f() {}
+
+/// <!---->
+/// <!-- -->
+/// <!-- <div> -->
+/// <!-- <!-- -->
+pub fn g() {}
+
+/// <!--
+/// -->
+pub fn h() {}
+
+/// <!--
+//~^ ERROR Unclosed HTML comment
+pub fn i() {}
+
+/// hello
+///
+/// ```
+/// uiapp.run(&env::args().collect::<Vec<_>>());
+/// ```
+pub fn j() {}
+
+// Check that nested codeblocks are working as well
+/// hello
+///
+/// ``````markdown
+/// normal markdown
+///
+/// ```
+/// uiapp.run(&env::args().collect::<Vec<_>>());
+/// ```
+///
+/// <Vec<_> shouldn't warn!
+/// ``````
+pub fn k() {}
+
+/// Web Components style <dashed-tags>
+//~^ ERROR unclosed HTML tag `dashed-tags`
+/// Web Components style </unopened-tag>
+//~^ ERROR unopened HTML tag `unopened-tag`
+pub fn m() {}
diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr
new file mode 100644
index 000000000..24a455576
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.stderr
@@ -0,0 +1,98 @@
+error: unclosed HTML tag `p`
+ --> $DIR/invalid-html-tags.rs:3:5
+ |
+LL | //! <p>💩<p>
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/invalid-html-tags.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unclosed HTML tag `p`
+ --> $DIR/invalid-html-tags.rs:3:9
+ |
+LL | //! <p>💩<p>
+ | ^^^
+
+error: unclosed HTML tag `unknown`
+ --> $DIR/invalid-html-tags.rs:11:5
+ |
+LL | /// <unknown>
+ | ^^^^^^^^^
+
+error: unclosed HTML tag `script`
+ --> $DIR/invalid-html-tags.rs:14:5
+ |
+LL | /// <script>
+ | ^^^^^^^^
+
+error: unclosed HTML tag `h2`
+ --> $DIR/invalid-html-tags.rs:19:7
+ |
+LL | /// <h2>
+ | ^^^^
+
+error: unclosed HTML tag `h3`
+ --> $DIR/invalid-html-tags.rs:21:9
+ |
+LL | /// <h3>
+ | ^^^^
+
+error: unopened HTML tag `hello`
+ --> $DIR/invalid-html-tags.rs:24:5
+ |
+LL | /// </hello>
+ | ^^^^^^^^
+
+error: unclosed HTML tag `p`
+ --> $DIR/invalid-html-tags.rs:29:14
+ |
+LL | /// <br/> <p>
+ | ^^^
+
+error: unclosed HTML tag `div`
+ --> $DIR/invalid-html-tags.rs:41:5
+ |
+LL | /// <div style="hello">
+ | ^^^^
+
+error: unclosed HTML tag `h3`
+ --> $DIR/invalid-html-tags.rs:43:7
+ |
+LL | /// <h3>
+ | ^^^^
+
+error: unclosed HTML tag `script`
+ --> $DIR/invalid-html-tags.rs:45:5
+ |
+LL | /// <script
+ | ^^^^^^
+
+error: unclosed HTML tag `div`
+ --> $DIR/invalid-html-tags.rs:73:5
+ |
+LL | /// <div></div
+ | ^^^^^
+
+error: Unclosed HTML comment
+ --> $DIR/invalid-html-tags.rs:87:5
+ |
+LL | /// <!--
+ | ^^^
+
+error: unopened HTML tag `unopened-tag`
+ --> $DIR/invalid-html-tags.rs:114:26
+ |
+LL | /// Web Components style </unopened-tag>
+ | ^^^^^^^^^^^^^^^
+
+error: unclosed HTML tag `dashed-tags`
+ --> $DIR/invalid-html-tags.rs:112:26
+ |
+LL | /// Web Components style <dashed-tags>
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/rustdoc-ui/invalid-keyword.rs b/src/test/rustdoc-ui/invalid-keyword.rs
new file mode 100644
index 000000000..2d70471c8
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-keyword.rs
@@ -0,0 +1,4 @@
+#![feature(rustdoc_internals)]
+
+#[doc(keyword = "foo df")] //~ ERROR
+mod foo {}
diff --git a/src/test/rustdoc-ui/invalid-keyword.stderr b/src/test/rustdoc-ui/invalid-keyword.stderr
new file mode 100644
index 000000000..8658e3825
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-keyword.stderr
@@ -0,0 +1,8 @@
+error: `foo df` is not a valid identifier
+ --> $DIR/invalid-keyword.rs:3:17
+ |
+LL | #[doc(keyword = "foo df")]
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs
new file mode 100644
index 000000000..b503d1093
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-syntax.rs
@@ -0,0 +1,101 @@
+// check-pass
+
+/// ```
+/// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
+/// ```
+pub fn foo() {}
+//~^^^^ WARNING could not parse code block as Rust code
+
+/// ```
+/// |
+/// LL | use foobar::Baz;
+/// | ^^^^^^ did you mean `baz::foobar`?
+/// ```
+pub fn bar() {}
+//~^^^^^^ WARNING could not parse code block as Rust code
+
+/// ```
+/// valid
+/// ```
+///
+/// ```
+/// \_
+/// ```
+///
+/// ```text
+/// "invalid
+/// ```
+pub fn valid_and_invalid() {}
+//~^^^^^^^^ WARNING could not parse code block as Rust code
+
+/// This is a normal doc comment, but...
+///
+/// There's a code block with bad syntax in it:
+///
+/// ```rust
+/// \_
+/// ```
+///
+/// Good thing we tested it!
+pub fn baz() {}
+//~^^^^^^ WARNING could not parse code block as Rust code
+
+/// Indented block start
+///
+/// code with bad syntax
+/// \_
+///
+/// Indented block end
+pub fn quux() {}
+//~^^^^^ could not parse code block as Rust code
+
+/// Unclosed fence
+///
+/// ```
+/// slkdjf
+pub fn xyzzy() {}
+
+/// Indented code that contains a fence
+///
+/// ```
+pub fn blah() {}
+//~^^ WARNING could not parse code block as Rust code
+
+/// ```edition2018
+/// \_
+/// ```
+pub fn blargh() {}
+//~^^^^ WARNING could not parse code block as Rust code
+
+#[doc = "```"]
+/// \_
+#[doc = "```"]
+pub fn crazy_attrs() {}
+//~^^^^ WARNING could not parse code block
+
+/// ```rust
+/// ```
+pub fn empty_rust() {}
+//~^^^ WARNING Rust code block is empty
+
+/// ```
+///
+///
+/// ```
+pub fn empty_rust_with_whitespace() {}
+//~^^^^^ WARNING Rust code block is empty
+
+/// ```
+/// let x = 1;
+/// ```
+///
+/// \____/
+///
+pub fn indent_after_fenced() {}
+//~^^^ WARNING could not parse code block as Rust code
+
+/// ```
+/// "invalid
+/// ```
+pub fn invalid() {}
+//~^^^^ WARNING could not parse code block as Rust code
diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr
new file mode 100644
index 000000000..4c6249cc6
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-syntax.stderr
@@ -0,0 +1,154 @@
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:3:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
+LL | | /// ```
+ | |_______^
+ |
+ = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
+ = note: error from rustc: unknown start of token: \
+ = note: error from rustc: unknown start of token: \
+ = note: error from rustc: unknown start of token: \
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ++++
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:9:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// |
+LL | | /// LL | use foobar::Baz;
+LL | | /// | ^^^^^^ did you mean `baz::foobar`?
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: `
+ = note: error from rustc: unknown start of token: `
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ++++
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:21:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// \_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: \
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ++++
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:35:5
+ |
+LL | /// ```rust
+ | _____^
+LL | | /// \_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: \
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:45:9
+ |
+LL | /// code with bad syntax
+ | _________^
+LL | | /// \_
+ | |__________^
+ |
+ = note: error from rustc: unknown start of token: \
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:60:9
+ |
+LL | /// ```
+ | ^^^
+ |
+ = note: error from rustc: unknown start of token: `
+ = note: error from rustc: unknown start of token: `
+ = note: error from rustc: unknown start of token: `
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:64:5
+ |
+LL | /// ```edition2018
+ | _____^
+LL | | /// \_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: \
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:70:1
+ |
+LL | / #[doc = "```"]
+LL | | /// \_
+LL | | #[doc = "```"]
+ | |______________^
+ |
+ = help: mark blocks that do not contain Rust code as text: ```text
+ = note: error from rustc: unknown start of token: \
+
+warning: Rust code block is empty
+ --> $DIR/invalid-syntax.rs:76:5
+ |
+LL | /// ```rust
+ | _____^
+LL | | /// ```
+ | |_______^
+
+warning: Rust code block is empty
+ --> $DIR/invalid-syntax.rs:81:5
+ |
+LL | /// ```
+ | _____^
+LL | | ///
+LL | | ///
+LL | | /// ```
+ | |_______^
+ |
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ++++
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:92:9
+ |
+LL | /// \____/
+ | _________^
+LL | | ///
+ | |_
+ |
+ = note: error from rustc: unknown start of token: \
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:97:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// "invalid
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unterminated double quote string
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ++++
+
+warning: 12 warnings emitted
+
diff --git a/src/test/rustdoc-ui/invalid-theme-name.rs b/src/test/rustdoc-ui/invalid-theme-name.rs
new file mode 100644
index 000000000..c22ebf027
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-theme-name.rs
@@ -0,0 +1,3 @@
+// compile-flags:--theme {{src-base}}/invalid-theme-name.rs
+// error-pattern: invalid argument
+// error-pattern: must have a .css extension
diff --git a/src/test/rustdoc-ui/invalid-theme-name.stderr b/src/test/rustdoc-ui/invalid-theme-name.stderr
new file mode 100644
index 000000000..80204442d
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-theme-name.stderr
@@ -0,0 +1,4 @@
+error: invalid argument: "$DIR/invalid-theme-name.rs"
+ |
+ = help: arguments to --theme must have a .css extension
+
diff --git a/src/test/rustdoc-ui/issue-58473-2.rs b/src/test/rustdoc-ui/issue-58473-2.rs
new file mode 100644
index 000000000..000b6a329
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-58473-2.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+ /**
+ Does nothing, returns `()`
+
+ yadda-yadda-yadda
+ */
+ fn foo() {}
+}
diff --git a/src/test/rustdoc-ui/issue-58473.rs b/src/test/rustdoc-ui/issue-58473.rs
new file mode 100644
index 000000000..44e1f58d0
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-58473.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+pub trait Foo {
+ /**
+ Does nothing, returns `()`
+
+ yadda-yadda-yadda
+ */
+ fn foo() {}
+}
diff --git a/src/test/rustdoc-ui/issue-61592-2.rs b/src/test/rustdoc-ui/issue-61592-2.rs
new file mode 100644
index 000000000..5b4fc5ee7
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61592-2.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-61592.rs
+
+extern crate foo;
+
+#[doc = "bar"]
+#[doc(inline)] //~ ERROR
+#[doc = "baz"]
+pub use foo::Foo as _;
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/issue-61592-2.stderr b/src/test/rustdoc-ui/issue-61592-2.stderr
new file mode 100644
index 000000000..1b7f8bb55
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61592-2.stderr
@@ -0,0 +1,12 @@
+error[E0780]: anonymous imports cannot be inlined
+ --> $DIR/issue-61592-2.rs:6:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^
+LL | #[doc = "baz"]
+LL | pub use foo::Foo as _;
+ | ---------------------- anonymous import
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0780`.
diff --git a/src/test/rustdoc-ui/issue-61592.rs b/src/test/rustdoc-ui/issue-61592.rs
new file mode 100644
index 000000000..66772557f
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61592.rs
@@ -0,0 +1,8 @@
+// aux-build:issue-61592.rs
+
+extern crate foo;
+
+#[doc(inline)] //~ ERROR
+pub use foo::Foo as _;
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/issue-61592.stderr b/src/test/rustdoc-ui/issue-61592.stderr
new file mode 100644
index 000000000..9c9c9106f
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61592.stderr
@@ -0,0 +1,11 @@
+error[E0780]: anonymous imports cannot be inlined
+ --> $DIR/issue-61592.rs:5:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^
+LL | pub use foo::Foo as _;
+ | ---------------------- anonymous import
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0780`.
diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs
new file mode 100644
index 000000000..4bd8efeaa
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.rs
@@ -0,0 +1,4 @@
+// This previously triggered an ICE.
+
+pub(in crate::r#mod) fn main() {}
+//~^ ERROR failed to resolve: maybe a missing crate `r#mod`
diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr
new file mode 100644
index 000000000..38fadaa44
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.stderr
@@ -0,0 +1,13 @@
+error[E0433]: failed to resolve: maybe a missing crate `r#mod`?
+ --> $DIR/issue-61732.rs:3:15
+ |
+LL | pub(in crate::r#mod) fn main() {}
+ | ^^^^^ maybe a missing crate `r#mod`?
+ |
+ = help: consider adding `extern crate r#mod` to use the `r#mod` crate
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr
new file mode 100644
index 000000000..31d2dbe96
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-74134.private.stderr
@@ -0,0 +1,11 @@
+warning: public documentation for `public_item` links to private item `PrivateType`
+ --> $DIR/issue-74134.rs:19:11
+ |
+LL | /// [`PrivateType`]
+ | ^^^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr
new file mode 100644
index 000000000..6a3173e3e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-74134.public.stderr
@@ -0,0 +1,11 @@
+warning: public documentation for `public_item` links to private item `PrivateType`
+ --> $DIR/issue-74134.rs:19:11
+ |
+LL | /// [`PrivateType`]
+ | ^^^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs
new file mode 100644
index 000000000..b1be9123a
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-74134.rs
@@ -0,0 +1,41 @@
+// revisions: public private
+// [private]compile-flags: --document-private-items
+// check-pass
+
+// There are 4 cases here:
+// 1. public item -> public type: no warning
+// 2. public item -> private type: warning
+// 3. private item -> public type: no warning
+// 4. private item -> private type: no warning
+// All 4 cases are tested with and without --document-private-items.
+//
+// Case 4 without --document-private-items is the one described in issue #74134.
+
+struct PrivateType;
+pub struct PublicType;
+
+pub struct Public {
+ /// [`PublicType`]
+ /// [`PrivateType`]
+ //~^ WARNING public documentation for `public_item` links to private item `PrivateType`
+ pub public_item: u32,
+
+ /// [`PublicType`]
+ /// [`PrivateType`]
+ private_item: u32,
+}
+
+// The following cases are identical to the ones above, except that they are in a private
+// module. Thus they all fall into cases 3 and 4 and should not produce a warning.
+
+mod private {
+ pub struct Public {
+ /// [`super::PublicType`]
+ /// [`super::PrivateType`]
+ pub public_item: u32,
+
+ /// [`super::PublicType`]
+ /// [`super::PrivateType`]
+ private_item: u32,
+ }
+}
diff --git a/src/test/rustdoc-ui/issue-79465.rs b/src/test/rustdoc-ui/issue-79465.rs
new file mode 100644
index 000000000..f1a77982f
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79465.rs
@@ -0,0 +1,3 @@
+pub fn f1<T>(x: T::A) {}
+//~^ ERROR
+//~^^ ERROR
diff --git a/src/test/rustdoc-ui/issue-79465.stderr b/src/test/rustdoc-ui/issue-79465.stderr
new file mode 100644
index 000000000..489cc1442
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79465.stderr
@@ -0,0 +1,15 @@
+error[E0220]: associated type `A` not found for `T`
+ --> $DIR/issue-79465.rs:1:20
+ |
+LL | pub fn f1<T>(x: T::A) {}
+ | ^ associated type `A` not found
+
+error[E0220]: associated type `A` not found for `T`
+ --> $DIR/issue-79465.rs:1:20
+ |
+LL | pub fn f1<T>(x: T::A) {}
+ | ^ associated type `A` not found
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/rustdoc-ui/issue-79467.rs b/src/test/rustdoc-ui/issue-79467.rs
new file mode 100644
index 000000000..eb0b9b380
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79467.rs
@@ -0,0 +1,8 @@
+fn g()
+where
+ 'static: 'static,
+ dyn 'static: 'static + Copy, //~ ERROR at least one trait is required for an object type
+{
+}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/issue-79467.stderr b/src/test/rustdoc-ui/issue-79467.stderr
new file mode 100644
index 000000000..561513a43
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79467.stderr
@@ -0,0 +1,9 @@
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/issue-79467.rs:4:5
+ |
+LL | dyn 'static: 'static + Copy,
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/rustdoc-ui/issue-79494.rs b/src/test/rustdoc-ui/issue-79494.rs
new file mode 100644
index 000000000..fc39424b7
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79494.rs
@@ -0,0 +1,5 @@
+// only-x86_64-unknown-linux-gnu
+
+#![feature(const_transmute)]
+
+const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types
diff --git a/src/test/rustdoc-ui/issue-79494.stderr b/src/test/rustdoc-ui/issue-79494.stderr
new file mode 100644
index 000000000..7ed5ed382
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79494.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+ --> $DIR/issue-79494.rs:5:29
+ |
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: source type: `usize` (64 bits)
+ = note: target type: `&[u8]` (128 bits)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/src/test/rustdoc-ui/issue-80992.rs b/src/test/rustdoc-ui/issue-80992.rs
new file mode 100644
index 000000000..8983439bb
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-80992.rs
@@ -0,0 +1,11 @@
+// check-pass
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+pub fn test() -> Result<(), ()> {
+ //! ```compile_fail
+ //! fn test() -> Result< {}
+ //! ```
+ Ok(())
+}
diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout
new file mode 100644
index 000000000..d2b1cd1d5
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-80992.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/issue-81662-shortness.rs b/src/test/rustdoc-ui/issue-81662-shortness.rs
new file mode 100644
index 000000000..27a21a313
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-81662-shortness.rs
@@ -0,0 +1,12 @@
+// compile-flags:--test --error-format=short
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+/// ```rust
+/// foo();
+/// ```
+//~^^ ERROR cannot find function `foo` in this scope
+fn foo() {
+ println!("Hello, world!");
+}
diff --git a/src/test/rustdoc-ui/issue-81662-shortness.stdout b/src/test/rustdoc-ui/issue-81662-shortness.stdout
new file mode 100644
index 000000000..748113be3
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-81662-shortness.stdout
@@ -0,0 +1,16 @@
+
+running 1 test
+test $DIR/issue-81662-shortness.rs - foo (line 6) ... FAILED
+
+failures:
+
+---- $DIR/issue-81662-shortness.rs - foo (line 6) stdout ----
+$DIR/issue-81662-shortness.rs:7:1: error[E0425]: cannot find function `foo` in this scope
+error: aborting due to previous error
+Couldn't compile the test.
+
+failures:
+ $DIR/issue-81662-shortness.rs - foo (line 6)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.rs b/src/test/rustdoc-ui/issue-83883-describe-lints.rs
new file mode 100644
index 000000000..0474d6c14
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-83883-describe-lints.rs
@@ -0,0 +1,10 @@
+// compile-flags: -W help
+// check-pass
+// check-stdout
+// error-pattern:Lint checks provided
+// error-pattern:rustdoc::broken-intra-doc-links
+//
+// ignore-tidy-linelength
+//
+// normalize-stdout-test: "( +name default meaning\n +---- ------- -------\n)?( *[[:word:]:-]+ (allow |warn |deny |forbid ) [^\n]+\n)+" -> " $$NAMES $$LEVELS $$MEANINGS"
+// normalize-stdout-test: " +name sub-lints\n +---- ---------\n( *[[:word:]:-]+ [^\n]+\n)+" -> " $$NAMES $$SUB_LINTS"
diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout
new file mode 100644
index 000000000..bbf66a315
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout
@@ -0,0 +1,24 @@
+
+Available lint options:
+ -W <foo> Warn about <foo>
+ -A <foo> Allow <foo>
+ -D <foo> Deny <foo>
+ -F <foo> Forbid <foo> (deny <foo> and all attempts to override)
+
+
+Lint checks provided by rustc:
+
+ $NAMES $LEVELS $MEANINGS
+
+Lint groups provided by rustc:
+
+ $NAMES $SUB_LINTS
+
+Lint checks provided by plugins loaded by this crate:
+
+ $NAMES $LEVELS $MEANINGS
+
+Lint groups provided by plugins loaded by this crate:
+
+ $NAMES $SUB_LINTS
+
diff --git a/src/test/rustdoc-ui/issue-91134.rs b/src/test/rustdoc-ui/issue-91134.rs
new file mode 100644
index 000000000..d2ff3a252
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91134.rs
@@ -0,0 +1,14 @@
+// compile-flags: --test --crate-name=empty_fn --extern=empty_fn --test-args=--test-threads=1
+// aux-build:empty-fn.rs
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// edition:2021
+
+/// <https://github.com/rust-lang/rust/issues/91134>
+///
+/// ```
+/// extern crate empty_fn;
+/// empty_fn::empty();
+/// ```
+pub struct Something;
diff --git a/src/test/rustdoc-ui/issue-91134.stdout b/src/test/rustdoc-ui/issue-91134.stdout
new file mode 100644
index 000000000..084062743
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91134.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/issue-91134.rs - Something (line 10) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/issue-91713.rs b/src/test/rustdoc-ui/issue-91713.rs
new file mode 100644
index 000000000..610bbf11d
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.rs
@@ -0,0 +1,3 @@
+// check-pass
+// compile-flags: --passes list
+// error-pattern: the `passes` flag no longer functions
diff --git a/src/test/rustdoc-ui/issue-91713.stderr b/src/test/rustdoc-ui/issue-91713.stderr
new file mode 100644
index 000000000..44ead7a1d
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stderr
@@ -0,0 +1,5 @@
+warning: the `passes` flag no longer functions
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+ = help: you may want to use --document-private-items
+
diff --git a/src/test/rustdoc-ui/issue-91713.stdout b/src/test/rustdoc-ui/issue-91713.stdout
new file mode 100644
index 000000000..a19e452b4
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stdout
@@ -0,0 +1,29 @@
+Available passes for running rustdoc:
+check_doc_test_visibility - run various visibility-related lints on doctests
+ strip-hidden - strips all `#[doc(hidden)]` items from the output
+ strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
+ strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
+ propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
+collect-intra-doc-links - resolves intra-doc links
+check-code-block-syntax - validates syntax inside Rust code blocks
+ collect-trait-impls - retrieves trait impls for items in the crate
+calculate-doc-coverage - counts the number of items with and without documentation
+check-invalid-html-tags - detects invalid HTML tags in doc comments
+ check-bare-urls - detects URLs that are not hyperlinks
+
+Default passes for rustdoc:
+ collect-trait-impls
+check_doc_test_visibility
+ strip-hidden (when not --document-hidden-items)
+ strip-private (when not --document-private-items)
+ strip-priv-imports (when --document-private-items)
+collect-intra-doc-links
+check-code-block-syntax
+check-invalid-html-tags
+ propagate-doc-cfg
+ check-bare-urls
+
+Passes run with `--show-coverage`:
+ strip-hidden (when not --document-hidden-items)
+ strip-private (when not --document-private-items)
+calculate-doc-coverage
diff --git a/src/test/rustdoc-ui/issue-98690.rs b/src/test/rustdoc-ui/issue-98690.rs
new file mode 100644
index 000000000..fe9bd87ab
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-98690.rs
@@ -0,0 +1,10 @@
+// compile-flags: --test --persist-doctests /../../ -Z unstable-options
+// failure-status: 101
+// only-linux
+
+#![crate_name = "foo"]
+
+//! ```rust
+//! use foo::dummy;
+//! dummy();
+//! ```
diff --git a/src/test/rustdoc-ui/issue-98690.stderr b/src/test/rustdoc-ui/issue-98690.stderr
new file mode 100644
index 000000000..47d94f99a
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-98690.stderr
@@ -0,0 +1 @@
+Couldn't create directory for doctest executables: Permission denied (os error 13)
diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs
new file mode 100644
index 000000000..61555a6e6
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-group.rs
@@ -0,0 +1,29 @@
+//! Documenting the kinds of lints emitted by rustdoc.
+//!
+//! ```
+//! println!("sup");
+//! ```
+
+#![deny(rustdoc::all)]
+
+/// what up, let's make an [error]
+///
+/// ```
+/// println!("sup");
+/// ```
+pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error`
+
+/// wait, this doesn't have a doctest?
+pub fn no_doctest() {} //~^ ERROR missing code example in this documentation
+
+/// wait, this *does* have a doctest?
+///
+/// ```
+/// println!("sup");
+/// ```
+fn private_doctest() {} //~^^^^^ ERROR documentation test in private item
+
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+//~^^ ERROR missing code example
+pub fn c() {}
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
new file mode 100644
index 000000000..e28600160
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -0,0 +1,50 @@
+error: missing code example in this documentation
+ --> $DIR/lint-group.rs:16:1
+ |
+LL | /// wait, this doesn't have a doctest?
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/lint-group.rs:7:9
+ |
+LL | #![deny(rustdoc::all)]
+ | ^^^^^^^^^^^^
+ = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]`
+
+error: documentation test in private item
+ --> $DIR/lint-group.rs:19:1
+ |
+LL | / /// wait, this *does* have a doctest?
+LL | | ///
+LL | | /// ```
+LL | | /// println!("sup");
+LL | | /// ```
+ | |_______^
+ |
+ = note: `#[deny(rustdoc::private_doc_tests)]` implied by `#[deny(rustdoc::all)]`
+
+error: missing code example in this documentation
+ --> $DIR/lint-group.rs:26:1
+ |
+LL | /// <unknown>
+ | ^^^^^^^^^^^^^
+
+error: unresolved link to `error`
+ --> $DIR/lint-group.rs:9:29
+ |
+LL | /// what up, let's make an [error]
+ | ^^^^^ no item named `error` in scope
+ |
+ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(rustdoc::all)]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unclosed HTML tag `unknown`
+ --> $DIR/lint-group.rs:26:5
+ |
+LL | /// <unknown>
+ | ^^^^^^^^^
+ |
+ = note: `#[deny(rustdoc::invalid_html_tags)]` implied by `#[deny(rustdoc::all)]`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
new file mode 100644
index 000000000..fac6342cd
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
@@ -0,0 +1,100 @@
+#![deny(missing_docs)]
+#![deny(rustdoc::missing_doc_code_examples)]
+
+//! crate level doc
+//! ```
+//! println!("hello"):
+//! ```
+
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+pub fn test() {
+}
+
+#[allow(missing_docs)]
+pub mod module1 { //~ ERROR
+}
+
+#[allow(rustdoc::missing_doc_code_examples)]
+/// doc
+pub mod module2 {
+
+ /// doc
+ pub fn test() {}
+}
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+pub mod module3 {
+
+ /// doc
+ //~^ ERROR
+ pub fn test() {}
+}
+
+/// Doc, but no code example and it's fine!
+pub const Const: u32 = 0;
+/// Doc, but no code example and it's fine!
+pub static Static: u32 = 0;
+/// Doc, but no code example and it's fine!
+pub type Type = u32;
+
+/// Doc
+//~^ ERROR
+pub struct Struct {
+ /// Doc, but no code example and it's fine!
+ pub field: u32,
+}
+
+/// Doc
+//~^ ERROR
+pub enum Enum {
+ /// Doc, but no code example and it's fine!
+ X,
+}
+
+/// Doc
+//~^ ERROR
+#[repr(C)]
+pub union Union {
+ /// Doc, but no code example and it's fine!
+ a: i32,
+ /// Doc, but no code example and it's fine!
+ b: f32,
+}
+
+// no code example and it's fine!
+impl Clone for Struct {
+ fn clone(&self) -> Self {
+ Self { field: self.field }
+ }
+}
+
+
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+#[derive(Clone)]
+pub struct NiceStruct;
+
+#[doc(hidden)]
+pub mod foo {
+ pub fn bar() {}
+}
+
+fn babar() {}
+
+
+mod fofoo {
+ pub fn tadam() {}
+}
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
new file mode 100644
index 000000000..9e51ecd2b
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
@@ -0,0 +1,38 @@
+error: missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:19:1
+ |
+LL | pub mod module1 {
+ | ^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/lint-missing-doc-code-example.rs:2:9
+ |
+LL | #![deny(rustdoc::missing_doc_code_examples)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:37:3
+ |
+LL | /// doc
+ | ^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:49:1
+ |
+LL | /// Doc
+ | ^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:56:1
+ |
+LL | /// Doc
+ | ^^^^^^^
+
+error: missing code example in this documentation
+ --> $DIR/lint-missing-doc-code-example.rs:63:1
+ |
+LL | /// Doc
+ | ^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/rustdoc-ui/macro-docs.rs b/src/test/rustdoc-ui/macro-docs.rs
new file mode 100644
index 000000000..0e8472eb2
--- /dev/null
+++ b/src/test/rustdoc-ui/macro-docs.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+macro_rules! m {
+ () => {
+ /// A
+ //~^ WARNING
+ #[path = "auxiliary/module_macro_doc.rs"]
+ pub mod mymodule;
+ }
+}
+
+m!();
diff --git a/src/test/rustdoc-ui/macro-docs.stderr b/src/test/rustdoc-ui/macro-docs.stderr
new file mode 100644
index 000000000..e3cc17311
--- /dev/null
+++ b/src/test/rustdoc-ui/macro-docs.stderr
@@ -0,0 +1,20 @@
+warning: unresolved link to `long_cat`
+ --> $DIR/macro-docs.rs:5:9
+ |
+LL | /// A
+ | ^^^^^
+...
+LL | m!();
+ | ---- in this macro invocation
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+ = note: the link appears in this line:
+
+ [`long_cat`] is really long
+ ^^^^^^^^^^
+ = note: no item named `long_cat` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+ = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/macro-docs.stdout b/src/test/rustdoc-ui/macro-docs.stdout
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/test/rustdoc-ui/macro-docs.stdout
diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs
new file mode 100644
index 000000000..a186410ac
--- /dev/null
+++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs
@@ -0,0 +1,6 @@
+// error-pattern: no documentation found
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+#![deny(rustdoc::missing_crate_level_docs)]
+//^~ NOTE defined here
+
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr
new file mode 100644
index 000000000..1a1f8085a
--- /dev/null
+++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr
@@ -0,0 +1,12 @@
+error: no documentation found for this crate's top-level module
+ |
+note: the lint level is defined here
+ --> $DIR/no-crate-level-doc-lint.rs:3:9
+ |
+LL | #![deny(rustdoc::missing_crate_level_docs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: The following guide may be of use:
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/no-run-flag-error.rs b/src/test/rustdoc-ui/no-run-flag-error.rs
new file mode 100644
index 000000000..4ead62148
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag-error.rs
@@ -0,0 +1,6 @@
+// test the behavior of the --no-run flag without the --test flag
+
+// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1
+// error-pattern: the `--test` flag must be passed
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag-error.stderr b/src/test/rustdoc-ui/no-run-flag-error.stderr
new file mode 100644
index 000000000..d032646c3
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag-error.stderr
@@ -0,0 +1,2 @@
+error: the `--test` flag must be passed to enable `--no-run`
+
diff --git a/src/test/rustdoc-ui/no-run-flag.rs b/src/test/rustdoc-ui/no-run-flag.rs
new file mode 100644
index 000000000..da1672c4a
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag.rs
@@ -0,0 +1,38 @@
+// test the behavior of the --no-run flag
+
+// check-pass
+// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+/// println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+/// Ok the test does not run
+/// ```
+/// panic!()
+/// ```
+/// Ok the test does not run
+/// ```should_panic
+/// loop {
+/// println!("Hello, world");
+/// panic!()
+/// }
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout
new file mode 100644
index 000000000..02f28aaf6
--- /dev/null
+++ b/src/test/rustdoc-ui/no-run-flag.stdout
@@ -0,0 +1,12 @@
+
+running 7 tests
+test $DIR/no-run-flag.rs - f (line 11) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 14) ... ignored
+test $DIR/no-run-flag.rs - f (line 17) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok
+test $DIR/no-run-flag.rs - f (line 28) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 32) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 8) - compile ... ok
+
+test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/nocapture-fail.rs b/src/test/rustdoc-ui/nocapture-fail.rs
new file mode 100644
index 000000000..7706bd1f3
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture-fail.rs
@@ -0,0 +1,12 @@
+// check-pass
+// compile-flags:--test -Zunstable-options --nocapture
+// normalize-stderr-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```compile_fail
+/// fn foo() {
+/// Input: 123
+/// }
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/nocapture-fail.stderr b/src/test/rustdoc-ui/nocapture-fail.stderr
new file mode 100644
index 000000000..b65b622c1
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture-fail.stderr
@@ -0,0 +1,18 @@
+error: struct literal body without path
+ --> $DIR/nocapture-fail.rs:8:10
+ |
+LL | fn foo() {
+ | __________^
+LL | | Input: 123
+LL | | }
+ | |_^
+ |
+help: you might have forgotten to add the struct literal inside the block
+ |
+LL ~ fn foo() { SomeStruct {
+LL | Input: 123
+LL ~ } }
+ |
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/nocapture-fail.stdout b/src/test/rustdoc-ui/nocapture-fail.stdout
new file mode 100644
index 000000000..754f77db5
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture-fail.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/nocapture-fail.rs - Foo (line 7) - compile fail ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/nocapture.rs b/src/test/rustdoc-ui/nocapture.rs
new file mode 100644
index 000000000..321f5ca08
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture.rs
@@ -0,0 +1,10 @@
+// check-pass
+// compile-flags:--test -Zunstable-options --nocapture
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// println!("hello!");
+/// eprintln!("stderr");
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/nocapture.stderr b/src/test/rustdoc-ui/nocapture.stderr
new file mode 100644
index 000000000..af6415db3
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture.stderr
@@ -0,0 +1 @@
+stderr
diff --git a/src/test/rustdoc-ui/nocapture.stdout b/src/test/rustdoc-ui/nocapture.stdout
new file mode 100644
index 000000000..4880e75da
--- /dev/null
+++ b/src/test/rustdoc-ui/nocapture.stdout
@@ -0,0 +1,7 @@
+
+running 1 test
+hello!
+test $DIR/nocapture.rs - Foo (line 6) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs
new file mode 100644
index 000000000..f48cad373
--- /dev/null
+++ b/src/test/rustdoc-ui/normalize-cycle.rs
@@ -0,0 +1,25 @@
+// check-pass
+// Regresion test for <https://github.com/rust-lang/rust/issues/79459>.
+pub trait Query {}
+
+pub trait AsQuery {
+ type Query;
+}
+
+impl<T: Query> AsQuery for T {
+ type Query = T;
+}
+
+pub trait SelectDsl<Selection> {
+ type Output;
+}
+
+impl<T, Selection> SelectDsl<Selection> for T
+where
+ T: AsQuery,
+ T::Query: SelectDsl<Selection>,
+{
+ type Output = <T::Query as SelectDsl<Selection>>::Output;
+}
+
+pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output;
diff --git a/src/test/rustdoc-ui/normalize-overflow.rs b/src/test/rustdoc-ui/normalize-overflow.rs
new file mode 100644
index 000000000..0cdcc88e3
--- /dev/null
+++ b/src/test/rustdoc-ui/normalize-overflow.rs
@@ -0,0 +1,3 @@
+// aux-crate:overflow=overflow.rs
+// check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/79506>.
diff --git a/src/test/rustdoc-ui/output-format-html-stable.rs b/src/test/rustdoc-ui/output-format-html-stable.rs
new file mode 100644
index 000000000..fa0362640
--- /dev/null
+++ b/src/test/rustdoc-ui/output-format-html-stable.rs
@@ -0,0 +1,4 @@
+// compile-flags: --output-format html
+// check-pass
+// This tests that `--output-format html` is accepted without `-Z unstable-options`,
+// since it has been stable since 1.0.
diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs
new file mode 100644
index 000000000..a1f9f8dca
--- /dev/null
+++ b/src/test/rustdoc-ui/private-doc-test.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```ignore (used for testing ignored doc tests)
+ /// assert!(false);
+ /// ```
+ fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/private-item-doc-test.rs b/src/test/rustdoc-ui/private-item-doc-test.rs
new file mode 100644
index 000000000..1a3d6cc63
--- /dev/null
+++ b/src/test/rustdoc-ui/private-item-doc-test.rs
@@ -0,0 +1,11 @@
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```
+ /// assert!(false);
+ /// ```
+ //~^^^^^ ERROR documentation test in private item
+ fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr
new file mode 100644
index 000000000..5df613298
--- /dev/null
+++ b/src/test/rustdoc-ui/private-item-doc-test.stderr
@@ -0,0 +1,18 @@
+error: documentation test in private item
+ --> $DIR/private-item-doc-test.rs:4:5
+ |
+LL | / /// private doc test
+LL | | ///
+LL | | /// ```
+LL | | /// assert!(false);
+LL | | /// ```
+ | |___________^
+ |
+note: the lint level is defined here
+ --> $DIR/private-item-doc-test.rs:1:9
+ |
+LL | #![deny(rustdoc::private_doc_tests)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.rs b/src/test/rustdoc-ui/private-public-item-doc-test.rs
new file mode 100644
index 000000000..7cc62b38c
--- /dev/null
+++ b/src/test/rustdoc-ui/private-public-item-doc-test.rs
@@ -0,0 +1,11 @@
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```
+ /// assert!(false);
+ /// ```
+ //~^^^^^ ERROR documentation test in private item
+ pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.stderr b/src/test/rustdoc-ui/private-public-item-doc-test.stderr
new file mode 100644
index 000000000..f50dbd184
--- /dev/null
+++ b/src/test/rustdoc-ui/private-public-item-doc-test.stderr
@@ -0,0 +1,18 @@
+error: documentation test in private item
+ --> $DIR/private-public-item-doc-test.rs:4:5
+ |
+LL | / /// private doc test
+LL | | ///
+LL | | /// ```
+LL | | /// assert!(false);
+LL | | /// ```
+ | |___________^
+ |
+note: the lint level is defined here
+ --> $DIR/private-public-item-doc-test.rs:1:9
+ |
+LL | #![deny(rustdoc::private_doc_tests)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/pub-export-lint.rs b/src/test/rustdoc-ui/pub-export-lint.rs
new file mode 100644
index 000000000..f2e66b77b
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.rs
@@ -0,0 +1,5 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// [aloha]
+//~^ ERROR unresolved link to `aloha`
+pub use std::task::RawWakerVTable;
diff --git a/src/test/rustdoc-ui/pub-export-lint.stderr b/src/test/rustdoc-ui/pub-export-lint.stderr
new file mode 100644
index 000000000..c6be9c6a9
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `aloha`
+ --> $DIR/pub-export-lint.rs:3:6
+ |
+LL | /// [aloha]
+ | ^^^^^ no item named `aloha` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/pub-export-lint.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/public-reexported-item-doc-test.rs b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs
new file mode 100644
index 000000000..b86a53305
--- /dev/null
+++ b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+pub fn foo() {}
+
+mod private {
+ /// re-exported doc test
+ ///
+ /// ```
+ /// assert!(true);
+ /// ```
+ pub fn bar() {}
+}
+
+pub use private::bar;
diff --git a/src/test/rustdoc-ui/range-pattern.rs b/src/test/rustdoc-ui/range-pattern.rs
new file mode 100644
index 000000000..fd255d02f
--- /dev/null
+++ b/src/test/rustdoc-ui/range-pattern.rs
@@ -0,0 +1,3 @@
+// check-pass
+
+fn func(0u8..=255: u8) {}
diff --git a/src/test/rustdoc-ui/recursive-deref-ice.rs b/src/test/rustdoc-ui/recursive-deref-ice.rs
new file mode 100644
index 000000000..c44fd27f4
--- /dev/null
+++ b/src/test/rustdoc-ui/recursive-deref-ice.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+// ICE found in https://github.com/rust-lang/rust/issues/83123
+
+pub struct Attribute;
+
+pub struct Map<'hir> {}
+impl<'hir> Map<'hir> {
+ pub fn attrs(&self) -> &'hir [Attribute] { &[] }
+}
+
+pub struct List<T>(T);
+
+impl<T> std::ops::Deref for List<T> {
+ type Target = [T];
+ fn deref(&self) -> &[T] {
+ &[]
+ }
+}
diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.rs b/src/test/rustdoc-ui/reference-link-reports-error-once.rs
new file mode 100644
index 000000000..71bd2c522
--- /dev/null
+++ b/src/test/rustdoc-ui/reference-link-reports-error-once.rs
@@ -0,0 +1,20 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// Links to [a] [link][a]
+/// And also a [third link][a]
+/// And also a [reference link][b]
+///
+/// Other links to the same target should still emit error: [ref] //~ERROR unresolved link to `ref`
+/// Duplicate [ref] //~ERROR unresolved link to `ref`
+///
+/// Other links to other targets should still emit error: [ref2] //~ERROR unresolved link to `ref2`
+/// Duplicate [ref2] //~ERROR unresolved link to `ref2`
+///
+/// [a]: ref
+//~^ ERROR unresolved link to `ref`
+/// [b]: ref2
+//~^ ERROR unresolved link to
+
+/// [ref][]
+//~^ ERROR unresolved link
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.stderr b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr
new file mode 100644
index 000000000..b46a51e93
--- /dev/null
+++ b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr
@@ -0,0 +1,63 @@
+error: unresolved link to `ref`
+ --> $DIR/reference-link-reports-error-once.rs:13:10
+ |
+LL | /// [a]: ref
+ | ^^^ no item named `ref` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/reference-link-reports-error-once.rs:1:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref2`
+ --> $DIR/reference-link-reports-error-once.rs:15:10
+ |
+LL | /// [b]: ref2
+ | ^^^^ no item named `ref2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref`
+ --> $DIR/reference-link-reports-error-once.rs:7:62
+ |
+LL | /// Other links to the same target should still emit error: [ref]
+ | ^^^ no item named `ref` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref`
+ --> $DIR/reference-link-reports-error-once.rs:8:16
+ |
+LL | /// Duplicate [ref]
+ | ^^^ no item named `ref` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref2`
+ --> $DIR/reference-link-reports-error-once.rs:10:60
+ |
+LL | /// Other links to other targets should still emit error: [ref2]
+ | ^^^^ no item named `ref2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref2`
+ --> $DIR/reference-link-reports-error-once.rs:11:16
+ |
+LL | /// Duplicate [ref2]
+ | ^^^^ no item named `ref2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `ref`
+ --> $DIR/reference-link-reports-error-once.rs:18:6
+ |
+LL | /// [ref][]
+ | ^^^ no item named `ref` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/rustdoc-ui/reference-links.rs b/src/test/rustdoc-ui/reference-links.rs
new file mode 100644
index 000000000..e81e03446
--- /dev/null
+++ b/src/test/rustdoc-ui/reference-links.rs
@@ -0,0 +1,6 @@
+// Test that errors point to the reference, not to the title text.
+#![deny(rustdoc::broken_intra_doc_links)]
+//! Links to [a] [link][a]
+//!
+//! [a]: std::process::Comman
+//~^ ERROR unresolved
diff --git a/src/test/rustdoc-ui/reference-links.stderr b/src/test/rustdoc-ui/reference-links.stderr
new file mode 100644
index 000000000..c98a2fd7c
--- /dev/null
+++ b/src/test/rustdoc-ui/reference-links.stderr
@@ -0,0 +1,14 @@
+error: unresolved link to `std::process::Comman`
+ --> $DIR/reference-links.rs:5:10
+ |
+LL | //! [a]: std::process::Comman
+ | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process`
+ |
+note: the lint level is defined here
+ --> $DIR/reference-links.rs:2:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.rs b/src/test/rustdoc-ui/renamed-lint-still-applies.rs
new file mode 100644
index 000000000..a4d3a4b49
--- /dev/null
+++ b/src/test/rustdoc-ui/renamed-lint-still-applies.rs
@@ -0,0 +1,10 @@
+// compile-args: --crate-type lib
+#![deny(broken_intra_doc_links)]
+//~^ WARNING renamed to `rustdoc::broken_intra_doc_links`
+//! [x]
+//~^ ERROR unresolved link
+
+#![deny(rustdoc::non_autolinks)]
+//~^ WARNING renamed to `rustdoc::bare_urls`
+//! http://example.com
+//~^ ERROR not a hyperlink
diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.stderr b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr
new file mode 100644
index 000000000..8e2a2cdd7
--- /dev/null
+++ b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr
@@ -0,0 +1,42 @@
+warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links`
+ --> $DIR/renamed-lint-still-applies.rs:2:9
+ |
+LL | #![deny(broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links`
+ |
+ = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
+ --> $DIR/renamed-lint-still-applies.rs:7:9
+ |
+LL | #![deny(rustdoc::non_autolinks)]
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+
+error: unresolved link to `x`
+ --> $DIR/renamed-lint-still-applies.rs:4:6
+ |
+LL | //! [x]
+ | ^ no item named `x` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/renamed-lint-still-applies.rs:2:9
+ |
+LL | #![deny(broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: this URL is not a hyperlink
+ --> $DIR/renamed-lint-still-applies.rs:9:5
+ |
+LL | //! http://example.com
+ | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
+ |
+note: the lint level is defined here
+ --> $DIR/renamed-lint-still-applies.rs:7:9
+ |
+LL | #![deny(rustdoc::non_autolinks)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: bare URLs are not automatically turned into clickable links
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
diff --git a/src/test/rustdoc-ui/run-directory.correct.stdout b/src/test/rustdoc-ui/run-directory.correct.stdout
new file mode 100644
index 000000000..e9b275479
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.correct.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/run-directory.rs - foo (line 10) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/run-directory.incorrect.stdout b/src/test/rustdoc-ui/run-directory.incorrect.stdout
new file mode 100644
index 000000000..97a5dbc5c
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.incorrect.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/run-directory.rs - foo (line 19) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs
new file mode 100644
index 000000000..0d432c1e6
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.rs
@@ -0,0 +1,23 @@
+// this test asserts that the cwd of doctest invocations is set correctly.
+
+// revisions: correct incorrect
+// check-pass
+// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options
+// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// assert_eq!(
+/// std::fs::read_to_string("run-directory.rs").unwrap(),
+/// include_str!("run-directory.rs"),
+/// );
+/// ```
+#[cfg(correct)]
+pub fn foo() {}
+
+/// ```
+/// assert!(std::fs::read_to_string("run-directory.rs").is_err());
+/// ```
+#[cfg(incorrect)]
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/rustc-check-passes.rs b/src/test/rustdoc-ui/rustc-check-passes.rs
new file mode 100644
index 000000000..731cc8ba6
--- /dev/null
+++ b/src/test/rustdoc-ui/rustc-check-passes.rs
@@ -0,0 +1,4 @@
+#![feature(box_syntax)]
+#![feature(box_syntax)] //~ ERROR
+
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/rustc-check-passes.stderr b/src/test/rustdoc-ui/rustc-check-passes.stderr
new file mode 100644
index 000000000..9707895ff
--- /dev/null
+++ b/src/test/rustdoc-ui/rustc-check-passes.stderr
@@ -0,0 +1,9 @@
+error[E0636]: the feature `box_syntax` has already been declared
+ --> $DIR/rustc-check-passes.rs:2:12
+ |
+LL | #![feature(box_syntax)]
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0636`.
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs
new file mode 100644
index 000000000..8f4fde96d
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs
@@ -0,0 +1,7 @@
+// check-fail
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+
+pub fn foo() {
+ INVALID_FUNC();
+ //~^ ERROR could not resolve path
+}
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr
new file mode 100644
index 000000000..750aa3207
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: could not resolve path `INVALID_FUNC`
+ --> $DIR/scrape-examples-fail-if-type-error.rs:5:3
+ |
+LL | INVALID_FUNC();
+ | ^^^^^^^^^^^^ could not resolve path `INVALID_FUNC`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/scrape-examples-ice.rs b/src/test/rustdoc-ui/scrape-examples-ice.rs
new file mode 100644
index 000000000..d629b62a7
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-ice.rs
@@ -0,0 +1,4 @@
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+// check-pass
+#![no_std]
+use core as _;
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs
new file mode 100644
index 000000000..a1f005c32
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr
new file mode 100644
index 000000000..eb8e9f799
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs
new file mode 100644
index 000000000..4aacec7f0
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr
new file mode 100644
index 000000000..eb8e9f799
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
new file mode 100644
index 000000000..ce51556dd
--- /dev/null
+++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+// Minimization of issue #59502
+
+trait MyTrait<T> {
+ type Output;
+}
+
+pub fn pow<T: MyTrait<T, Output = T>>(arg: T) -> T {
+ arg
+}
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs
new file mode 100644
index 000000000..744b3071f
--- /dev/null
+++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs
@@ -0,0 +1,38 @@
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<32> thing!
+// Numbers aren't valid HTML tags, so no error.
+pub struct ConstGeneric;
+
+/// This Vec<i32, i32> thing!
+// HTML tags cannot contain commas, so no error.
+pub struct MultipleGenerics;
+
+/// This Vec<i32 class="test"> thing!
+//~^ERROR unclosed HTML tag `i32`
+// HTML attributes shouldn't be treated as Rust syntax, so no suggestions.
+pub struct TagWithAttributes;
+
+/// This Vec<i32></i32> thing!
+// There should be no error, and no suggestion, since the tags are balanced.
+pub struct DoNotWarnOnMatchingTags;
+
+/// This Vec</i32> thing!
+//~^ERROR unopened HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct EndTagsAreNotValidRustSyntax;
+
+/// This 123<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct NumbersAreNotPaths;
+
+/// This Vec:<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct InvalidTurbofish;
+
+/// This [link](https://rust-lang.org)<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct BareTurbofish;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr
new file mode 100644
index 000000000..832b8b2ca
--- /dev/null
+++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr
@@ -0,0 +1,38 @@
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:11:13
+ |
+LL | /// This Vec<i32 class="test"> thing!
+ | ^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-no-suggestions.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unopened HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:20:13
+ |
+LL | /// This Vec</i32> thing!
+ | ^^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:25:13
+ |
+LL | /// This 123<i32> thing!
+ | ^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:30:14
+ |
+LL | /// This Vec:<i32> thing!
+ | ^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:35:39
+ |
+LL | /// This [link](https://rust-lang.org)<i32> thing!
+ | ^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.fixed b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed
new file mode 100644
index 000000000..c0a0de24c
--- /dev/null
+++ b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed
@@ -0,0 +1,32 @@
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This `Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This `vec::Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This `i32<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This `Vec::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)`::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>`Vec::<i32>`</span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.rs b/src/test/rustdoc-ui/suggestions/html-as-generics.rs
new file mode 100644
index 000000000..0b6009b0e
--- /dev/null
+++ b/src/test/rustdoc-ui/suggestions/html-as-generics.rs
@@ -0,0 +1,32 @@
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This vec::Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This i32<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This Vec::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>Vec::<i32></span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr
new file mode 100644
index 000000000..df54b7126
--- /dev/null
+++ b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr
@@ -0,0 +1,73 @@
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:4:13
+ |
+LL | /// This Vec<i32> thing!
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics.rs:2:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try marking as source code
+ |
+LL | /// This `Vec<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:9:18
+ |
+LL | /// This vec::Vec<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `vec::Vec<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:14:13
+ |
+LL | /// This i32<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `i32<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:19:15
+ |
+LL | /// This Vec::<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `Vec::<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:24:41
+ |
+LL | /// This [link](https://rust-lang.org)::<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [link](https://rust-lang.org)`::<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:29:21
+ |
+LL | /// This <span>Vec::<i32></span> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This <span>`Vec::<i32>`</span> thing!
+ | + +
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/rustdoc-ui/test-compile-fail1.rs b/src/test/rustdoc-ui/test-compile-fail1.rs
new file mode 100644
index 000000000..a05390238
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail1.rs
@@ -0,0 +1,8 @@
+// compile-flags:--test
+
+/// ```
+/// assert!(true)
+/// ```
+pub fn f() {}
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-compile-fail1.stderr b/src/test/rustdoc-ui/test-compile-fail1.stderr
new file mode 100644
index 000000000..72915e46b
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail1.stderr
@@ -0,0 +1,14 @@
+error[E0428]: the name `f` is defined multiple times
+ --> $DIR/test-compile-fail1.rs:8:1
+ |
+6 | pub fn f() {}
+ | ---------- previous definition of the value `f` here
+7 |
+8 | pub fn f() {}
+ | ^^^^^^^^^^ `f` redefined here
+ |
+ = note: `f` must be defined only once in the value namespace of this module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/rustdoc-ui/test-compile-fail2.rs b/src/test/rustdoc-ui/test-compile-fail2.rs
new file mode 100644
index 000000000..651ded0a0
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail2.rs
@@ -0,0 +1,3 @@
+// compile-flags:--test
+
+fail
diff --git a/src/test/rustdoc-ui/test-compile-fail2.stderr b/src/test/rustdoc-ui/test-compile-fail2.stderr
new file mode 100644
index 000000000..cee5b63cf
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail2.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found `<eof>`
+ --> $DIR/test-compile-fail2.rs:3:1
+ |
+3 | fail
+ | ^^^^ expected one of `!` or `::`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/test-compile-fail3.rs b/src/test/rustdoc-ui/test-compile-fail3.rs
new file mode 100644
index 000000000..faa30ad83
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail3.rs
@@ -0,0 +1,3 @@
+// compile-flags:--test
+
+"fail
diff --git a/src/test/rustdoc-ui/test-compile-fail3.stderr b/src/test/rustdoc-ui/test-compile-fail3.stderr
new file mode 100644
index 000000000..fab801b3b
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail3.stderr
@@ -0,0 +1,9 @@
+error[E0765]: unterminated double quote string
+ --> $DIR/test-compile-fail3.rs:3:1
+ |
+3 | "fail
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0765`.
diff --git a/src/test/rustdoc-ui/test-no_std.rs b/src/test/rustdoc-ui/test-no_std.rs
new file mode 100644
index 000000000..ee919985e
--- /dev/null
+++ b/src/test/rustdoc-ui/test-no_std.rs
@@ -0,0 +1,13 @@
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// check-pass
+
+#![no_std]
+
+extern crate alloc;
+
+/// ```
+/// assert!(true)
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-no_std.stdout b/src/test/rustdoc-ui/test-no_std.stdout
new file mode 100644
index 000000000..8d5a30804
--- /dev/null
+++ b/src/test/rustdoc-ui/test-no_std.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/test-no_std.rs - f (line 10) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/test-type.rs b/src/test/rustdoc-ui/test-type.rs
new file mode 100644
index 000000000..882da5c25
--- /dev/null
+++ b/src/test/rustdoc-ui/test-type.rs
@@ -0,0 +1,26 @@
+// compile-flags: --test --test-args=--test-threads=1
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+/// println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-type.stdout b/src/test/rustdoc-ui/test-type.stdout
new file mode 100644
index 000000000..a66fd240d
--- /dev/null
+++ b/src/test/rustdoc-ui/test-type.stdout
@@ -0,0 +1,10 @@
+
+running 5 tests
+test $DIR/test-type.rs - f (line 12) ... ignored
+test $DIR/test-type.rs - f (line 15) - compile ... ok
+test $DIR/test-type.rs - f (line 21) - compile fail ... ok
+test $DIR/test-type.rs - f (line 6) ... ok
+test $DIR/test-type.rs - f (line 9) ... ok
+
+test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/tuple-variadic-check.rs b/src/test/rustdoc-ui/tuple-variadic-check.rs
new file mode 100644
index 000000000..505de5348
--- /dev/null
+++ b/src/test/rustdoc-ui/tuple-variadic-check.rs
@@ -0,0 +1,15 @@
+#![feature(rustdoc_internals)]
+
+trait Mine {}
+
+// This one is fine
+#[doc(fake_variadic)]
+impl<T> Mine for (T,) {}
+
+trait Mine2 {}
+
+// This one is not
+#[doc(fake_variadic)] //~ ERROR
+impl<T, U> Mine for (T,U) {}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/tuple-variadic-check.stderr b/src/test/rustdoc-ui/tuple-variadic-check.stderr
new file mode 100644
index 000000000..d127fb858
--- /dev/null
+++ b/src/test/rustdoc-ui/tuple-variadic-check.stderr
@@ -0,0 +1,8 @@
+error: `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
+ --> $DIR/tuple-variadic-check.rs:12:7
+ |
+LL | #[doc(fake_variadic)]
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs
new file mode 100644
index 000000000..ddf03dd07
--- /dev/null
+++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs
@@ -0,0 +1,24 @@
+#![deny(unknown_lints)]
+//~^ NOTE lint level is defined
+#![deny(renamed_and_removed_lints)]
+//~^ NOTE lint level is defined
+#![deny(x)]
+//~^ ERROR unknown lint
+#![deny(rustdoc::x)]
+//~^ ERROR unknown lint: `rustdoc::x`
+#![deny(intra_doc_link_resolution_failure)]
+//~^ ERROR renamed to `rustdoc::broken_intra_doc_links`
+#![deny(non_autolinks)]
+//~^ ERROR renamed to `rustdoc::bare_urls`
+#![deny(rustdoc::non_autolinks)]
+//~^ ERROR renamed to `rustdoc::bare_urls`
+
+#![deny(private_doc_tests)]
+//~^ ERROR renamed to `rustdoc::private_doc_tests`
+
+#![deny(rustdoc)]
+//~^ ERROR removed: use `rustdoc::all` instead
+
+// Explicitly don't try to handle this case, it was never valid
+#![deny(rustdoc::intra_doc_link_resolution_failure)]
+//~^ ERROR unknown lint
diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr
new file mode 100644
index 000000000..b105f47d7
--- /dev/null
+++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr
@@ -0,0 +1,64 @@
+error: unknown lint: `x`
+ --> $DIR/unknown-renamed-lints.rs:5:9
+ |
+LL | #![deny(x)]
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/unknown-renamed-lints.rs:1:9
+ |
+LL | #![deny(unknown_lints)]
+ | ^^^^^^^^^^^^^
+
+error: unknown lint: `rustdoc::x`
+ --> $DIR/unknown-renamed-lints.rs:7:9
+ |
+LL | #![deny(rustdoc::x)]
+ | ^^^^^^^^^^ help: did you mean: `rustdoc::all`
+
+error: lint `intra_doc_link_resolution_failure` has been renamed to `rustdoc::broken_intra_doc_links`
+ --> $DIR/unknown-renamed-lints.rs:9:9
+ |
+LL | #![deny(intra_doc_link_resolution_failure)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links`
+ |
+note: the lint level is defined here
+ --> $DIR/unknown-renamed-lints.rs:3:9
+ |
+LL | #![deny(renamed_and_removed_lints)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `non_autolinks` has been renamed to `rustdoc::bare_urls`
+ --> $DIR/unknown-renamed-lints.rs:11:9
+ |
+LL | #![deny(non_autolinks)]
+ | ^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+
+error: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
+ --> $DIR/unknown-renamed-lints.rs:13:9
+ |
+LL | #![deny(rustdoc::non_autolinks)]
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+
+error: lint `private_doc_tests` has been renamed to `rustdoc::private_doc_tests`
+ --> $DIR/unknown-renamed-lints.rs:16:9
+ |
+LL | #![deny(private_doc_tests)]
+ | ^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::private_doc_tests`
+
+error: lint `rustdoc` has been removed: use `rustdoc::all` instead
+ --> $DIR/unknown-renamed-lints.rs:19:9
+ |
+LL | #![deny(rustdoc)]
+ | ^^^^^^^
+
+error: unknown lint: `rustdoc::intra_doc_link_resolution_failure`
+ --> $DIR/unknown-renamed-lints.rs:23:9
+ |
+LL | #![deny(rustdoc::intra_doc_link_resolution_failure)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs
new file mode 100644
index 000000000..0cff8cd9a
--- /dev/null
+++ b/src/test/rustdoc-ui/unparseable-doc-test.rs
@@ -0,0 +1,11 @@
+// compile-flags: --test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+// rustc-env: RUST_BACKTRACE=0
+
+/// ```rust
+/// let x = 7;
+/// "unterminated
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout
new file mode 100644
index 000000000..2641c66f2
--- /dev/null
+++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout
@@ -0,0 +1,23 @@
+
+running 1 test
+test $DIR/unparseable-doc-test.rs - foo (line 7) ... FAILED
+
+failures:
+
+---- $DIR/unparseable-doc-test.rs - foo (line 7) stdout ----
+error[E0765]: unterminated double quote string
+ --> $DIR/unparseable-doc-test.rs:9:1
+ |
+LL | "unterminated
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0765`.
+Couldn't compile the test.
+
+failures:
+ $DIR/unparseable-doc-test.rs - foo (line 7)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/unused-braces-lint.rs b/src/test/rustdoc-ui/unused-braces-lint.rs
new file mode 100644
index 000000000..be0e31e4b
--- /dev/null
+++ b/src/test/rustdoc-ui/unused-braces-lint.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// This tests the bug in #70814, where the unused_braces lint triggered on the following code
+// without providing a span.
+
+#![deny(unused_braces)]
+
+fn main() {
+ {
+ {
+ use std;
+ }
+ }
+}
diff --git a/src/test/rustdoc-ui/unused-extern-crate.rs b/src/test/rustdoc-ui/unused-extern-crate.rs
new file mode 100644
index 000000000..f703a1837
--- /dev/null
+++ b/src/test/rustdoc-ui/unused-extern-crate.rs
@@ -0,0 +1,3 @@
+// check-pass
+// aux-crate:panic_item=panic-item.rs
+// @has unused_extern_crate/index.html
diff --git a/src/test/rustdoc-ui/unused.rs b/src/test/rustdoc-ui/unused.rs
new file mode 100644
index 000000000..702b24c36
--- /dev/null
+++ b/src/test/rustdoc-ui/unused.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// This test purpose is to check that unused_imports lint isn't fired
+// by rustdoc. Why would it? Because when rustdoc is running, it uses
+// "everybody-loops" which replaces parts of code with "loop {}" to get
+// huge performance improvements.
+
+#![deny(unused_imports)]
+
+use std::fs::File;
+
+pub fn f() {
+ let _: File;
+}
diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs
new file mode 100644
index 000000000..5037043f1
--- /dev/null
+++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs
@@ -0,0 +1 @@
+// compile-flags: --output ./foo
diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr
new file mode 100644
index 000000000..96d2295ac
--- /dev/null
+++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr
@@ -0,0 +1,2 @@
+error: cannot use both 'out-dir' and 'output' at once
+
diff --git a/src/test/rustdoc-ui/wasm-safe.rs b/src/test/rustdoc-ui/wasm-safe.rs
new file mode 100644
index 000000000..ba971342b
--- /dev/null
+++ b/src/test/rustdoc-ui/wasm-safe.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+#[cfg(any(target_arch = "wasm32", doc))]
+#[target_feature(enable = "simd128")]
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/z-help.rs b/src/test/rustdoc-ui/z-help.rs
new file mode 100644
index 000000000..c7cf841b9
--- /dev/null
+++ b/src/test/rustdoc-ui/z-help.rs
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Zhelp
+// check-stdout
+// regex-error-pattern: -Z\s+self-profile
+
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
new file mode 100644
index 000000000..6dc412315
--- /dev/null
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -0,0 +1,200 @@
+ -Z allow-features=val -- only allow the listed language features to be enabled in code (space separated)
+ -Z always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no)
+ -Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
+ -Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
+ -Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
+ -Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
+ -Z box-noalias=val -- emit noalias metadata for box (default: yes)
+ -Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
+ -Z cf-protection=val -- instrument control-flow architecture protection
+ -Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
+ -Z chalk=val -- enable the experimental Chalk-based trait solving engine
+ -Z codegen-backend=val -- the backend to use
+ -Z combine-cgu=val -- combine CGUs into a single one
+ -Z crate-attr=val -- inject the given attribute in the crate
+ -Z debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO
+ -Z debug-macros=val -- emit line numbers debug info inside macros (default: no)
+ -Z deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes)
+ -Z dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no)
+ -Z dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no)
+ -Z dlltool=val -- import library generation tool (windows-gnu only)
+ -Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
+ -Z drop-tracking=val -- enables drop tracking in generators (default: no)
+ -Z dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no)
+ -Z dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no)
+ -Z dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no)
+ -Z dump-mir=val -- dump MIR state to file.
+ `val` is used to select which passes and functions to dump. For example:
+ `all` matches all passes and functions,
+ `foo` matches all passes for functions whose name contains 'foo',
+ `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
+ `foo | bar` all passes for function names containing 'foo' or 'bar'.
+ -Z dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no)
+ -Z dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`)
+ -Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
+ -Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
+ -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
+ -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
+ -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
+ -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
+ -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
+ -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
+ -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
+ -Z fuel=val -- set the optimization fuel quota for a crate
+ -Z function-sections=val -- whether each function should go in its own section
+ -Z future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no)
+ -Z gcc-ld=val -- implementation of ld used by cc
+ -Z graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no)
+ -Z graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)
+ -Z hir-stats=val -- print some statistics about AST and HIR (default: no)
+ -Z human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no)
+ -Z identify-regions=val -- display unnamed regions as `'<id>`, using a non-ident unique id (default: no)
+ -Z incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no)
+ -Z incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
+ -Z incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
+ -Z incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
+ -Z inline-mir=val -- enable MIR inlining (default: no)
+ -Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
+ -Z inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
+ -Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
+ -Z input-stats=val -- gather statistics about the input (default: no)
+ -Z instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are:
+ `=all` (implicit value)
+ `=except-unused-generics`
+ `=except-unused-functions`
+ `=off` (default)
+ -Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
+ -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
+ -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
+ -Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
+ -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated)
+ -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
+ -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`)
+ -Z ls=val -- list the symbols defined by a library crate (default: no)
+ -Z macro-backtrace=val -- show macro backtraces (default: no)
+ -Z merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name
+ -Z meta-stats=val -- gather metadata statistics (default: no)
+ -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
+ -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual.
+ -Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing
+ -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
+ -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
+ -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
+ -Z new-llvm-pass-manager=val -- use new LLVM pass manager (default: no)
+ -Z nll-facts=val -- dump facts from NLL analysis into side files (default: no)
+ -Z nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`)
+ -Z no-analysis=val -- parse and expand the source, but run no analysis
+ -Z no-codegen=val -- run all passes except codegen; no output
+ -Z no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups
+ -Z no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints
+ -Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
+ -Z no-link=val -- compile without linking
+ -Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
+ -Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
+ -Z no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate
+ -Z normalize-docs=val -- normalize associated items in rustdoc when generating documentation
+ -Z oom=val -- panic strategy for out-of-memory handling
+ -Z osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no)
+ -Z diagnostic-width=val -- set the current output width for diagnostic truncation
+ -Z panic-abort-tests=val -- support compiling tests with panic=abort (default: no)
+ -Z panic-in-drop=val -- panic strategy for panics in drops
+ -Z parse-only=val -- parse only; do not compile, assemble, or link (default: no)
+ -Z perf-stats=val -- print some performance-related statistics (default: no)
+ -Z pick-stable-methods-before-any-unstable=val -- try to pick stable methods first before picking any unstable methods (default: yes)
+ -Z plt=val -- whether to use the PLT when calling into shared libraries;
+ only has effect for PIC code on systems with ELF binaries
+ (default: PLT is disabled if full relro is enabled)
+ -Z polonius=val -- enable polonius-based borrow-checker (default: no)
+ -Z polymorphize=val -- perform polymorphization analysis
+ -Z pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times)
+ -Z pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated)
+ -Z precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551.
+ -Z print-fuel=val -- make rustc print the total optimization fuel used by a crate
+ -Z print-llvm-passes=val -- print the LLVM optimization passes being run (default: no)
+ -Z print-mono-items=val -- print the result of the monomorphization collection pass
+ -Z print-type-sizes=val -- print layout information for each type encountered (default: no)
+ -Z proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no)
+ -Z proc-macro-execution-strategy=val -- how to run proc-macro code (default: same-thread)
+ -Z profile=val -- insert profiling code (default: no)
+ -Z profile-closures=val -- profile size of closures
+ -Z profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path)
+ -Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
+ -Z profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)
+ -Z query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no)
+ -Z randomize-layout=val -- randomize the layout of types (default: no)
+ -Z layout-seed=val -- seed layout randomization
+ -Z relax-elf-relocations=val -- whether ELF relocations can be relaxed
+ -Z relro-level=val -- choose which RELRO level to use
+ -Z remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix
+ -Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
+ -Z report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
+ -Z sanitizer=val -- use a sanitizer
+ -Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
+ -Z sanitizer-recover=val -- enable recovery for selected sanitizers
+ -Z saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes)
+ -Z save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no)
+ -Z self-profile=val -- run the self profiler and output the raw event data
+ -Z self-profile-events=val -- specify the events recorded by the self profiler;
+ for example: `-Z self-profile-events=default,query-keys`
+ all options: none, all, default, generic-activity, query-provider, query-cache-hit
+ query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
+ -Z self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of:
+ `wall-time` (monotonic clock, i.e. `std::time::Instant`)
+ `instructions:u` (retired instructions, userspace-only)
+ `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
+ -Z share-generics=val -- make the current crate share its generic instantiations
+ -Z show-span=val -- show spans for compiler debugging (expr|pat|ty)
+ -Z span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span`
+ -Z span-free-formats=val -- exclude spans when debug-printing compiler state (default: no)
+ -Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
+ -Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
+ -Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
+ -Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
+ -Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+ (default: `split`)
+
+ `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+ file which is ignored by the linker
+ `single`: sections which do not require relocation are written into object file but ignored
+ by the linker
+ -Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
+ -Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
+ -Z teach=val -- show extended diagnostic help (default: no)
+ -Z temps-dir=val -- the directory the intermediate files are written to
+ -Z translate-lang=val -- language identifier for diagnostic output
+ -Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
+ -Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
+ -Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
+ -Z thinlto=val -- enable ThinLTO when possible
+ -Z thir-unsafeck=val -- use the THIR unsafety checker (default: no)
+ -Z threads=val -- use a thread pool with N threads
+ -Z time=val -- measure time of rustc processes (default: no)
+ -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no)
+ -Z time-passes=val -- measure time of each rustc pass (default: no)
+ -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
+ -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
+ -Z translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes)
+ -Z trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)
+ -Z treat-err-as-bug=val -- treat error number `val` that occurs as bug
+ -Z trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items
+ -Z ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no)
+ -Z uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16)
+ -Z unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no)
+ -Z unpretty=val -- present the input source, unstable (and less-pretty) variants;
+ `normal`, `identified`,
+ `expanded`, `expanded,identified`,
+ `expanded,hygiene` (with internal representations),
+ `ast-tree` (raw AST before expansion),
+ `ast-tree,expanded` (raw AST after expansion),
+ `hir` (the HIR), `hir,identified`,
+ `hir,typed` (HIR with types for each node),
+ `hir-tree` (dump the raw HIR),
+ `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)
+ -Z unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no)
+ -Z unstable-options=val -- adds unstable command line options to rustc interface (default: no)
+ -Z use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array
+ -Z validate-mir=val -- validate MIR after each transformation
+ -Z verbose=val -- in general, enable more debug printouts (default: no)
+ -Z verify-llvm-ir=val -- verify LLVM IR (default: no)
+ -Z virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]`
+ -Z wasi-exec-model=val -- whether to build a wasi command or reactor
diff --git a/src/test/rustdoc/all.rs b/src/test/rustdoc/all.rs
new file mode 100644
index 000000000..a95d6c462
--- /dev/null
+++ b/src/test/rustdoc/all.rs
@@ -0,0 +1,28 @@
+#![crate_name = "foo"]
+
+// @has foo/all.html '//a[@href="struct.Struct.html"]' 'Struct'
+// @has foo/all.html '//a[@href="enum.Enum.html"]' 'Enum'
+// @has foo/all.html '//a[@href="union.Union.html"]' 'Union'
+// @has foo/all.html '//a[@href="constant.CONST.html"]' 'CONST'
+// @has foo/all.html '//a[@href="static.STATIC.html"]' 'STATIC'
+// @has foo/all.html '//a[@href="fn.function.html"]' 'function'
+
+pub struct Struct;
+pub enum Enum {
+ X,
+ Y,
+}
+pub union Union {
+ x: u32,
+}
+pub const CONST: u32 = 0;
+pub static STATIC: &str = "baguette";
+pub fn function() {}
+
+mod private_module {
+ pub struct ReexportedStruct;
+}
+
+// @has foo/all.html '//a[@href="struct.ReexportedStruct.html"]' 'ReexportedStruct'
+// @!has foo/all.html 'private_module'
+pub use private_module::ReexportedStruct;
diff --git a/src/test/rustdoc/anchors.no_const_anchor.html b/src/test/rustdoc/anchors.no_const_anchor.html
new file mode 100644
index 000000000..98f47e530
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_const_anchor.html
@@ -0,0 +1 @@
+<div id="associatedconstant.YOLO" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#16">source</a></div><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div>
diff --git a/src/test/rustdoc/anchors.no_const_anchor2.html b/src/test/rustdoc/anchors.no_const_anchor2.html
new file mode 100644
index 000000000..6d37e8e5e
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_const_anchor2.html
@@ -0,0 +1 @@
+<section id="associatedconstant.X" class="associatedconstant has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#42">source</a></span><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
diff --git a/src/test/rustdoc/anchors.no_method_anchor.html b/src/test/rustdoc/anchors.no_method_anchor.html
new file mode 100644
index 000000000..f46d3090e
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_method_anchor.html
@@ -0,0 +1 @@
+<section id="method.new" class="method has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#48">source</a></span><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -&gt; Self</h4></section> \ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_trait_method_anchor.html b/src/test/rustdoc/anchors.no_trait_method_anchor.html
new file mode 100644
index 000000000..445a7bb56
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_trait_method_anchor.html
@@ -0,0 +1 @@
+<div id="method.bar" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#23">source</a></div><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div> \ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_tymethod_anchor.html b/src/test/rustdoc/anchors.no_tymethod_anchor.html
new file mode 100644
index 000000000..bb0771b10
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_tymethod_anchor.html
@@ -0,0 +1 @@
+<div id="tymethod.foo" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#20">source</a></div><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div> \ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_type_anchor.html b/src/test/rustdoc/anchors.no_type_anchor.html
new file mode 100644
index 000000000..d317eb500
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_type_anchor.html
@@ -0,0 +1 @@
+<div id="associatedtype.T" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#13">source</a></div><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div> \ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_type_anchor2.html b/src/test/rustdoc/anchors.no_type_anchor2.html
new file mode 100644
index 000000000..72a1186bf
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_type_anchor2.html
@@ -0,0 +1 @@
+<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
diff --git a/src/test/rustdoc/anchors.rs b/src/test/rustdoc/anchors.rs
new file mode 100644
index 000000000..034cf8eaf
--- /dev/null
+++ b/src/test/rustdoc/anchors.rs
@@ -0,0 +1,49 @@
+// This test ensures that anchors are generated in the right places.
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @has 'foo/trait.Bar.html'
+pub trait Bar {
+ // There should be no anchors here.
+ // @snapshot no_type_anchor - '//*[@id="associatedtype.T"]'
+ type T;
+ // There should be no anchors here.
+ // @snapshot no_const_anchor - '//*[@id="associatedconstant.YOLO"]'
+ const YOLO: u32;
+
+ // There should be no anchors here.
+ // @snapshot no_tymethod_anchor - '//*[@id="tymethod.foo"]'
+ fn foo();
+ // There should be no anchors here.
+ // @snapshot no_trait_method_anchor - '//*[@id="method.bar"]'
+ fn bar() {}
+}
+
+// @has 'foo/struct.Foo.html'
+impl Bar for Foo {
+ // @has - '//*[@id="associatedtype.T"]/a[@class="anchor"]' ''
+ type T = u32;
+ // @has - '//*[@id="associatedconstant.YOLO"]/a[@class="anchor"]' ''
+ const YOLO: u32 = 0;
+
+ // @has - '//*[@id="method.foo"]/a[@class="anchor"]' ''
+ fn foo() {}
+ // Same check for provided "bar" method.
+ // @has - '//*[@id="method.bar"]/a[@class="anchor"]' ''
+}
+
+impl Foo {
+ // @snapshot no_const_anchor2 - '//*[@id="associatedconstant.X"]'
+ // There should be no anchors here.
+ pub const X: i32 = 0;
+ // @snapshot no_type_anchor2 - '//*[@id="associatedtype.Y"]'
+ // There should be no anchors here.
+ pub type Y = u32;
+ // @snapshot no_method_anchor - '//*[@id="method.new"]'
+ // There should be no anchors here.
+ pub fn new() -> Self { Self }
+}
diff --git a/src/test/rustdoc/anonymous-lifetime.rs b/src/test/rustdoc/anonymous-lifetime.rs
new file mode 100644
index 000000000..f5a7d2258
--- /dev/null
+++ b/src/test/rustdoc/anonymous-lifetime.rs
@@ -0,0 +1,28 @@
+// Regression test for https://github.com/rust-lang/rust/issues/84634
+#![crate_name = "foo"]
+
+use std::pin::Pin;
+use std::task::Poll;
+
+pub trait Stream {
+ type Item;
+
+ fn poll_next(mut self: Pin<&mut Self>) -> Poll<Option<Self::Item>>;
+ fn size_hint(&self) -> (usize, Option<usize>);
+}
+
+// @has 'foo/trait.Stream.html'
+// @has - '//*[@class="code-header in-band"]' 'impl<S: ?Sized + Stream + Unpin> Stream for &mut S'
+impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
+ type Item = S::Item;
+
+ fn poll_next(
+ mut self: Pin<&mut Self>,
+ ) -> Poll<Option<Self::Item>> {
+ S::poll_next(Pin::new(&mut **self), cx)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (**self).size_hint()
+ }
+}
diff --git a/src/test/rustdoc/anonymous-reexport.rs b/src/test/rustdoc/anonymous-reexport.rs
new file mode 100644
index 000000000..6b884ff14
--- /dev/null
+++ b/src/test/rustdoc/anonymous-reexport.rs
@@ -0,0 +1,22 @@
+#![crate_name = "foo"]
+
+// This test ensures we don't display anonymous (non-inline) re-exports of public items.
+
+// @has 'foo/index.html'
+// @has - '//*[@id="main-content"]' ''
+// We check that the only "h2" present is for "Bla".
+// @count - '//*[@id="main-content"]/h2' 1
+// @has - '//*[@id="main-content"]/h2' 'Structs'
+// @count - '//*[@id="main-content"]//a[@class="struct"]' 1
+
+mod ext {
+ pub trait Foo {}
+ pub trait Bar {}
+ pub struct S;
+}
+
+pub use crate::ext::Foo as _;
+pub use crate::ext::Bar as _;
+pub use crate::ext::S as _;
+
+pub struct Bla;
diff --git a/src/test/rustdoc/asm-foreign.rs b/src/test/rustdoc/asm-foreign.rs
new file mode 100644
index 000000000..d7550ca5a
--- /dev/null
+++ b/src/test/rustdoc/asm-foreign.rs
@@ -0,0 +1,20 @@
+// Make sure rustdoc accepts asm! for a foreign architecture.
+
+use std::arch::asm;
+
+// @has asm_foreign/fn.aarch64.html
+pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
+ let c;
+ asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+ || {};
+ b
+ });
+ c
+}
+
+// @has asm_foreign/fn.x86.html
+pub unsafe fn x86(a: f64, b: f64) -> f64 {
+ let c;
+ asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
+ c
+}
diff --git a/src/test/rustdoc/asm-foreign2.rs b/src/test/rustdoc/asm-foreign2.rs
new file mode 100644
index 000000000..87306901e
--- /dev/null
+++ b/src/test/rustdoc/asm-foreign2.rs
@@ -0,0 +1,11 @@
+// only-aarch64
+// Make sure rustdoc accepts options(att_syntax) asm! on non-x86 targets.
+
+use std::arch::asm;
+
+// @has asm_foreign2/fn.x86.html
+pub unsafe fn x86(x: i64) -> i64 {
+ let y;
+ asm!("movq {}, {}", in(reg) x, out(reg) y, options(att_syntax));
+ y
+}
diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs
new file mode 100644
index 000000000..6060bc0a6
--- /dev/null
+++ b/src/test/rustdoc/assoc-consts-version.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#![stable(since="1.1.1", feature="rust1")]
+
+#[stable(since="1.1.1", feature="rust1")]
+pub struct SomeStruct;
+
+impl SomeStruct {
+ // @has 'foo/struct.SomeStruct.html' \
+ // '//*[@id="associatedconstant.SOME_CONST"]//span[@class="since"]' '1.1.2'
+ #[stable(since="1.1.2", feature="rust2")]
+ pub const SOME_CONST: usize = 0;
+}
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
new file mode 100644
index 000000000..a79e93145
--- /dev/null
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -0,0 +1,103 @@
+pub trait Foo {
+ // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
+ // 'const FOO: usize = 13usize;'
+ // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
+ const FOO: usize = 12 + 1;
+ // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
+ const FOO_NO_DEFAULT: bool;
+ // @!has - FOO_HIDDEN
+ #[doc(hidden)]
+ const FOO_HIDDEN: u8 = 0;
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+ // @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Foo for Bar'
+ // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
+ const FOO: usize = 12;
+ // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
+ const FOO_NO_DEFAULT: bool = false;
+ // @!has - FOO_HIDDEN
+ #[doc(hidden)]
+ const FOO_HIDDEN: u8 = 0;
+}
+
+impl Bar {
+ // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
+ // 'const BAR: usize'
+ pub const BAR: usize = 3;
+
+ // @has - '//*[@id="associatedconstant.BAR_ESCAPED"]' \
+ // "const BAR_ESCAPED: &'static str = \"<em>markup</em>\""
+ pub const BAR_ESCAPED: &'static str = "<em>markup</em>";
+}
+
+pub struct Baz<'a, U: 'a, T>(T, &'a [U]);
+
+impl Bar {
+ // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAZ"]' \
+ // "const BAZ: Baz<'static, u8, u32>"
+ pub const BAZ: Baz<'static, u8, u32> = Baz(321, &[1, 2, 3]);
+}
+
+pub fn f(_: &(ToString + 'static)) {}
+
+impl Bar {
+ // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
+ // "const F: fn(_: &(dyn ToString + 'static))"
+ pub const F: fn(_: &(ToString + 'static)) = f;
+}
+
+impl Bar {
+ // @!has assoc_consts/struct.Bar.html 'BAR_PRIVATE'
+ const BAR_PRIVATE: char = 'a';
+ // @!has assoc_consts/struct.Bar.html 'BAR_HIDDEN'
+ #[doc(hidden)]
+ pub const BAR_HIDDEN: &'static str = "a";
+}
+
+// @has assoc_consts/trait.Qux.html
+pub trait Qux {
+ // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
+ // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
+ /// Docs for QUX0 in trait.
+ const QUX0: u8;
+ // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
+ // @has - '//*[@class="docblock"]' "Docs for QUX1 in trait."
+ /// Docs for QUX1 in trait.
+ const QUX1: i8;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ /// Docs for QUX_DEFAULT12 in trait.
+ const QUX_DEFAULT0: u16 = 1;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
+ /// Docs for QUX_DEFAULT1 in trait.
+ const QUX_DEFAULT1: i16 = 2;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+ /// Docs for QUX_DEFAULT2 in trait.
+ const QUX_DEFAULT2: u32 = 3;
+}
+
+// @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Qux for Bar'
+impl Qux for Bar {
+ // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
+ // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
+ /// Docs for QUX0 in trait.
+ const QUX0: u8 = 4;
+ // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
+ // @has - '//*[@class="docblock"]' "Docs for QUX1 in impl."
+ /// Docs for QUX1 in impl.
+ const QUX1: i8 = 5;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ const QUX_DEFAULT0: u16 = 6;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
+ /// Docs for QUX_DEFAULT1 in impl.
+ const QUX_DEFAULT1: i16 = 7;
+ // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+}
diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs
new file mode 100644
index 000000000..a409d6413
--- /dev/null
+++ b/src/test/rustdoc/assoc-item-cast.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+pub trait Expression {
+ type SqlType;
+}
+
+pub trait AsExpression<T> {
+ type Expression: Expression<SqlType = T>;
+ fn as_expression(self) -> Self::Expression;
+}
+
+// @has foo/type.AsExprOf.html
+// @has - '//pre[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
+pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;
diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs
new file mode 100644
index 000000000..a9e5b8d00
--- /dev/null
+++ b/src/test/rustdoc/assoc-types.rs
@@ -0,0 +1,37 @@
+#![crate_type="lib"]
+
+// @has assoc_types/trait.Index.html
+pub trait Index<I: ?Sized> {
+ // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized'
+ type Output: ?Sized;
+ // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]' \
+ // "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
+ // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]//a[@href="trait.Index.html#associatedtype.Output"]' \
+ // "Output"
+ fn index<'a>(&'a self, index: I) -> &'a Self::Output;
+}
+
+// @has assoc_types/fn.use_output.html
+// @has - '//*[@class="rust fn"]' '-> &T::Output'
+// @has - '//*[@class="rust fn"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
+pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output {
+ obj.index(index)
+}
+
+pub trait Feed {
+ type Input;
+}
+
+// @has assoc_types/fn.use_input.html
+// @has - '//*[@class="rust fn"]' 'T::Input'
+// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { }
+
+// @has assoc_types/fn.cmp_input.html
+// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>'
+// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
+ where T::Input: PartialEq<U::Input>
+{
+ a == b
+}
diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs
new file mode 100644
index 000000000..9319a073b
--- /dev/null
+++ b/src/test/rustdoc/associated-consts.rs
@@ -0,0 +1,51 @@
+#![crate_name = "foo"]
+
+pub trait Trait {
+ const FOO: u32 = 12;
+
+ fn foo();
+}
+
+pub struct Bar;
+
+// @has 'foo/struct.Bar.html'
+// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
+impl Trait for Bar {
+ const FOO: u32 = 1;
+
+ fn foo() {}
+}
+
+pub enum Foo {
+ A,
+}
+
+// @has 'foo/enum.Foo.html'
+// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
+impl Trait for Foo {
+ const FOO: u32 = 1;
+
+ fn foo() {}
+}
+
+pub struct Baz;
+
+// @has 'foo/struct.Baz.html'
+// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
+impl Baz {
+ pub const FOO: u32 = 42;
+}
+
+pub enum Quux {
+ B,
+}
+
+// @has 'foo/enum.Quux.html'
+// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
+impl Quux {
+ pub const FOO: u32 = 42;
+}
diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs
new file mode 100644
index 000000000..0277501de
--- /dev/null
+++ b/src/test/rustdoc/async-fn.rs
@@ -0,0 +1,95 @@
+// edition:2018
+// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
+pub async fn foo() -> Option<Foo> {
+ None
+}
+
+// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32'
+pub async fn bar(a: i32, b: i32) -> i32 {
+ 0
+}
+
+// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz<T>(a: T) -> T'
+pub async fn baz<T>(a: T) -> T {
+ a
+}
+
+// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char'
+pub async unsafe fn qux() -> char {
+ '⚠'
+}
+
+// @has async_fn/fn.mut_args.html '//pre[@class="rust fn"]' 'pub async fn mut_args(a: usize)'
+pub async fn mut_args(mut a: usize) {}
+
+// @has async_fn/fn.mut_ref.html '//pre[@class="rust fn"]' 'pub async fn mut_ref(x: i32)'
+pub async fn mut_ref(ref mut x: i32) {}
+
+trait Bar {}
+
+impl Bar for () {}
+
+// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar'
+pub async fn quux() -> impl Bar {
+ ()
+}
+
+// @has async_fn/struct.Foo.html
+// @matches - '//h4[@class="code-header"]' 'pub async fn f\(\)$'
+// @matches - '//h4[@class="code-header"]' 'pub async unsafe fn g\(\)$'
+// @matches - '//h4[@class="code-header"]' 'pub async fn mut_self\(self, first: usize\)$'
+pub struct Foo;
+
+impl Foo {
+ pub async fn f() {}
+ pub async unsafe fn g() {}
+ pub async fn mut_self(mut self, mut first: usize) {}
+}
+
+pub trait Pattern<'a> {}
+
+pub trait Trait<const N: usize> {}
+// @has async_fn/fn.const_generics.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
+pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
+
+// test that elided lifetimes are properly elided and not displayed as `'_`
+// regression test for #63037
+// @has async_fn/fn.elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+pub async fn elided(foo: &str) -> &str {}
+// This should really be shown as written, but for implementation reasons it's difficult.
+// See `impl Clean for TyKind::Rptr`.
+// @has async_fn/fn.user_elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+pub async fn user_elided(foo: &'_ str) -> &str {}
+// @has async_fn/fn.static_trait.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
+// @has async_fn/fn.lifetime_for_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
+// @has async_fn/fn.elided_in_input_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
+
+struct AsyncFdReadyGuard<'a, T> { x: &'a T }
+
+impl Foo {
+ // @has async_fn/struct.Foo.html
+ // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
+ // taken from `tokio` as an example of a method that was particularly bad before
+ // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+ pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
+ // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
+ pub async fn mut_self(&mut self) {}
+}
+
+// test named lifetimes, just in case
+// @has async_fn/fn.named.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
+// @has async_fn/fn.named_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs
new file mode 100644
index 000000000..2ba61388c
--- /dev/null
+++ b/src/test/rustdoc/async-move-doctest.rs
@@ -0,0 +1,12 @@
+// compile-flags:--test
+// edition:2018
+
+// Prior to setting the default edition for the doctest pre-parser,
+// this doctest would fail due to a fatal parsing error.
+// see https://github.com/rust-lang/rust/issues/59313
+
+//! ```
+//! fn foo() {
+//! drop(async move {});
+//! }
+//! ```
diff --git a/src/test/rustdoc/attribute-rendering.rs b/src/test/rustdoc/attribute-rendering.rs
new file mode 100644
index 000000000..677787184
--- /dev/null
+++ b/src/test/rustdoc/attribute-rendering.rs
@@ -0,0 +1,7 @@
+#![crate_name = "foo"]
+
+// @has 'foo/fn.f.html'
+// @has - //*[@'class="docblock item-decl"]' '#[export_name = "f"] pub fn f()'
+#[export_name = "\
+f"]
+pub fn f() {}
diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs
new file mode 100644
index 000000000..1c7f4b724
--- /dev/null
+++ b/src/test/rustdoc/attributes.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html '//*[@class="rust fn"]' '#[no_mangle]'
+#[no_mangle]
+pub extern "C" fn f() {}
+
+// @has foo/fn.g.html '//*[@class="rust fn"]' '#[export_name = "bar"]'
+#[export_name = "bar"]
+pub extern "C" fn g() {}
+
+// @has foo/struct.Repr.html '//*[@class="docblock item-decl"]' '#[repr(C, align(8))]'
+#[repr(C, align(8))]
+pub struct Repr;
diff --git a/src/test/rustdoc/auto-impl-for-trait.rs b/src/test/rustdoc/auto-impl-for-trait.rs
new file mode 100644
index 000000000..bc658fbfc
--- /dev/null
+++ b/src/test/rustdoc/auto-impl-for-trait.rs
@@ -0,0 +1,16 @@
+// Test for https://github.com/rust-lang/rust/issues/48463 issue.
+
+use std::any::Any;
+use std::ops::Deref;
+
+pub struct AnyValue {
+ val: Box<Any>,
+}
+
+impl Deref for AnyValue {
+ type Target = Any;
+
+ fn deref(&self) -> &Any {
+ &*self.val
+ }
+}
diff --git a/src/test/rustdoc/auto-impl-primitive.rs b/src/test/rustdoc/auto-impl-primitive.rs
new file mode 100644
index 000000000..172333d44
--- /dev/null
+++ b/src/test/rustdoc/auto-impl-primitive.rs
@@ -0,0 +1,10 @@
+#![feature(rustdoc_internals)]
+
+#![crate_name = "foo"]
+
+pub use std::fs::File;
+
+// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
+#[doc(primitive = "i16")]
+/// I love poneys!
+mod prim {}
diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs
new file mode 100644
index 000000000..661d905ab
--- /dev/null
+++ b/src/test/rustdoc/auto-trait-not-send.rs
@@ -0,0 +1,8 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+// @has - '//*[@id="impl-Send-for-Foo"]' 'impl !Send for Foo'
+// @has - '//*[@id="impl-Sync-for-Foo"]' 'impl !Sync for Foo'
+pub struct Foo(*const i8);
+pub trait Whatever: Send {}
+impl<T: Send + ?Sized> Whatever for T {}
diff --git a/src/test/rustdoc/auto-traits.rs b/src/test/rustdoc/auto-traits.rs
new file mode 100644
index 000000000..93d4bf2f6
--- /dev/null
+++ b/src/test/rustdoc/auto-traits.rs
@@ -0,0 +1,13 @@
+// aux-build:auto-traits.rs
+
+#![feature(auto_traits)]
+
+#![crate_name = "foo"]
+
+extern crate auto_traits;
+
+// @has 'foo/trait.Foo.html' '//pre' 'pub unsafe auto trait Foo'
+pub unsafe auto trait Foo {}
+
+// @has 'foo/trait.Bar.html' '//pre' 'pub unsafe auto trait Bar'
+pub use auto_traits::Bar;
diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs
new file mode 100644
index 000000000..a047c76b6
--- /dev/null
+++ b/src/test/rustdoc/auto_aliases.rs
@@ -0,0 +1,6 @@
+#![feature(auto_traits)]
+
+// @has auto_aliases/trait.Bar.html '//*[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+pub struct Foo;
+
+pub auto trait Bar {}
diff --git a/src/test/rustdoc/auxiliary/all-item-types.rs b/src/test/rustdoc/auxiliary/all-item-types.rs
new file mode 100644
index 000000000..f94bd9987
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/all-item-types.rs
@@ -0,0 +1,22 @@
+#![feature(extern_types)]
+
+pub mod foo_mod {}
+extern "C" {
+ pub fn foo_ffn();
+ pub static FOO_FSTATIC: FooStruct;
+ pub type FooFType;
+}
+pub fn foo_fn() {}
+pub trait FooTrait {}
+pub struct FooStruct;
+pub enum FooEnum {}
+pub union FooUnion {
+ x: (),
+}
+pub type FooType = FooStruct;
+pub static FOO_STATIC: FooStruct = FooStruct;
+pub const FOO_CONSTANT: FooStruct = FooStruct;
+#[macro_export]
+macro_rules! foo_macro {
+ () => ();
+}
diff --git a/src/test/rustdoc/auxiliary/auto-traits.rs b/src/test/rustdoc/auxiliary/auto-traits.rs
new file mode 100644
index 000000000..84976c73b
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/auto-traits.rs
@@ -0,0 +1,3 @@
+#![feature(auto_traits)]
+
+pub unsafe auto trait Bar {}
diff --git a/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs
new file mode 100644
index 000000000..3baf8a6c0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs
@@ -0,0 +1,19 @@
+pub trait Tr {
+ type VisibleAssoc;
+ #[doc(hidden)]
+ type HiddenAssoc;
+
+ const VISIBLE_ASSOC: ();
+ #[doc(hidden)]
+ const HIDDEN_ASSOC: ();
+}
+
+pub struct Ty;
+
+impl Tr for Ty {
+ type VisibleAssoc = ();
+ type HiddenAssoc = ();
+
+ const VISIBLE_ASSOC: () = ();
+ const HIDDEN_ASSOC: () = ();
+}
diff --git a/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs b/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs
new file mode 100644
index 000000000..159531222
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs
@@ -0,0 +1,5 @@
+#[doc(hidden)]
+pub enum HiddenType {}
+
+#[doc(hidden)]
+pub trait HiddenTrait {}
diff --git a/src/test/rustdoc/auxiliary/elided-lifetime.rs b/src/test/rustdoc/auxiliary/elided-lifetime.rs
new file mode 100644
index 000000000..4f2c93379
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/elided-lifetime.rs
@@ -0,0 +1,11 @@
+#![crate_name = "bar"]
+
+pub struct Ref<'a>(&'a u32);
+
+pub fn test5(a: &u32) -> Ref {
+ Ref(a)
+}
+
+pub fn test6(a: &u32) -> Ref<'_> {
+ Ref(a)
+}
diff --git a/src/test/rustdoc/auxiliary/empty.rs b/src/test/rustdoc/auxiliary/empty.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/empty.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/auxiliary/enum-primitive.rs b/src/test/rustdoc/auxiliary/enum-primitive.rs
new file mode 100644
index 000000000..ed1da253a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/enum-primitive.rs
@@ -0,0 +1,207 @@
+// Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// “Software”), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+//! This crate exports a macro `enum_from_primitive!` that wraps an
+//! `enum` declaration and automatically adds an implementation of
+//! `num::FromPrimitive` (reexported here), to allow conversion from
+//! primitive integers to the enum. It therefore provides an
+//! alternative to the built-in `#[derive(FromPrimitive)]`, which
+//! requires the unstable `std::num::FromPrimitive` and is disabled in
+//! Rust 1.0.
+//!
+//! # Example
+//!
+//! ```
+//! #[macro_use] extern crate enum_primitive;
+//! extern crate num_traits;
+//! use num_traits::FromPrimitive;
+//!
+//! enum_from_primitive! {
+//! #[derive(Debug, PartialEq)]
+//! enum FooBar {
+//! Foo = 17,
+//! Bar = 42,
+//! Baz,
+//! }
+//! }
+//!
+//! fn main() {
+//! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
+//! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
+//! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
+//! assert_eq!(FooBar::from_i32(91), None);
+//! }
+//! ```
+
+pub mod num_traits {
+ pub trait FromPrimitive: Sized {
+ fn from_i64(n: i64) -> Option<Self>;
+ fn from_u64(n: u64) -> Option<Self>;
+ }
+}
+
+pub use std::option::Option;
+pub use num_traits::FromPrimitive;
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+macro_rules! enum_from_primitive_impl_ty {
+ ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => {
+ #[allow(non_upper_case_globals, unused)]
+ fn $meth(n: $ty) -> $crate::Option<Self> {
+ $( if n == $name::$variant as $ty {
+ $crate::Option::Some($name::$variant)
+ } else )* {
+ $crate::Option::None
+ }
+ }
+ };
+}
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl_ty)]
+macro_rules! enum_from_primitive_impl {
+ ($name:ident, $( $variant:ident )*) => {
+ impl $crate::FromPrimitive for $name {
+ enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* }
+ enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* }
+ }
+ };
+}
+
+/// Wrap this macro around an `enum` declaration to get an
+/// automatically generated implementation of `num::FromPrimitive`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl)]
+macro_rules! enum_from_primitive {
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+}
diff --git a/src/test/rustdoc/auxiliary/extern-impl-trait.rs b/src/test/rustdoc/auxiliary/extern-impl-trait.rs
new file mode 100644
index 000000000..dbd543930
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/extern-impl-trait.rs
@@ -0,0 +1,27 @@
+pub trait Foo {
+ type Associated;
+}
+
+pub struct X;
+pub struct Y;
+
+
+impl Foo for X {
+ type Associated = ();
+}
+
+impl Foo for Y {
+ type Associated = ();
+}
+
+impl X {
+ pub fn returns_sized<'a>(&'a self) -> impl Foo<Associated=()> + 'a {
+ X
+ }
+}
+
+impl Y {
+ pub fn returns_unsized<'a>(&'a self) -> Box<impl ?Sized + Foo<Associated=()> + 'a> {
+ Box::new(X)
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/extern-links.rs b/src/test/rustdoc/auxiliary/extern-links.rs
new file mode 100644
index 000000000..4a835673a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/extern-links.rs
@@ -0,0 +1 @@
+pub struct Foo;
diff --git a/src/test/rustdoc/auxiliary/external-cross-doc.md b/src/test/rustdoc/auxiliary/external-cross-doc.md
new file mode 100644
index 000000000..d3c853265
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/external-cross-doc.md
@@ -0,0 +1,4 @@
+# Cross-crate imported docs
+
+This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included
+docs.
diff --git a/src/test/rustdoc/auxiliary/external-cross.rs b/src/test/rustdoc/auxiliary/external-cross.rs
new file mode 100644
index 000000000..5de63cdab
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/external-cross.rs
@@ -0,0 +1,3 @@
+#[deny(missing_docs)]
+#[doc = include_str!("external-cross-doc.md")]
+pub struct NeedMoreDocs;
diff --git a/src/test/rustdoc/auxiliary/external-doc.md b/src/test/rustdoc/auxiliary/external-doc.md
new file mode 100644
index 000000000..babde0a05
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/external-doc.md
@@ -0,0 +1,3 @@
+# External Docs
+
+This file is here to test the `#[doc = include_str!("file")]` attribute.
diff --git a/src/test/rustdoc/auxiliary/external-macro-src.rs b/src/test/rustdoc/auxiliary/external-macro-src.rs
new file mode 100644
index 000000000..ce20ca5c9
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/external-macro-src.rs
@@ -0,0 +1,15 @@
+// compile-flags:--remap-path-prefix={{src-base}}=/does-not-exist
+
+#![doc(html_root_url = "https://example.com/")]
+
+#[macro_export]
+macro_rules! make_foo {
+ () => {
+ pub struct Foo;
+ impl Foo {
+ pub fn new() -> Foo {
+ Foo
+ }
+ }
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/html_root.rs b/src/test/rustdoc/auxiliary/html_root.rs
new file mode 100644
index 000000000..4eb0b700f
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/html_root.rs
@@ -0,0 +1,2 @@
+#![doc(html_root_url="https://example.com/html_root")]
+pub fn foo() {}
diff --git a/src/test/rustdoc/auxiliary/inline-default-methods.rs b/src/test/rustdoc/auxiliary/inline-default-methods.rs
new file mode 100644
index 000000000..8a636f449
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/inline-default-methods.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Foo {
+ fn bar(&self);
+ fn foo(&mut self) {}
+}
diff --git a/src/test/rustdoc/auxiliary/issue-100204-aux.rs b/src/test/rustdoc/auxiliary/issue-100204-aux.rs
new file mode 100644
index 000000000..df1b59069
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-100204-aux.rs
@@ -0,0 +1,13 @@
+#![crate_name="first"]
+
+pub mod prelude {
+ pub use crate::Bot;
+}
+
+pub struct Bot;
+
+impl Bot {
+ pub fn new() -> Bot {
+ Bot
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-13698.rs b/src/test/rustdoc/auxiliary/issue-13698.rs
new file mode 100644
index 000000000..a65ebfe36
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-13698.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Foo {
+ #[doc(hidden)]
+ fn foo(&self) {}
+}
+
+impl Foo for i32 {}
diff --git a/src/test/rustdoc/auxiliary/issue-15318.rs b/src/test/rustdoc/auxiliary/issue-15318.rs
new file mode 100644
index 000000000..695fa58ef
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-15318.rs
@@ -0,0 +1,16 @@
+// no-prefer-dynamic
+// compile-flags: -Cmetadata=aux
+#![crate_type = "rlib"]
+#![doc(html_root_url = "http://example.com/")]
+#![feature(lang_items)]
+#![no_std]
+
+#[lang = "eh_personality"]
+fn foo() {}
+
+#[panic_handler]
+fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
+
+/// dox
+#[doc(primitive = "pointer")]
+pub mod ptr {}
diff --git a/src/test/rustdoc/auxiliary/issue-17476.rs b/src/test/rustdoc/auxiliary/issue-17476.rs
new file mode 100644
index 000000000..80c915eb7
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-17476.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Cmetadata=aux
+
+#![doc(html_root_url = "http://example.com")]
+
+pub trait Foo {
+ fn foo(&self) {}
+}
diff --git a/src/test/rustdoc/auxiliary/issue-19190-3.rs b/src/test/rustdoc/auxiliary/issue-19190-3.rs
new file mode 100644
index 000000000..8c526a89a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-19190-3.rs
@@ -0,0 +1,23 @@
+// compile-flags: -Cmetadata=aux
+
+use std::ops::Deref;
+
+pub struct Foo;
+
+impl Deref for Foo {
+ type Target = String;
+ fn deref(&self) -> &String { loop {} }
+}
+
+pub struct Bar;
+pub struct Baz;
+
+impl Baz {
+ pub fn baz(&self) {}
+ pub fn static_baz() {}
+}
+
+impl Deref for Bar {
+ type Target = Baz;
+ fn deref(&self) -> &Baz { loop {} }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-20646.rs b/src/test/rustdoc/auxiliary/issue-20646.rs
new file mode 100644
index 000000000..8e16f2de0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-20646.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Trait {
+ type Output;
+}
+
+pub fn fun<T>(_: T) where T: Trait<Output=i32> {}
diff --git a/src/test/rustdoc/auxiliary/issue-20727.rs b/src/test/rustdoc/auxiliary/issue-20727.rs
new file mode 100644
index 000000000..7ffc1985b
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-20727.rs
@@ -0,0 +1,30 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Deref {
+ type Target: ?Sized;
+
+ fn deref<'a>(&'a self) -> &'a Self::Target;
+}
+
+pub trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+
+pub trait Bar {}
+pub trait Deref2 {
+ type Target: Bar;
+
+ fn deref(&self) -> Self::Target;
+}
+
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
+ fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
+}
diff --git a/src/test/rustdoc/auxiliary/issue-21092.rs b/src/test/rustdoc/auxiliary/issue-21092.rs
new file mode 100644
index 000000000..51ab7de1c
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-21092.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Foo {
+ type Bar;
+ fn foo(&self) {}
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+ type Bar = i32;
+}
diff --git a/src/test/rustdoc/auxiliary/issue-21801.rs b/src/test/rustdoc/auxiliary/issue-21801.rs
new file mode 100644
index 000000000..732612ff0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-21801.rs
@@ -0,0 +1,9 @@
+// compile-flags: -Cmetadata=aux
+
+pub struct Foo;
+
+impl Foo {
+ pub fn new<F>(f: F) -> Foo where F: FnMut() -> i32 {
+ loop {}
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-22025.rs b/src/test/rustdoc/auxiliary/issue-22025.rs
new file mode 100644
index 000000000..5346c0e92
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-22025.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Cmetadata=aux
+
+pub mod foo {
+
+ pub trait Foo {}
+ pub struct Bar;
+
+ impl Foo for Bar {}
+
+}
diff --git a/src/test/rustdoc/auxiliary/issue-23207-1.rs b/src/test/rustdoc/auxiliary/issue-23207-1.rs
new file mode 100644
index 000000000..8531d5f1a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-23207-1.rs
@@ -0,0 +1,3 @@
+pub mod fmt {
+ pub struct Error;
+}
diff --git a/src/test/rustdoc/auxiliary/issue-23207-2.rs b/src/test/rustdoc/auxiliary/issue-23207-2.rs
new file mode 100644
index 000000000..b92b16653
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-23207-2.rs
@@ -0,0 +1,5 @@
+extern crate issue_23207_1;
+
+pub mod fmt {
+ pub use issue_23207_1::fmt::Error;
+}
diff --git a/src/test/rustdoc/auxiliary/issue-26606-macro.rs b/src/test/rustdoc/auxiliary/issue-26606-macro.rs
new file mode 100644
index 000000000..d60d32526
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-26606-macro.rs
@@ -0,0 +1,4 @@
+#[macro_export]
+macro_rules! make_item (
+ ($name: ident) => (pub const $name: usize = 42;)
+);
diff --git a/src/test/rustdoc/auxiliary/issue-27362-aux.rs b/src/test/rustdoc/auxiliary/issue-27362-aux.rs
new file mode 100644
index 000000000..077bdc33e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-27362-aux.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Cmetadata=aux
+
+pub const fn foo() {}
+pub const unsafe fn bar() {}
+
+pub struct Foo;
+
+impl Foo {
+ pub const unsafe fn baz() {}
+}
diff --git a/src/test/rustdoc/auxiliary/issue-28927-1.rs b/src/test/rustdoc/auxiliary/issue-28927-1.rs
new file mode 100644
index 000000000..688c73428
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-28927-1.rs
@@ -0,0 +1,4 @@
+mod detail {
+ pub extern crate issue_28927_2 as inner2;
+}
+pub use detail::inner2 as bar;
diff --git a/src/test/rustdoc/auxiliary/issue-28927-2.rs b/src/test/rustdoc/auxiliary/issue-28927-2.rs
new file mode 100644
index 000000000..7c0937fce
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-28927-2.rs
@@ -0,0 +1 @@
+pub struct Baz;
diff --git a/src/test/rustdoc/auxiliary/issue-29584.rs b/src/test/rustdoc/auxiliary/issue-29584.rs
new file mode 100644
index 000000000..a9b8796c0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-29584.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Cmetadata=aux
+
+pub struct Foo;
+
+#[doc(hidden)]
+mod bar {
+ trait Bar {}
+
+ impl Bar for ::Foo {}
+}
diff --git a/src/test/rustdoc/auxiliary/issue-30109-1.rs b/src/test/rustdoc/auxiliary/issue-30109-1.rs
new file mode 100644
index 000000000..ca05a6a90
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-30109-1.rs
@@ -0,0 +1 @@
+pub struct Bar;
diff --git a/src/test/rustdoc/auxiliary/issue-34274.rs b/src/test/rustdoc/auxiliary/issue-34274.rs
new file mode 100644
index 000000000..c46660579
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-34274.rs
@@ -0,0 +1,3 @@
+extern "C" {
+ pub fn extern_c_fn();
+}
diff --git a/src/test/rustdoc/auxiliary/issue-36031.rs b/src/test/rustdoc/auxiliary/issue-36031.rs
new file mode 100644
index 000000000..da688139e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-36031.rs
@@ -0,0 +1,9 @@
+pub trait Foo {
+ const FOO: usize;
+}
+
+pub struct Bar;
+
+impl Bar {
+ pub const BAR: usize = 3;
+}
diff --git a/src/test/rustdoc/auxiliary/issue-40936.rs b/src/test/rustdoc/auxiliary/issue-40936.rs
new file mode 100644
index 000000000..b921e5201
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-40936.rs
@@ -0,0 +1,5 @@
+pub mod outermod {
+ pub mod innermod {
+ pub use super::*;
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-46727.rs b/src/test/rustdoc/auxiliary/issue-46727.rs
new file mode 100644
index 000000000..30dccfa77
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-46727.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Foo {}
+
+pub struct Bar<T> { x: T }
+
+impl<T> Foo for Bar<[T; 1 + 1 + 1]> {}
diff --git a/src/test/rustdoc/auxiliary/issue-48414.rs b/src/test/rustdoc/auxiliary/issue-48414.rs
new file mode 100644
index 000000000..f442ac722
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-48414.rs
@@ -0,0 +1,5 @@
+/// Woah, this trait links to [OtherTrait](OtherTrait)!
+pub trait SomeTrait {}
+
+/// Woah, this trait links to [SomeTrait](SomeTrait)!
+pub trait OtherTrait {}
diff --git a/src/test/rustdoc/auxiliary/issue-53689.rs b/src/test/rustdoc/auxiliary/issue-53689.rs
new file mode 100644
index 000000000..5003c2c00
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-53689.rs
@@ -0,0 +1 @@
+pub struct MyStruct;
diff --git a/src/test/rustdoc/auxiliary/issue-57180.rs b/src/test/rustdoc/auxiliary/issue-57180.rs
new file mode 100644
index 000000000..4e2f4b87c
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-57180.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Cmetadata=aux
+
+pub trait Trait {
+}
+
+pub struct Struct<F>
+{
+ _p: ::std::marker::PhantomData<F>,
+}
+
+impl<F: Fn() -> u32>
+Trait for Struct<F>
+ where
+ F: Fn() -> u32,
+{
+}
diff --git a/src/test/rustdoc/auxiliary/issue-61592.rs b/src/test/rustdoc/auxiliary/issue-61592.rs
new file mode 100644
index 000000000..6e16a4caf
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-61592.rs
@@ -0,0 +1,4 @@
+#![crate_name = "foo"]
+
+pub trait FooTrait {}
+pub struct FooStruct;
diff --git a/src/test/rustdoc/auxiliary/issue-73061.rs b/src/test/rustdoc/auxiliary/issue-73061.rs
new file mode 100644
index 000000000..e05a3bc6d
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-73061.rs
@@ -0,0 +1,17 @@
+//edition:2018
+
+#![feature(type_alias_impl_trait)]
+
+pub trait Foo {
+ type X: std::future::Future<Output = ()>;
+ fn x(&self) -> Self::X;
+}
+
+pub struct F;
+
+impl Foo for F {
+ type X = impl std::future::Future<Output = ()>;
+ fn x(&self) -> Self::X {
+ async {}
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-85454.rs b/src/test/rustdoc/auxiliary/issue-85454.rs
new file mode 100644
index 000000000..45664dfc3
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-85454.rs
@@ -0,0 +1,17 @@
+// @has issue_85454/trait.FromResidual.html
+// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+pub trait FromResidual<R = <Self as Try>::Residual> {
+ fn from_residual(residual: R) -> Self;
+}
+
+pub trait Try: FromResidual {
+ type Output;
+ type Residual;
+ fn from_output(output: Self::Output) -> Self;
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+pub enum ControlFlow<B, C = ()> {
+ Continue(C),
+ Break(B),
+}
diff --git a/src/test/rustdoc/auxiliary/issue-86620-1.rs b/src/test/rustdoc/auxiliary/issue-86620-1.rs
new file mode 100644
index 000000000..f6debf6fb
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-86620-1.rs
@@ -0,0 +1,11 @@
+#![crate_name = "issue_86620_1"]
+
+pub trait VZip {
+ fn vzip() -> usize;
+}
+
+impl<T> VZip for T {
+ fn vzip() -> usize {
+ 0
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs
new file mode 100644
index 000000000..4e55e7ed5
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs
@@ -0,0 +1,17 @@
+/// When reexporting this function, make sure the anonymous lifetimes are not rendered.
+///
+/// https://github.com/rust-lang/rust/issues/98697
+pub fn repro<F>()
+where
+ F: Fn(&str),
+{
+ unimplemented!()
+}
+
+pub struct Extra;
+
+pub trait MyTrait<T> {
+ fn run() {}
+}
+
+impl MyTrait<&Extra> for Extra {}
diff --git a/src/test/rustdoc/auxiliary/issue-99221-aux.rs b/src/test/rustdoc/auxiliary/issue-99221-aux.rs
new file mode 100644
index 000000000..e061e42b2
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-99221-aux.rs
@@ -0,0 +1,20 @@
+pub struct Option;
+impl Option {
+ pub fn unwrap(self) {}
+}
+
+mod macros {
+ use crate::Option;
+ /// [`Option::unwrap`]
+ #[macro_export]
+ macro_rules! print {
+ () => ()
+ }
+}
+
+mod structs {
+ use crate::Option;
+ /// [`Option::unwrap`]
+ pub struct Print;
+}
+pub use structs::Print;
diff --git a/src/test/rustdoc/auxiliary/issue-99734-aux.rs b/src/test/rustdoc/auxiliary/issue-99734-aux.rs
new file mode 100644
index 000000000..234d55efb
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-99734-aux.rs
@@ -0,0 +1,11 @@
+pub struct Option;
+impl Option {
+ pub fn unwrap(self) {}
+}
+
+/// [`Option::unwrap`]
+pub mod task {}
+
+extern "C" {
+ pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/auxiliary/macro_pub_in_module.rs b/src/test/rustdoc/auxiliary/macro_pub_in_module.rs
new file mode 100644
index 000000000..137b12386
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/macro_pub_in_module.rs
@@ -0,0 +1,13 @@
+// edition:2018
+
+#![feature(decl_macro)]
+#![crate_name = "external_crate"]
+
+pub mod some_module {
+ /* == Make sure the logic is not affected by a re-export == */
+ mod private {
+ pub macro external_macro() {}
+ }
+
+ pub use private::external_macro;
+}
diff --git a/src/test/rustdoc/auxiliary/masked.rs b/src/test/rustdoc/auxiliary/masked.rs
new file mode 100644
index 000000000..f289359e5
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/masked.rs
@@ -0,0 +1,10 @@
+#[derive(Clone)]
+pub struct MaskedStruct;
+
+pub trait MaskedTrait {
+ fn masked_method();
+}
+
+impl MaskedTrait for String {
+ fn masked_method() {}
+}
diff --git a/src/test/rustdoc/auxiliary/mod-stackoverflow.rs b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs
new file mode 100644
index 000000000..e0b90f180
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs
@@ -0,0 +1,11 @@
+// compile-flags: -Cmetadata=aux
+
+pub mod tree {
+ pub use tree;
+}
+
+pub mod tree2 {
+ pub mod prelude {
+ pub use tree2;
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/no_html_root.rs b/src/test/rustdoc/auxiliary/no_html_root.rs
new file mode 100644
index 000000000..c5c0bc606
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/no_html_root.rs
@@ -0,0 +1 @@
+pub fn bar() {}
diff --git a/src/test/rustdoc/auxiliary/normalize-assoc-item.rs b/src/test/rustdoc/auxiliary/normalize-assoc-item.rs
new file mode 100644
index 000000000..fbd111c30
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/normalize-assoc-item.rs
@@ -0,0 +1,12 @@
+#![crate_name = "inner"]
+pub trait MyTrait {
+ type Y;
+}
+
+impl MyTrait for u32 {
+ type Y = i32;
+}
+
+pub fn foo() -> <u32 as MyTrait>::Y {
+ 0
+}
diff --git a/src/test/rustdoc/auxiliary/primitive-doc.rs b/src/test/rustdoc/auxiliary/primitive-doc.rs
new file mode 100644
index 000000000..e8da852a5
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/primitive-doc.rs
@@ -0,0 +1,9 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![feature(no_core)]
+#![no_core]
+
+#[doc(primitive = "usize")]
+/// This is the built-in type `usize`.
+mod usize {
+}
diff --git a/src/test/rustdoc/auxiliary/primitive-reexport.rs b/src/test/rustdoc/auxiliary/primitive-reexport.rs
new file mode 100644
index 000000000..b2e9fa43b
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/primitive-reexport.rs
@@ -0,0 +1,8 @@
+// compile-flags: --emit metadata --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+
+pub mod bar {
+ pub use bool;
+ pub use char as my_char;
+}
diff --git a/src/test/rustdoc/auxiliary/pub-extern-crate.rs b/src/test/rustdoc/auxiliary/pub-extern-crate.rs
new file mode 100644
index 000000000..8c89c8d6c
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/pub-extern-crate.rs
@@ -0,0 +1,2 @@
+#![crate_name = "inner"]
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs
new file mode 100644
index 000000000..7934e0733
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs
@@ -0,0 +1,21 @@
+#![crate_name="macros"]
+
+#[macro_export]
+macro_rules! foo {
+ () => {};
+}
+
+#[macro_export]
+macro_rules! bar {
+ () => {};
+}
+
+#[macro_export]
+macro_rules! baz {
+ () => {};
+}
+
+#[macro_export]
+macro_rules! quux {
+ () => {};
+}
diff --git a/src/test/rustdoc/auxiliary/real_gimli.rs b/src/test/rustdoc/auxiliary/real_gimli.rs
new file mode 100644
index 000000000..80d5c4ba8
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/real_gimli.rs
@@ -0,0 +1,13 @@
+// aux-build:realcore.rs
+
+#![crate_name = "real_gimli"]
+#![feature(staged_api, extremely_unstable)]
+#![unstable(feature = "rustc_private", issue = "none")]
+
+extern crate realcore;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+pub struct EndianSlice;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+impl realcore::Deref for EndianSlice {}
diff --git a/src/test/rustdoc/auxiliary/realcore.rs b/src/test/rustdoc/auxiliary/realcore.rs
new file mode 100644
index 000000000..e0a906df0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/realcore.rs
@@ -0,0 +1,15 @@
+#![crate_name = "realcore"]
+#![feature(staged_api)]
+#![unstable(feature = "extremely_unstable", issue = "none")]
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub struct Foo {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub trait Join {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+impl Join for Foo {}
+
+#[stable(feature = "faked_deref", since = "1.47.0")]
+pub trait Deref {}
diff --git a/src/test/rustdoc/auxiliary/reexp-stripped.rs b/src/test/rustdoc/auxiliary/reexp-stripped.rs
new file mode 100644
index 000000000..ccc3dc11f
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexp-stripped.rs
@@ -0,0 +1,11 @@
+pub use private::Quz;
+pub use hidden::Bar;
+
+mod private {
+ pub struct Quz;
+}
+
+#[doc(hidden)]
+pub mod hidden {
+ pub struct Bar;
+}
diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs
new file mode 100644
index 000000000..672ccb1cf
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexport-check.rs
@@ -0,0 +1,2 @@
+/// Docs in original
+pub struct S;
diff --git a/src/test/rustdoc/auxiliary/reexports.rs b/src/test/rustdoc/auxiliary/reexports.rs
new file mode 100644
index 000000000..4336993a3
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexports.rs
@@ -0,0 +1,66 @@
+#![feature(decl_macro)]
+
+pub macro addr_of($place:expr) {
+ &raw const $place
+}
+
+pub macro addr_of_crate($place:expr) {
+ &raw const $place
+}
+
+pub macro addr_of_super($place:expr) {
+ &raw const $place
+}
+
+pub macro addr_of_self($place:expr) {
+ &raw const $place
+}
+
+pub macro addr_of_local($place:expr) {
+ &raw const $place
+}
+
+pub struct Foo;
+pub struct FooCrate;
+pub struct FooSuper;
+pub struct FooSelf;
+pub struct FooLocal;
+
+pub enum Bar { Foo, }
+pub enum BarCrate { Foo, }
+pub enum BarSuper { Foo, }
+pub enum BarSelf { Foo, }
+pub enum BarLocal { Foo, }
+
+pub fn foo() {}
+pub fn foo_crate() {}
+pub fn foo_super() {}
+pub fn foo_self() {}
+pub fn foo_local() {}
+
+pub type Type = i32;
+pub type TypeCrate = i32;
+pub type TypeSuper = i32;
+pub type TypeSelf = i32;
+pub type TypeLocal = i32;
+
+pub union Union {
+ a: i8,
+ b: i8,
+}
+pub union UnionCrate {
+ a: i8,
+ b: i8,
+}
+pub union UnionSuper {
+ a: i8,
+ b: i8,
+}
+pub union UnionSelf {
+ a: i8,
+ b: i8,
+}
+pub union UnionLocal {
+ a: i8,
+ b: i8,
+}
diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs
new file mode 100644
index 000000000..032db3b25
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs
@@ -0,0 +1,23 @@
+#![feature(auto_traits)]
+
+pub mod bar {
+ use std::marker;
+
+ pub auto trait Bar {}
+
+ pub trait Foo {
+ fn foo(&self) {}
+ }
+
+ impl Foo {
+ pub fn test<T: Bar>(&self) {}
+ }
+
+ pub struct TypeId;
+
+ impl TypeId {
+ pub fn of<T: Bar + ?Sized>() -> TypeId {
+ panic!()
+ }
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs b/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs
new file mode 100644
index 000000000..12934238a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs
@@ -0,0 +1,11 @@
+#![crate_type="lib"]
+
+pub trait Trait {
+ fn provided(&self) {}
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+ fn provided(&self) {}
+}
diff --git a/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs b/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs
new file mode 100644
index 000000000..e493048d9
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs
@@ -0,0 +1,7 @@
+#![crate_type="lib"]
+#![feature(unboxed_closures)]
+
+pub trait Foo {
+ extern "rust-call" fn foo(&self, _: ()) -> i32;
+ extern "rust-call" fn foo_(&self, _: ()) -> i32 { 0 }
+}
diff --git a/src/test/rustdoc/auxiliary/rustdoc-ffi.rs b/src/test/rustdoc/auxiliary/rustdoc-ffi.rs
new file mode 100644
index 000000000..b74d190b5
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/rustdoc-ffi.rs
@@ -0,0 +1,6 @@
+#![crate_type="lib"]
+
+extern "C" {
+ // @has lib/fn.foreigner.html //pre 'pub unsafe fn foreigner(cold_as_ice: u32)'
+ pub fn foreigner(cold_as_ice: u32);
+}
diff --git a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs
new file mode 100644
index 000000000..135987fc0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs
@@ -0,0 +1,3 @@
+#![feature(auto_traits)]
+
+pub auto trait AnAutoTrait {}
diff --git a/src/test/rustdoc/auxiliary/source-code-bar.rs b/src/test/rustdoc/auxiliary/source-code-bar.rs
new file mode 100644
index 000000000..8700d688e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/source-code-bar.rs
@@ -0,0 +1,17 @@
+//! just some other file. :)
+
+use crate::Foo;
+
+pub struct Bar {
+ field: Foo,
+}
+
+pub struct Bar2 {
+ field: crate::Foo,
+}
+
+pub mod sub {
+ pub trait Trait {
+ fn tadam() {}
+ }
+}
diff --git a/src/test/rustdoc/auxiliary/source_code.rs b/src/test/rustdoc/auxiliary/source_code.rs
new file mode 100644
index 000000000..72a5c1a0a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/source_code.rs
@@ -0,0 +1 @@
+pub struct SourceCode;
diff --git a/src/test/rustdoc/auxiliary/src-links-external.rs b/src/test/rustdoc/auxiliary/src-links-external.rs
new file mode 100644
index 000000000..4a835673a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/src-links-external.rs
@@ -0,0 +1 @@
+pub struct Foo;
diff --git a/src/test/rustdoc/auxiliary/trait-alias-mention.rs b/src/test/rustdoc/auxiliary/trait-alias-mention.rs
new file mode 100644
index 000000000..6df06c87a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/trait-alias-mention.rs
@@ -0,0 +1,3 @@
+#![feature(trait_alias)]
+
+pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;
diff --git a/src/test/rustdoc/auxiliary/trait-visibility.rs b/src/test/rustdoc/auxiliary/trait-visibility.rs
new file mode 100644
index 000000000..1e8d0b8e0
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/trait-visibility.rs
@@ -0,0 +1,3 @@
+pub trait Bar {
+ fn foo();
+}
diff --git a/src/test/rustdoc/auxiliary/unit-return.rs b/src/test/rustdoc/auxiliary/unit-return.rs
new file mode 100644
index 000000000..7b9986162
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/unit-return.rs
@@ -0,0 +1,3 @@
+pub fn f2<F: FnMut(u32) + Clone>(f: F) {}
+
+pub fn f3<F: FnMut(u64) -> () + Clone>(f: F) {}
diff --git a/src/test/rustdoc/auxiliary/unstable-trait.rs b/src/test/rustdoc/auxiliary/unstable-trait.rs
new file mode 100644
index 000000000..6f06a6e26
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/unstable-trait.rs
@@ -0,0 +1,26 @@
+#![feature(staged_api)]
+#![stable(feature = "private_general", since = "1.0.0")]
+
+#[unstable(feature = "private_trait", issue = "none")]
+pub trait Bar {}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+pub struct Foo {
+ // nothing
+}
+
+impl Foo {
+ #[stable(feature = "private_general", since = "1.0.0")]
+ pub fn stable_impl() {}
+}
+
+impl Foo {
+ #[unstable(feature = "private_trait", issue = "none")]
+ pub fn bar() {}
+
+ #[stable(feature = "private_general", since = "1.0.0")]
+ pub fn bar2() {}
+}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+impl Bar for Foo {}
diff --git a/src/test/rustdoc/auxiliary/variant-struct.rs b/src/test/rustdoc/auxiliary/variant-struct.rs
new file mode 100644
index 000000000..0f3d2e5f1
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/variant-struct.rs
@@ -0,0 +1,5 @@
+pub enum Foo {
+ Bar {
+ qux: (),
+ }
+}
diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs
new file mode 100644
index 000000000..9ec089fd7
--- /dev/null
+++ b/src/test/rustdoc/bad-codeblock-syntax.rs
@@ -0,0 +1,44 @@
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
+// @has bad_codeblock_syntax/fn.foo.html
+// @has - '//*[@class="docblock"]' '\_'
+/// ```
+/// \_
+/// ```
+pub fn foo() {}
+
+// @has bad_codeblock_syntax/fn.bar.html
+// @has - '//*[@class="docblock"]' '`baz::foobar`'
+/// ```
+/// `baz::foobar`
+/// ```
+pub fn bar() {}
+
+// @has bad_codeblock_syntax/fn.quux.html
+// @has - '//*[@class="docblock"]' '\_'
+/// ```rust
+/// \_
+/// ```
+pub fn quux() {}
+
+// @has bad_codeblock_syntax/fn.ok.html
+// @has - '//*[@class="docblock"]' '\_'
+/// ```text
+/// \_
+/// ```
+pub fn ok() {}
+
+// @has bad_codeblock_syntax/fn.escape.html
+// @has - '//*[@class="docblock"]' '\_ <script>alert("not valid Rust");</script>'
+/// ```
+/// \_
+/// <script>alert("not valid Rust");</script>
+/// ```
+pub fn escape() {}
+
+// @has bad_codeblock_syntax/fn.unterminated.html
+// @has - '//*[@class="docblock"]' '"unterminated'
+/// ```
+/// "unterminated
+/// ```
+pub fn unterminated() {}
diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs
new file mode 100644
index 000000000..676d656da
--- /dev/null
+++ b/src/test/rustdoc/blanket-reexport-item.rs
@@ -0,0 +1,8 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
+pub struct S2 {}
+mod m {
+ pub struct S {}
+}
+pub use m::*;
diff --git a/src/test/rustdoc/cap-lints.rs b/src/test/rustdoc/cap-lints.rs
new file mode 100644
index 000000000..08a353396
--- /dev/null
+++ b/src/test/rustdoc/cap-lints.rs
@@ -0,0 +1,9 @@
+// This should fail a normal compile due to non_camel_case_types,
+// It should pass a doc-compile as it only needs to type-check and
+// therefore should not concern itself with the lints.
+#[deny(warnings)]
+
+// @has cap_lints/struct.Foo.html //* 'Foo'
+pub struct Foo {
+ field: i32,
+}
diff --git a/src/test/rustdoc/cfg-doctest.rs b/src/test/rustdoc/cfg-doctest.rs
new file mode 100644
index 000000000..6a9d26a4b
--- /dev/null
+++ b/src/test/rustdoc/cfg-doctest.rs
@@ -0,0 +1,6 @@
+// @!has cfg_doctest/struct.SomeStruct.html
+// @!has cfg_doctest/index.html '//a/@href' 'struct.SomeStruct.html'
+
+/// Sneaky, this isn't actually part of docs.
+#[cfg(doctest)]
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/check-source-code-urls-to-def-std.rs b/src/test/rustdoc/check-source-code-urls-to-def-std.rs
new file mode 100644
index 000000000..3396b234a
--- /dev/null
+++ b/src/test/rustdoc/check-source-code-urls-to-def-std.rs
@@ -0,0 +1,42 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+// @has 'src/foo/check-source-code-urls-to-def-std.rs.html'
+
+fn babar() {}
+
+// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str'
+// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
+// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar'
+pub fn foo(a: u32, b: &str, c: String) {
+ let x = 12;
+ let y: bool = true;
+ babar();
+}
+
+macro_rules! yolo { () => {}}
+
+fn bar(a: i32) {}
+
+macro_rules! bar {
+ ($a:ident) => { bar($a) }
+}
+
+macro_rules! data {
+ ($x:expr) => { $x * 2 }
+}
+
+pub fn another_foo() {
+ // This is known limitation: if the macro doesn't generate anything, the visitor
+ // can't find any item or anything that could tell us that it comes from expansion.
+ // @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!'
+ yolo!();
+ // @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
+ eprintln!();
+ // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!'
+ let x = data!(4);
+ // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!'
+ bar!(x);
+}
diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs
new file mode 100644
index 000000000..ec44e1bc6
--- /dev/null
+++ b/src/test/rustdoc/check-source-code-urls-to-def.rs
@@ -0,0 +1,69 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
+// aux-build:source_code.rs
+// build-aux-docs
+
+#![feature(rustdoc_internals)]
+
+#![crate_name = "foo"]
+
+extern crate source_code;
+
+// @has 'src/foo/check-source-code-urls-to-def.rs.html'
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
+#[path = "auxiliary/source-code-bar.rs"]
+pub mod bar;
+
+// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4
+use bar::Bar;
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
+use bar::sub::{self, Trait};
+
+pub struct Foo;
+
+impl Foo {
+ fn hello(&self) {}
+}
+
+fn babar() {}
+
+// @has - '//a/@href' '/struct.String.html'
+// @has - '//a/@href' '/primitive.u32.html'
+// @has - '//a/@href' '/primitive.str.html'
+// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5
+// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
+pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
+ let x = 12;
+ let y: Foo = Foo;
+ let z: Bar = bar::Bar { field: Foo };
+ babar();
+ // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello'
+ y.hello();
+}
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
+pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
+
+pub trait AnotherTrait {}
+pub trait WhyNot {}
+
+// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#49"]' 'AnotherTrait'
+// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#50"]' 'WhyNot'
+pub fn foo3<T, V>(t: &T, v: &V)
+where
+ T: AnotherTrait,
+ V: WhyNot
+{}
+
+pub trait AnotherTrait2 {}
+
+// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#60"]' 'AnotherTrait2'
+pub fn foo4() {
+ let x: Vec<AnotherTrait2> = Vec::new();
+}
+
+// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool'
+#[doc(primitive = "bool")]
+mod whatever {}
diff --git a/src/test/rustdoc/check-styled-link.rs b/src/test/rustdoc/check-styled-link.rs
new file mode 100644
index 000000000..ed4a5ea21
--- /dev/null
+++ b/src/test/rustdoc/check-styled-link.rs
@@ -0,0 +1,8 @@
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @has foo/struct.Bar.html '//a[@href="struct.Foo.html"]' 'Foo'
+
+/// Code-styled reference to [`Foo`].
+pub struct Bar;
diff --git a/src/test/rustdoc/check.rs b/src/test/rustdoc/check.rs
new file mode 100644
index 000000000..1fb4b35dd
--- /dev/null
+++ b/src/test/rustdoc/check.rs
@@ -0,0 +1,5 @@
+// compile-flags: -Z unstable-options --check
+
+// @!has check/fn.foo.html
+// @!has check/index.html
+pub fn foo() {}
diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs
new file mode 100644
index 000000000..140c5b3a6
--- /dev/null
+++ b/src/test/rustdoc/codeblock-title.rs
@@ -0,0 +1,25 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ"
+
+/// foo
+///
+/// ```compile_fail
+/// foo();
+/// ```
+///
+/// ```ignore (tidy)
+/// goo();
+/// ```
+///
+/// ```should_panic
+/// hoo();
+/// ```
+///
+/// ```edition2018
+/// let x = 0;
+/// ```
+pub fn bar() -> usize { 2 }
diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs
new file mode 100644
index 000000000..5691d1735
--- /dev/null
+++ b/src/test/rustdoc/comment-in-doctest.rs
@@ -0,0 +1,20 @@
+// compile-flags:--test
+
+// comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into
+// thinking that everything after it was part of the regular program. combined with the librustc_ast
+// parser loop failing to detect the manual main function, it would wrap everything in `fn main`,
+// which would cause the doctest to fail as the "extern crate" declaration was no longer valid.
+// oddly enough, it would pass in 2018 if a crate was in the extern prelude. see
+// https://github.com/rust-lang/rust/issues/56727
+
+//! ```
+//! // crate: proc-macro-test
+//! //! this is a test
+//!
+//! // used to pull in proc-macro specific items
+//! extern crate proc_macro;
+//!
+//! use proc_macro::TokenStream;
+//!
+//! # fn main() {}
+//! ```
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
new file mode 100644
index 000000000..8455dd9ef
--- /dev/null
+++ b/src/test/rustdoc/const-display.rs
@@ -0,0 +1,86 @@
+#![crate_name = "foo"]
+
+#![unstable(feature = "humans",
+ reason = "who ever let humans program computers, we're apparently really bad at it",
+ issue = "none")]
+
+#![feature(foo, foo2)]
+#![feature(staged_api)]
+
+// @has 'foo/fn.foo.html' '//pre' 'pub fn foo() -> u32'
+// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo", issue = "none")]
+pub const fn foo() -> u32 { 42 }
+
+// @has 'foo/fn.foo_unsafe.html' '//pre' 'pub unsafe fn foo_unsafe() -> u32'
+// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo", issue = "none")]
+pub const unsafe fn foo_unsafe() -> u32 { 42 }
+
+// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32'
+// @!has - '//span[@class="since"]'
+#[unstable(feature = "humans", issue = "none")]
+pub const fn foo2() -> u32 { 42 }
+
+// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
+// @has - //span '1.0.0 (const: 1.0.0)'
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+pub const fn bar2() -> u32 { 42 }
+
+
+// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32'
+// @!has - '//span[@class="since"]'
+#[unstable(feature = "foo2", issue = "none")]
+pub const unsafe fn foo2_gated() -> u32 { 42 }
+
+// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
+// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)'
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+pub const unsafe fn bar2_gated() -> u32 { 42 }
+
+// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32'
+// @!has - '//span[@class="since"]'
+pub const unsafe fn bar_not_gated() -> u32 { 42 }
+
+pub struct Foo;
+
+impl Foo {
+ // @has 'foo/struct.Foo.html' '//*[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
+ // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature="foo", issue = "none")]
+ pub const fn gated() -> u32 { 42 }
+
+ // @has 'foo/struct.Foo.html' '//*[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
+ // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature="foo", issue = "none")]
+ pub const unsafe fn gated_unsafe() -> u32 { 42 }
+
+ // @has 'foo/struct.Foo.html' '//*[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
+ // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const2", since = "1.2.0")]
+ pub const fn stable_impl() -> u32 { 42 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+ // Do not show non-const stabilities that are the same as the enclosing item.
+ // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const2", since = "1.2.0")]
+ pub const fn stable_impl() -> u32 { 42 }
+
+ // Show const-stability even for unstable functions.
+ // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
+ #[unstable(feature = "foo2", issue = "none")]
+ #[rustc_const_stable(feature = "const3", since = "1.3.0")]
+ pub const fn const_stable_unstable() -> u32 { 42 }
+}
diff --git a/src/test/rustdoc/const-doc.rs b/src/test/rustdoc/const-doc.rs
new file mode 100644
index 000000000..74ab4af61
--- /dev/null
+++ b/src/test/rustdoc/const-doc.rs
@@ -0,0 +1,19 @@
+use std::marker::PhantomData;
+
+pub struct Foo<'a> {
+ f: PhantomData<&'a u32>,
+}
+
+pub struct ContentType {
+ pub ttype: Foo<'static>,
+ pub subtype: Foo<'static>,
+ pub params: Option<Foo<'static>>,
+}
+
+impl ContentType {
+ // @has const_doc/struct.ContentType.html
+ // @has - '//*[@id="associatedconstant.Any"]' 'const Any: ContentType'
+ pub const Any: ContentType = ContentType { ttype: Foo { f: PhantomData, },
+ subtype: Foo { f: PhantomData, },
+ params: None, };
+}
diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs
new file mode 100644
index 000000000..68c7f9c56
--- /dev/null
+++ b/src/test/rustdoc/const-evalutation-ice.rs
@@ -0,0 +1,10 @@
+// Just check we don't get an ICE for `N`.
+
+use std::cell::Cell;
+use std::mem;
+
+pub struct S {
+ s: Cell<usize>
+}
+
+pub const N: usize = 0 - (mem::size_of::<S>() != 4) as usize;
diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs
new file mode 100644
index 000000000..28eba849a
--- /dev/null
+++ b/src/test/rustdoc/const-fn.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+ 2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method has-srclink"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+ pub const fn new() -> Foo { Foo(0) }
+}
diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs
new file mode 100644
index 000000000..591139523
--- /dev/null
+++ b/src/test/rustdoc/const-generics/add-impl.rs
@@ -0,0 +1,17 @@
+#![crate_name = "foo"]
+
+use std::ops::Add;
+
+// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd<T, const WIDTH: usize>'
+pub struct Simd<T, const WIDTH: usize> {
+ inner: T,
+}
+
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16>> for Simd<u8, 16>'
+impl Add for Simd<u8, 16> {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ Self { inner: 0 }
+ }
+}
diff --git a/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs b/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs
new file mode 100644
index 000000000..55b632a48
--- /dev/null
+++ b/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs
@@ -0,0 +1,16 @@
+// edition:2018
+pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> {
+ [[0; N]; N].iter().copied()
+}
+
+pub struct ExternTy<const N: usize> {
+ pub inner: [u8; N],
+}
+
+pub type TyAlias<const N: usize> = ExternTy<N>;
+
+pub trait WTrait<const N: usize, const M: usize> {
+ fn hey<const P: usize>() -> usize {
+ N + M + P
+ }
+}
diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs
new file mode 100644
index 000000000..2693d9b59
--- /dev/null
+++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// 'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);'
+pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs
new file mode 100644
index 000000000..4279de91f
--- /dev/null
+++ b/src/test/rustdoc/const-generics/const-generic-slice.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+
+pub trait Array {
+ type Item;
+}
+
+// @has foo/trait.Array.html
+// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
+impl<T, const N: usize> Array for [T; N] {
+ type Item = T;
+}
diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs
new file mode 100644
index 000000000..352a8e646
--- /dev/null
+++ b/src/test/rustdoc/const-generics/const-generics-docs.rs
@@ -0,0 +1,128 @@
+// edition:2018
+// aux-build: extern_crate.rs
+#![crate_name = "foo"]
+
+extern crate extern_crate;
+// @has foo/fn.extern_fn.html '//pre[@class="rust fn"]' \
+// 'pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]>'
+pub use extern_crate::extern_fn;
+// @has foo/struct.ExternTy.html '//pre[@class="rust struct"]' \
+// 'pub struct ExternTy<const N: usize> {'
+pub use extern_crate::ExternTy;
+// @has foo/type.TyAlias.html '//pre[@class="rust typedef"]' \
+// 'type TyAlias<const N: usize> = ExternTy<N>;'
+pub use extern_crate::TyAlias;
+// @has foo/trait.WTrait.html '//pre[@class="rust trait"]' \
+// 'pub trait WTrait<const N: usize, const M: usize>'
+// @has - '//*[@class="rust trait"]' 'fn hey<const P: usize>() -> usize'
+pub use extern_crate::WTrait;
+
+// @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
+// 'pub trait Trait<const N: usize>'
+// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1> for u8'
+// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2> for u8'
+// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8'
+// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \
+// 'impl<const N: usize> Trait<N> for [u8; N]'
+pub trait Trait<const N: usize> {}
+impl Trait<1> for u8 {}
+impl Trait<2> for u8 {}
+impl Trait<{1 + 2}> for u8 {}
+impl<const N: usize> Trait<N> for [u8; N] {}
+
+// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// 'pub struct Foo<const N: usize> where u8: Trait<N>'
+pub struct Foo<const N: usize> where u8: Trait<N>;
+// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
+pub struct Bar<T, const N: usize>([T; N]);
+
+// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+impl<const M: usize> Foo<M> where u8: Trait<M> {
+ // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
+ pub const FOO_ASSOC: usize = M + 13;
+
+ // @has - '//*[@id="method.hey"]' 'pub fn hey<const N: usize>(&self) -> Bar<u8, N>'
+ pub fn hey<const N: usize>(&self) -> Bar<u8, N> {
+ Bar([0; N])
+ }
+}
+
+// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
+impl<const M: usize> Bar<u8, M> {
+ // @has - '//*[@id="method.hey"]' \
+ // 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
+ pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> {
+ Foo
+ }
+}
+
+// @has foo/fn.test.html '//pre[@class="rust fn"]' \
+// 'pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N>'
+pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
+ 2u8
+}
+
+// @has foo/fn.a_sink.html '//pre[@class="rust fn"]' \
+// 'pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N>'
+pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
+ v
+}
+
+// @has foo/fn.b_sink.html '//pre[@class="rust fn"]' \
+// 'pub async fn b_sink<const N: usize>(_: impl Trait<N>)'
+pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}
+
+// @has foo/fn.concrete.html '//pre[@class="rust fn"]' \
+// 'pub fn concrete() -> [u8; 22]'
+pub fn concrete() -> [u8; 3 + std::mem::size_of::<u64>() << 1] {
+ Default::default()
+}
+
+// @has foo/type.Faz.html '//pre[@class="rust typedef"]' \
+// 'type Faz<const N: usize> = [u8; N];'
+pub type Faz<const N: usize> = [u8; N];
+// @has foo/type.Fiz.html '//pre[@class="rust typedef"]' \
+// 'type Fiz<const N: usize> = [[u8; N]; 48];'
+pub type Fiz<const N: usize> = [[u8; N]; 3 << 4];
+
+macro_rules! define_me {
+ ($t:tt<$q:tt>) => {
+ pub struct $t<const $q: usize>([u8; $q]);
+ }
+}
+
+// @has foo/struct.Foz.html '//pre[@class="rust struct"]' \
+// 'pub struct Foz<const N: usize>(_);'
+define_me!(Foz<N>);
+
+trait Q {
+ const ASSOC: usize;
+}
+
+impl<const N: usize> Q for [u8; N] {
+ const ASSOC: usize = N;
+}
+
+// @has foo/fn.q_user.html '//pre[@class="rust fn"]' \
+// 'pub fn q_user() -> [u8; 13]'
+pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {
+ [0; <[u8; 13] as Q>::ASSOC]
+}
+
+// @has foo/union.Union.html '//pre[@class="rust union"]' \
+// 'pub union Union<const N: usize>'
+pub union Union<const N: usize> {
+ // @has - //pre "pub arr: [u8; N]"
+ pub arr: [u8; N],
+ // @has - //pre "pub another_arr: [(); N]"
+ pub another_arr: [(); N],
+}
+
+// @has foo/enum.Enum.html '//pre[@class="rust enum"]' \
+// 'pub enum Enum<const N: usize>'
+pub enum Enum<const N: usize> {
+ // @has - //pre "Variant([u8; N])"
+ Variant([u8; N]),
+ // @has - //pre "EmptyVariant"
+ EmptyVariant,
+}
diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
new file mode 100644
index 000000000..f1181d54a
--- /dev/null
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -0,0 +1,37 @@
+#![allow(incomplete_features)]
+#![feature(adt_const_params)]
+#![crate_name = "foo"]
+
+#[derive(PartialEq, Eq)]
+pub enum Order {
+ Sorted,
+ Unsorted,
+}
+
+// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
+// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+pub struct VSet<T, const ORDER: Order> {
+ inner: Vec<T>,
+}
+
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+impl<T> VSet<T, { Order::Sorted }> {
+ pub fn new() -> Self {
+ Self { inner: Vec::new() }
+ }
+}
+
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+impl<T> VSet<T, { Order::Unsorted }> {
+ pub fn new() -> Self {
+ Self { inner: Vec::new() }
+ }
+}
+
+pub struct Escape<const S: &'static str>;
+
+// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+impl Escape<r#"<script>alert("Escape");</script>"#> {
+ pub fn f() {}
+}
diff --git a/src/test/rustdoc/const-generics/generic_const_exprs.rs b/src/test/rustdoc/const-generics/generic_const_exprs.rs
new file mode 100644
index 000000000..215ee228e
--- /dev/null
+++ b/src/test/rustdoc/const-generics/generic_const_exprs.rs
@@ -0,0 +1,7 @@
+#![crate_name = "foo"]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
+// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
+// 'pub struct Ice<const N: usize>;'
+pub struct Ice<const N: usize> where [(); N + 1]:;
diff --git a/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs
new file mode 100644
index 000000000..4eac8e31e
--- /dev/null
+++ b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+// Checking if `Send` is implemented for `Hasher` requires us to evaluate a `ConstEquate` predicate,
+// which previously caused an ICE.
+
+pub struct Hasher<T> {
+ cv_stack: T,
+}
+
+unsafe impl<T: Default> Send for Hasher<T> {}
+
+// @has foo/struct.Foo.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foo'
+pub struct Foo {
+ hasher: Hasher<[u8; 3]>,
+}
diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs
new file mode 100644
index 000000000..ebda5b194
--- /dev/null
+++ b/src/test/rustdoc/const-generics/type-alias.rs
@@ -0,0 +1,4 @@
+#![crate_name = "foo"]
+
+// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
+pub type CellIndex<const D: usize> = [i64; D];
diff --git a/src/test/rustdoc/const-underscore.rs b/src/test/rustdoc/const-underscore.rs
new file mode 100644
index 000000000..0d4809409
--- /dev/null
+++ b/src/test/rustdoc/const-underscore.rs
@@ -0,0 +1,7 @@
+// compile-flags: --document-private-items
+
+// @!has const_underscore/constant._.html
+const _: () = {
+ #[no_mangle]
+ extern "C" fn implementation_detail() {}
+};
diff --git a/src/test/rustdoc/const-value-display.rs b/src/test/rustdoc/const-value-display.rs
new file mode 100644
index 000000000..5b2f3c48d
--- /dev/null
+++ b/src/test/rustdoc/const-value-display.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+// @has 'foo/constant.HOUR_IN_SECONDS.html'
+// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64'
+pub const HOUR_IN_SECONDS: u64 = 60 * 60;
+
+// @has 'foo/constant.NEGATIVE.html'
+// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64'
+pub const NEGATIVE: i64 = -60 * 60;
diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs
new file mode 100644
index 000000000..587ad4db4
--- /dev/null
+++ b/src/test/rustdoc/const.rs
@@ -0,0 +1,10 @@
+#![crate_type="lib"]
+
+pub struct Foo;
+
+impl Foo {
+ // @has const/struct.Foo.html '//*[@id="method.new"]//h4[@class="code-header"]' 'const unsafe fn new'
+ pub const unsafe fn new() -> Foo {
+ Foo
+ }
+}
diff --git a/src/test/rustdoc/constructor-imports.rs b/src/test/rustdoc/constructor-imports.rs
new file mode 100644
index 000000000..26795c274
--- /dev/null
+++ b/src/test/rustdoc/constructor-imports.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+
+pub mod a {
+ pub struct Foo;
+ pub enum Bar {
+ Baz,
+ }
+}
+
+// @count 'foo/index.html' '//*[code="pub use a::Foo;"]' 1
+#[doc(no_inline)]
+pub use a::Foo;
+// @count 'foo/index.html' '//*[code="pub use a::Bar::Baz;"]' 1
+#[doc(no_inline)]
+pub use a::Bar::Baz;
diff --git a/src/test/rustdoc/crate-version-escape.rs b/src/test/rustdoc/crate-version-escape.rs
new file mode 100644
index 000000000..8413709f1
--- /dev/null
+++ b/src/test/rustdoc/crate-version-escape.rs
@@ -0,0 +1,5 @@
+// compile-flags: --crate-version=<script>alert("hi")</script> -Z unstable-options
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>'
diff --git a/src/test/rustdoc/crate-version.rs b/src/test/rustdoc/crate-version.rs
new file mode 100644
index 000000000..2592c9853
--- /dev/null
+++ b/src/test/rustdoc/crate-version.rs
@@ -0,0 +1,3 @@
+// compile-flags: --crate-version=1.3.37
+
+// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37'
diff --git a/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs b/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs
new file mode 100644
index 000000000..d02bc4fe7
--- /dev/null
+++ b/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs
@@ -0,0 +1,23 @@
+// Regression test for issue #95717
+// Hide cross-crate `#[doc(hidden)]` associated items in trait impls.
+
+#![crate_name = "dependent"]
+// edition:2021
+// aux-crate:dependency=cross-crate-hidden-assoc-trait-items.rs
+
+// The trait `Tr` contains 2 hidden and 2 visisible associated items.
+// Instead of checking for the absence of the hidden items, check for the presence of the
+// visible items instead and assert that there are *exactly two* associated items
+// (by counting the number of `section`s). This is more robust and future-proof.
+
+// @has dependent/struct.Ty.html
+// @has - '//*[@id="associatedtype.VisibleAssoc"]' 'type VisibleAssoc = ()'
+// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC"]' 'const VISIBLE_ASSOC: ()'
+// @count - '//*[@class="impl-items"]/section' 2
+
+// @has dependent/trait.Tr.html
+// @has - '//*[@id="associatedtype.VisibleAssoc-1"]' 'type VisibleAssoc = ()'
+// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC-1"]' 'const VISIBLE_ASSOC: ()'
+// @count - '//*[@class="impl-items"]/section' 2
+
+pub use dependency::{Tr, Ty};
diff --git a/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs b/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs
new file mode 100644
index 000000000..eb2ced2f7
--- /dev/null
+++ b/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs
@@ -0,0 +1,35 @@
+// Issue #86448: test for cross-crate `doc(hidden)`
+#![crate_name = "foo"]
+
+// aux-build:cross-crate-hidden-impl-parameter.rs
+extern crate cross_crate_hidden_impl_parameter;
+
+pub use ::cross_crate_hidden_impl_parameter::{HiddenType, HiddenTrait}; // OK, not re-exported
+
+pub enum MyLibType {}
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CHiddenType%3E"]' 'impl From<HiddenType> for MyLibType'
+impl From<HiddenType> for MyLibType {
+ fn from(it: HiddenType) -> MyLibType {
+ match it {}
+ }
+}
+
+pub struct T<T>(T);
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CT%3CT%3CT%3CT%3CHiddenType%3E%3E%3E%3E%3E"]' 'impl From<T<T<T<T<HiddenType>>>>> for MyLibType'
+impl From<T<T<T<T<HiddenType>>>>> for MyLibType {
+ fn from(it: T<T<T<T<HiddenType>>>>) -> MyLibType {
+ todo!()
+ }
+}
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-HiddenTrait"]' 'impl HiddenTrait for MyLibType'
+impl HiddenTrait for MyLibType {}
+
+// @!has foo/struct.T.html '//*[@id="impl-From%3CMyLibType%3E"]' 'impl From<MyLibType> for T<T<T<T<HiddenType>>>>'
+impl From<MyLibType> for T<T<T<T<HiddenType>>>> {
+ fn from(it: MyLibType) -> T<T<T<T<HiddenType>>>> {
+ match it {}
+ }
+}
diff --git a/src/test/rustdoc/cross-crate-links.rs b/src/test/rustdoc/cross-crate-links.rs
new file mode 100644
index 000000000..7c736a4cc
--- /dev/null
+++ b/src/test/rustdoc/cross-crate-links.rs
@@ -0,0 +1,59 @@
+// aux-build:all-item-types.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate all_item_types;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/foo_mod/index.html"]' 'foo_mod'
+#[doc(no_inline)]
+pub use all_item_types::foo_mod;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_ffn.html"]' 'foo_ffn'
+#[doc(no_inline)]
+pub use all_item_types::foo_ffn;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_FSTATIC.html"]' 'FOO_FSTATIC'
+#[doc(no_inline)]
+pub use all_item_types::FOO_FSTATIC;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/foreigntype.FooFType.html"]' 'FooFType'
+#[doc(no_inline)]
+pub use all_item_types::FooFType;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_fn.html"]' 'foo_fn'
+#[doc(no_inline)]
+pub use all_item_types::foo_fn;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/trait.FooTrait.html"]' 'FooTrait'
+#[doc(no_inline)]
+pub use all_item_types::FooTrait;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/struct.FooStruct.html"]' 'FooStruct'
+#[doc(no_inline)]
+pub use all_item_types::FooStruct;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/enum.FooEnum.html"]' 'FooEnum'
+#[doc(no_inline)]
+pub use all_item_types::FooEnum;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/union.FooUnion.html"]' 'FooUnion'
+#[doc(no_inline)]
+pub use all_item_types::FooUnion;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/type.FooType.html"]' 'FooType'
+#[doc(no_inline)]
+pub use all_item_types::FooType;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_STATIC.html"]' 'FOO_STATIC'
+#[doc(no_inline)]
+pub use all_item_types::FOO_STATIC;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/constant.FOO_CONSTANT.html"]' 'FOO_CONSTANT'
+#[doc(no_inline)]
+pub use all_item_types::FOO_CONSTANT;
+
+// @has 'foo/index.html' '//a[@href="../all_item_types/macro.foo_macro.html"]' 'foo_macro'
+#[doc(no_inline)]
+pub use all_item_types::foo_macro;
diff --git a/src/test/rustdoc/cross-crate-primitive-doc.rs b/src/test/rustdoc/cross-crate-primitive-doc.rs
new file mode 100644
index 000000000..4ba296ee0
--- /dev/null
+++ b/src/test/rustdoc/cross-crate-primitive-doc.rs
@@ -0,0 +1,13 @@
+// aux-build:primitive-doc.rs
+// compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options
+// only-linux
+
+#![feature(no_core)]
+#![no_core]
+
+extern crate primitive_doc;
+
+// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize'
+// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'link'
+/// [link](usize)
+pub fn foo() -> usize { 0 }
diff --git a/src/test/rustdoc/decl-trailing-whitespace.declaration.html b/src/test/rustdoc/decl-trailing-whitespace.declaration.html
new file mode 100644
index 000000000..e60caaeff
--- /dev/null
+++ b/src/test/rustdoc/decl-trailing-whitespace.declaration.html
@@ -0,0 +1,7 @@
+<code>pub trait Write {
+ fn <a href="#tymethod.poll_write" class="fnname">poll_write</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fnname">poll_flush</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fnname">poll_close</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+
+ fn <a href="#method.poll_write_vectored" class="fnname">poll_write_vectored</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt; { ... }
+}</code>
diff --git a/src/test/rustdoc/decl-trailing-whitespace.rs b/src/test/rustdoc/decl-trailing-whitespace.rs
new file mode 100644
index 000000000..46a2307ab
--- /dev/null
+++ b/src/test/rustdoc/decl-trailing-whitespace.rs
@@ -0,0 +1,30 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98803>.
+
+#![crate_name = "foo"]
+
+pub struct Error;
+
+// @has 'foo/trait.Write.html'
+
+pub trait Write {
+ // @snapshot 'declaration' - '//*[@class="docblock item-decl"]//code'
+ fn poll_write(
+ self: Option<String>,
+ cx: &mut Option<String>,
+ buf: &mut [usize]
+ ) -> Option<Result<usize, Error>>;
+ fn poll_flush(
+ self: Option<String>,
+ cx: &mut Option<String>
+ ) -> Option<Result<(), Error>>;
+ fn poll_close(
+ self: Option<String>,
+ cx: &mut Option<String>,
+ ) -> Option<Result<(), Error>>;
+
+ fn poll_write_vectored(
+ self: Option<String>,
+ cx: &mut Option<String>,
+ bufs: &[usize]
+ ) -> Option<Result<usize, Error>> {}
+}
diff --git a/src/test/rustdoc/decl_macro.rs b/src/test/rustdoc/decl_macro.rs
new file mode 100644
index 000000000..94ade31b5
--- /dev/null
+++ b/src/test/rustdoc/decl_macro.rs
@@ -0,0 +1,56 @@
+// compile-flags: --document-private-items
+
+#![feature(decl_macro)]
+
+// @has decl_macro/macro.my_macro.html //pre 'pub macro my_macro() {'
+// @has - //pre '...'
+// @has - //pre '}'
+pub macro my_macro() {
+
+}
+
+// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {'
+// @has - //pre '...'
+// @has - //pre '}'
+pub macro my_macro_2($($tok:tt)*) {
+
+}
+
+// @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {'
+// @has - //pre '(_) => { ... },'
+// @has - //pre '($foo:ident . $bar:expr) => { ... },'
+// @has - //pre '($($foo:literal),+) => { ... },'
+// @has - //pre '}'
+pub macro my_macro_multi {
+ (_) => {
+
+ },
+ ($foo:ident . $bar:expr) => {
+
+ },
+ ($($foo:literal),+) => {
+
+ }
+}
+
+// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {'
+// @has - //pre '...'
+// @has - //pre '}'
+pub macro by_example_single {
+ ($foo:expr) => {}
+}
+
+mod a {
+ mod b {
+ // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {'
+ pub(in super) macro by_example_vis {
+ ($foo:expr) => {}
+ }
+ mod c {
+ // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
+ pub(in a) macro by_example_vis_named {
+ ($foo:expr) => {}
+ }
+ }
+ }
+}
diff --git a/src/test/rustdoc/decl_macro_priv.rs b/src/test/rustdoc/decl_macro_priv.rs
new file mode 100644
index 000000000..4e1279e34
--- /dev/null
+++ b/src/test/rustdoc/decl_macro_priv.rs
@@ -0,0 +1,14 @@
+// compile-flags: --document-private-items
+
+#![feature(decl_macro)]
+
+// @has decl_macro_priv/macro.crate_macro.html //pre 'pub(crate) macro crate_macro() {'
+// @has - //pre '...'
+// @has - //pre '}'
+pub(crate) macro crate_macro() {}
+
+// @has decl_macro_priv/macro.priv_macro.html //pre 'macro priv_macro() {'
+// @!has - //pre 'pub macro priv_macro() {'
+// @has - //pre '...'
+// @has - //pre '}'
+macro priv_macro() {}
diff --git a/src/test/rustdoc/deep-structures.rs b/src/test/rustdoc/deep-structures.rs
new file mode 100644
index 000000000..cd3b0d3ec
--- /dev/null
+++ b/src/test/rustdoc/deep-structures.rs
@@ -0,0 +1,104 @@
+// This test verifies that we do not hit recursion limit trying to prove auto-trait bounds for
+// reasonably deep structures.
+
+#![crate_type="rlib"]
+
+pub struct A01(A02);
+pub struct A02(A03);
+pub struct A03(A04);
+pub struct A04(A05);
+pub struct A05(A06);
+pub struct A06(A07);
+pub struct A07(A08);
+pub struct A08(A09);
+pub struct A09(A10);
+pub struct A10(A11);
+pub struct A11(A12);
+pub struct A12(A13);
+pub struct A13(A14);
+pub struct A14(A15);
+pub struct A15(A16);
+pub struct A16(A17);
+pub struct A17(A18);
+pub struct A18(A19);
+pub struct A19(A20);
+pub struct A20(A21);
+pub struct A21(A22);
+pub struct A22(A23);
+pub struct A23(A24);
+pub struct A24(A25);
+pub struct A25(A26);
+pub struct A26(A27);
+pub struct A27(A28);
+pub struct A28(A29);
+pub struct A29(A30);
+pub struct A30(A31);
+pub struct A31(A32);
+pub struct A32(A33);
+pub struct A33(A34);
+pub struct A34(A35);
+pub struct A35(A36);
+pub struct A36(A37);
+pub struct A37(A38);
+pub struct A38(A39);
+pub struct A39(A40);
+pub struct A40(A41);
+pub struct A41(A42);
+pub struct A42(A43);
+pub struct A43(A44);
+pub struct A44(A45);
+pub struct A45(A46);
+pub struct A46(A47);
+pub struct A47(A48);
+pub struct A48(A49);
+pub struct A49(A50);
+pub struct A50(A51);
+pub struct A51(A52);
+pub struct A52(A53);
+pub struct A53(A54);
+pub struct A54(A55);
+pub struct A55(A56);
+pub struct A56(A57);
+pub struct A57(A58);
+pub struct A58(A59);
+pub struct A59(A60);
+pub struct A60(A61);
+pub struct A61(A62);
+pub struct A62(A63);
+pub struct A63(A64);
+pub struct A64(A65);
+pub struct A65(A66);
+pub struct A66(A67);
+pub struct A67(A68);
+pub struct A68(A69);
+pub struct A69(A70);
+pub struct A70(A71);
+pub struct A71(A72);
+pub struct A72(A73);
+pub struct A73(A74);
+pub struct A74(A75);
+pub struct A75(A76);
+pub struct A76(A77);
+pub struct A77(A78);
+pub struct A78(A79);
+pub struct A79(A80);
+pub struct A80(A81);
+pub struct A81(A82);
+pub struct A82(A83);
+pub struct A83(A84);
+pub struct A84(A85);
+pub struct A85(A86);
+pub struct A86(A87);
+pub struct A87(A88);
+pub struct A88(A89);
+pub struct A89(A90);
+pub struct A90(A91);
+pub struct A91(A92);
+pub struct A92(A93);
+pub struct A93(A94);
+pub struct A94(A95);
+pub struct A95(A96);
+pub struct A96(A97);
+pub struct A97(A98);
+pub struct A98(A99);
+pub struct A99;
diff --git a/src/test/rustdoc/default-impl.rs b/src/test/rustdoc/default-impl.rs
new file mode 100644
index 000000000..f11b3b29b
--- /dev/null
+++ b/src/test/rustdoc/default-impl.rs
@@ -0,0 +1,9 @@
+// aux-build:rustdoc-default-impl.rs
+// ignore-cross-compile
+
+extern crate rustdoc_default_impl as foo;
+
+pub use foo::bar;
+
+pub fn wut<T: bar::Bar>() {
+}
diff --git a/src/test/rustdoc/default-theme.rs b/src/test/rustdoc/default-theme.rs
new file mode 100644
index 000000000..ecb8f0b3b
--- /dev/null
+++ b/src/test/rustdoc/default-theme.rs
@@ -0,0 +1,7 @@
+// compile-flags: --default-theme ayu
+
+// @has default_theme/index.html
+// @has - '//script[@id="default-settings"]/@data-theme' 'ayu'
+// @has - '//script[@id="default-settings"]/@data-use_system_theme' 'false'
+
+pub fn whatever() {}
diff --git a/src/test/rustdoc/default-trait-method-link.rs b/src/test/rustdoc/default-trait-method-link.rs
new file mode 100644
index 000000000..7bcd2a3c1
--- /dev/null
+++ b/src/test/rustdoc/default-trait-method-link.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+
+// @has foo/trait.Foo.html '//a[@href="trait.Foo.html#tymethod.req"]' 'req'
+// @has foo/trait.Foo.html '//a[@href="trait.Foo.html#method.prov"]' 'prov'
+
+/// Always make sure to implement [`req`], but you don't have to implement [`prov`].
+///
+/// [`req`]: Foo::req
+/// [`prov`]: Foo::prov
+pub trait Foo {
+ /// Required
+ fn req();
+ /// Provided
+ fn prov() {}
+}
diff --git a/src/test/rustdoc/default-trait-method.rs b/src/test/rustdoc/default-trait-method.rs
new file mode 100644
index 000000000..6d0e339c4
--- /dev/null
+++ b/src/test/rustdoc/default-trait-method.rs
@@ -0,0 +1,26 @@
+#![feature(min_specialization)]
+
+// @has default_trait_method/trait.Item.html
+// @has - '//*[@id="tymethod.foo"]' 'fn foo()'
+// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()'
+// @has - '//*[@id="tymethod.bar"]' 'fn bar()'
+// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()'
+// @has - '//*[@id="method.baz"]' 'fn baz()'
+// @!has - '//*[@id="method.baz"]' 'default fn baz()'
+pub trait Item {
+ fn foo();
+ fn bar();
+ fn baz() {}
+}
+
+// @has default_trait_method/struct.Foo.html
+// @has - '//*[@id="method.foo"]' 'default fn foo()'
+// @has - '//*[@id="method.bar"]' 'fn bar()'
+// @!has - '//*[@id="method.bar"]' 'default fn bar()'
+// @has - '//*[@id="method.baz"]' 'fn baz()'
+// @!has - '//*[@id="method.baz"]' 'default fn baz()'
+pub struct Foo;
+impl Item for Foo {
+ default fn foo() {}
+ fn bar() {}
+}
diff --git a/src/test/rustdoc/deprecated-future-staged-api.rs b/src/test/rustdoc/deprecated-future-staged-api.rs
new file mode 100644
index 000000000..2670e7f5d
--- /dev/null
+++ b/src/test/rustdoc/deprecated-future-staged-api.rs
@@ -0,0 +1,18 @@
+#![feature(staged_api)]
+#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in 99.99.99: effectively never'
+#[deprecated(since = "99.99.99", note = "effectively never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S1;
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in a future Rust version: literally never'
+#[deprecated(since = "TBD", note = "literally never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S2;
diff --git a/src/test/rustdoc/deprecated-future.rs b/src/test/rustdoc/deprecated-future.rs
new file mode 100644
index 000000000..7db8cc602
--- /dev/null
+++ b/src/test/rustdoc/deprecated-future.rs
@@ -0,0 +1,6 @@
+// @has deprecated_future/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecated'
+// @has deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \
+// 'Deprecated since 99.99.99: effectively never'
+#[deprecated(since = "99.99.99", note = "effectively never")]
+pub struct S;
diff --git a/src/test/rustdoc/deprecated-impls.rs b/src/test/rustdoc/deprecated-impls.rs
new file mode 100644
index 000000000..efd250ce9
--- /dev/null
+++ b/src/test/rustdoc/deprecated-impls.rs
@@ -0,0 +1,118 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo0.html
+pub struct Foo0;
+
+impl Foo0 {
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.1: fn_with_doc'
+ // @has - 'fn_with_doc short'
+ // @has - 'fn_with_doc full'
+ /// fn_with_doc short
+ ///
+ /// fn_with_doc full
+ #[deprecated(since = "1.0.1", note = "fn_with_doc")]
+ pub fn fn_with_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.2: fn_without_doc'
+ #[deprecated(since = "1.0.2", note = "fn_without_doc")]
+ pub fn fn_without_doc() {}
+}
+
+pub trait Bar {
+ /// fn_empty_with_doc short
+ ///
+ /// fn_empty_with_doc full
+ #[deprecated(since = "1.0.3", note = "fn_empty_with_doc")]
+ fn fn_empty_with_doc();
+
+ #[deprecated(since = "1.0.4", note = "fn_empty_without_doc")]
+ fn fn_empty_without_doc();
+
+ /// fn_def_with_doc short
+ ///
+ /// fn_def_with_doc full
+ #[deprecated(since = "1.0.5", note = "fn_def_with_doc")]
+ fn fn_def_with_doc() {}
+
+ #[deprecated(since = "1.0.6", note = "fn_def_without_doc")]
+ fn fn_def_without_doc() {}
+
+ /// fn_def_def_with_doc short
+ ///
+ /// fn_def_def_with_doc full
+ #[deprecated(since = "1.0.7", note = "fn_def_def_with_doc")]
+ fn fn_def_def_with_doc() {}
+
+ #[deprecated(since = "1.0.8", note = "fn_def_def_without_doc")]
+ fn fn_def_def_without_doc() {}
+}
+
+// @has foo/struct.Foo1.html
+pub struct Foo1;
+
+impl Bar for Foo1 {
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc'
+ // @has - 'fn_empty_with_doc_impl short'
+ // @has - 'fn_empty_with_doc_impl full'
+ /// fn_empty_with_doc_impl short
+ ///
+ /// fn_empty_with_doc_impl full
+ fn fn_empty_with_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc'
+ fn fn_empty_without_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc'
+ // @has - 'fn_def_with_doc_impl short'
+ // @has - 'fn_def_with_doc_impl full'
+ /// fn_def_with_doc_impl short
+ ///
+ /// fn_def_with_doc_impl full
+ fn fn_def_with_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc'
+ fn fn_def_without_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc'
+ // @has - 'fn_def_def_with_doc short'
+ // @!has - 'fn_def_def_with_doc full'
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc'
+}
+
+// @has foo/struct.Foo2.html
+pub struct Foo2;
+
+impl Bar for Foo2 {
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc'
+ // @has - 'fn_empty_with_doc short'
+ // @!has - 'fn_empty_with_doc full'
+ fn fn_empty_with_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc'
+ // @has - 'fn_empty_without_doc_impl short'
+ // @has - 'fn_empty_without_doc_impl full'
+ /// fn_empty_without_doc_impl short
+ ///
+ /// fn_empty_without_doc_impl full
+ fn fn_empty_without_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc'
+ // @has - 'fn_def_with_doc short'
+ // @!has - 'fn_def_with_doc full'
+ fn fn_def_with_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc'
+ // @has - 'fn_def_without_doc_impl short'
+ // @has - 'fn_def_without_doc_impl full'
+ /// fn_def_without_doc_impl short
+ ///
+ /// fn_def_without_doc_impl full
+ fn fn_def_without_doc() {}
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc'
+ // @has - 'fn_def_def_with_doc short'
+ // @!has - 'fn_def_def_with_doc full'
+
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc'
+}
diff --git a/src/test/rustdoc/deprecated.rs b/src/test/rustdoc/deprecated.rs
new file mode 100644
index 000000000..b3178da98
--- /dev/null
+++ b/src/test/rustdoc/deprecated.rs
@@ -0,0 +1,33 @@
+// @has deprecated/index.html '//*[@class="item-left module-item"]/span[@class="stab deprecated"]' \
+// 'Deprecated'
+// @has - '//*[@class="item-right docblock-short"]' 'Deprecated docs'
+
+// @has deprecated/struct.S.html '//*[@class="stab deprecated"]' \
+// 'Deprecated since 1.0.0: text'
+/// Deprecated docs
+#[deprecated(since = "1.0.0", note = "text")]
+pub struct S;
+
+// @matches deprecated/index.html '//*[@class="item-right docblock-short"]' '^Docs'
+/// Docs
+pub struct T;
+
+// @matches deprecated/struct.U.html '//*[@class="stab deprecated"]' \
+// 'Deprecated since 1.0.0$'
+#[deprecated(since = "1.0.0")]
+pub struct U;
+
+// @matches deprecated/struct.V.html '//*[@class="stab deprecated"]' \
+// 'Deprecated: text$'
+#[deprecated(note = "text")]
+pub struct V;
+
+// @matches deprecated/struct.W.html '//*[@class="stab deprecated"]' \
+// 'Deprecated$'
+#[deprecated]
+pub struct W;
+
+// @matches deprecated/struct.X.html '//*[@class="stab deprecated"]' \
+// 'Deprecated: shorthand reason$'
+#[deprecated = "shorthand reason"]
+pub struct X;
diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs
new file mode 100644
index 000000000..8ecca6d12
--- /dev/null
+++ b/src/test/rustdoc/deref-const-fn.rs
@@ -0,0 +1,38 @@
+// This test ensures that the const methods from Deref aren't shown as const.
+// For more information, see https://github.com/rust-lang/rust/issues/90855.
+
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// @has 'foo/struct.Bar.html'
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+ // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize'
+ // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+ pub const fn len(&self) -> usize { 0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Foo {
+ value: Bar,
+}
+
+// @has 'foo/struct.Foo.html'
+// @has - '//*[@id="method.len"]' 'pub fn len(&self) -> usize'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '(const: 1.0.0)'
+#[stable(feature = "rust1", since = "1.0.0")]
+impl std::ops::Deref for Foo {
+ type Target = Bar;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
diff --git a/src/test/rustdoc/deref-mut-methods.rs b/src/test/rustdoc/deref-mut-methods.rs
new file mode 100644
index 000000000..fdf843422
--- /dev/null
+++ b/src/test/rustdoc/deref-mut-methods.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+use std::ops;
+
+pub struct Foo;
+
+impl Foo {
+ pub fn foo(&mut self) {}
+}
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo'
+pub struct Bar {
+ foo: Foo,
+}
+
+impl ops::Deref for Bar {
+ type Target = Foo;
+
+ fn deref(&self) -> &Foo {
+ &self.foo
+ }
+}
+
+impl ops::DerefMut for Bar {
+ fn deref_mut(&mut self) -> &mut Foo {
+ &mut self.foo
+ }
+}
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
new file mode 100644
index 000000000..746df9c80
--- /dev/null
+++ b/src/test/rustdoc/deref-recursive-pathbuf.rs
@@ -0,0 +1,25 @@
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels and across multiple crates.
+// For `Deref` on non-foreign types, look at `deref-recursive.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
+// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+use std::path::PathBuf;
+
+pub struct Foo(PathBuf);
+
+impl Deref for Foo {
+ type Target = PathBuf;
+ fn deref(&self) -> &PathBuf { &self.0 }
+}
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
new file mode 100644
index 000000000..d5f8473f2
--- /dev/null
+++ b/src/test/rustdoc/deref-recursive.rs
@@ -0,0 +1,41 @@
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels if needed.
+// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
+// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+
+pub struct Foo(Bar);
+pub struct Bar(Baz);
+pub struct Baz;
+
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar { &self.0 }
+}
+
+impl Deref for Bar {
+ type Target = Baz;
+ fn deref(&self) -> &Baz { &self.0 }
+}
+
+impl Bar {
+ /// This appears under `Foo` methods
+ pub fn bar(&self) {}
+}
+
+impl Baz {
+ /// This should also appear in `Foo` methods when recursing
+ pub fn baz(&self) {}
+}
diff --git a/src/test/rustdoc/deref-slice-core.rs b/src/test/rustdoc/deref-slice-core.rs
new file mode 100644
index 000000000..cccf273a8
--- /dev/null
+++ b/src/test/rustdoc/deref-slice-core.rs
@@ -0,0 +1,22 @@
+// https://github.com/rust-lang/rust/issues/95325
+//
+// Show methods reachable from Deref of primitive.
+#![no_std]
+
+use core::ops::Deref;
+
+// @has 'deref_slice_core/struct.MyArray.html'
+// @has '-' '//*[@id="deref-methods-%5BT%5D"]' 'Methods from Deref<Target = [T]>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.len"]' 'pub fn len(&self)'
+
+pub struct MyArray<T> {
+ array: [T; 10],
+}
+
+impl<T> Deref for MyArray<T> {
+ type Target = [T];
+
+ fn deref(&self) -> &Self::Target {
+ &self.array
+ }
+}
diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs
new file mode 100644
index 000000000..28f977e31
--- /dev/null
+++ b/src/test/rustdoc/deref-typedef.rs
@@ -0,0 +1,46 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Bar.html'
+// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_j"]' 'foo_j'
+
+pub struct FooA;
+pub type FooB = FooA;
+pub type FooC = FooB;
+pub type FooD = FooC;
+pub type FooE = FooD;
+pub type FooF = FooE;
+pub type FooG = FooF;
+pub type FooH = FooG;
+pub type FooI = FooH;
+pub type FooJ = FooI;
+
+impl FooA {
+ pub fn foo_a(&self) {}
+}
+
+impl FooB {
+ pub fn foo_b(&self) {}
+}
+
+impl FooC {
+ pub fn foo_c(&self) {}
+}
+
+impl FooJ {
+ pub fn foo_j(&self) {}
+}
+
+pub struct Bar;
+impl std::ops::Deref for Bar {
+ type Target = FooJ;
+ fn deref(&self) -> &Self::Target { unimplemented!() }
+}
diff --git a/src/test/rustdoc/description.rs b/src/test/rustdoc/description.rs
new file mode 100644
index 000000000..05ec42822
--- /dev/null
+++ b/src/test/rustdoc/description.rs
@@ -0,0 +1,24 @@
+#![crate_name = "foo"]
+//! # Description test crate
+//!
+//! This is the contents of the test crate docstring.
+//! It should not show up in the description.
+
+// @has 'foo/index.html' '//meta[@name="description"]/@content' \
+// 'Description test crate'
+// @!has - '//meta[@name="description"]/@content' 'should not show up'
+
+// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \
+// 'First paragraph description.'
+// @!has - '//meta[@name="description"]/@content' 'Second paragraph'
+/// First paragraph description.
+///
+/// Second paragraph should not show up.
+pub mod foo_mod {
+ pub struct __Thing {}
+}
+
+// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \
+// 'Only paragraph.'
+/// Only paragraph.
+pub fn foo_fn() {}
diff --git a/src/test/rustdoc/description_default.rs b/src/test/rustdoc/description_default.rs
new file mode 100644
index 000000000..21d8e04d3
--- /dev/null
+++ b/src/test/rustdoc/description_default.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+// @has 'foo/index.html' '//meta[@name="description"]/@content' \
+// 'API documentation for the Rust `foo` crate.'
+
+// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \
+// 'API documentation for the Rust `foo_mod` mod in crate `foo`.'
+pub mod foo_mod {
+ pub struct __Thing {}
+}
+
+// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \
+// 'API documentation for the Rust `foo_fn` fn in crate `foo`.'
+pub fn foo_fn() {}
diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs
new file mode 100644
index 000000000..4f1541865
--- /dev/null
+++ b/src/test/rustdoc/doc-assoc-item.rs
@@ -0,0 +1,18 @@
+pub struct Foo<T> {
+ x: T,
+}
+
+pub trait Bar {
+ type Fuu;
+
+ fn foo(foo: Self::Fuu);
+}
+
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+impl<T: Bar<Fuu = u32>> Foo<T> {
+ pub fn new(t: T) -> Foo<T> {
+ Foo {
+ x: t,
+ }
+ }
+}
diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs
new file mode 100644
index 000000000..7842ee69c
--- /dev/null
+++ b/src/test/rustdoc/doc-auto-cfg.rs
@@ -0,0 +1,35 @@
+#![feature(doc_auto_cfg)]
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-meowmeow'
+#[cfg(not(meowmeow))]
+pub fn foo() {}
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doctest'
+#[cfg(any(meowmeow, test, doc, doctest))]
+pub fn bar() {}
+
+// @has foo/fn.appear_1.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
+#[cfg(any(meowmeow, doc, not(test)))]
+pub fn appear_1() {} // issue #98065
+
+// @has foo/fn.appear_2.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test'
+#[cfg(any(meowmeow, doc, all(test)))]
+pub fn appear_2() {} // issue #98065
+
+// @has foo/fn.appear_3.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+#[cfg(any(meowmeow, doc, all()))]
+pub fn appear_3() {} // issue #98065
diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs
new file mode 100644
index 000000000..636957fe9
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-hide.rs
@@ -0,0 +1,32 @@
+#![crate_name = "oud"]
+#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)]
+
+#![doc(cfg_hide(feature = "solecism"))]
+
+// @has 'oud/struct.Solecism.html'
+// @count - '//*[@class="stab portability"]' 0
+// compile-flags:--cfg feature="solecism"
+#[cfg(feature = "solecism")]
+pub struct Solecism;
+
+// @has 'oud/struct.Scribacious.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature solecism'
+#[cfg(feature = "solecism")]
+#[doc(cfg(feature = "solecism"))]
+pub struct Scribacious;
+
+// @has 'oud/struct.Hyperdulia.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia'
+// compile-flags:--cfg feature="hyperdulia"
+#[cfg(feature = "solecism")]
+#[cfg(feature = "hyperdulia")]
+pub struct Hyperdulia;
+
+// @has 'oud/struct.Oystercatcher.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only'
+// compile-flags:--cfg feature="oystercatcher"
+#[cfg(all(feature = "solecism", feature = "oystercatcher"))]
+pub struct Oystercatcher;
diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs
new file mode 100644
index 000000000..92804d372
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs
@@ -0,0 +1,7 @@
+// compile-flags:--cfg feature="worricow"
+#![crate_name = "xenogenous"]
+
+// @has 'xenogenous/struct.Worricow.html'
+// @count - '//*[@class="stab portability"]' 0
+#[cfg(feature = "worricow")]
+pub struct Worricow;
diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs
new file mode 100644
index 000000000..5d17a4ede
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-implicit.rs
@@ -0,0 +1,31 @@
+#![crate_name = "funambulism"]
+#![feature(doc_auto_cfg, doc_cfg)]
+
+// @has 'funambulism/struct.Disorbed.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature disorbed'
+// compile-flags:--cfg feature="disorbed"
+#[cfg(feature = "disorbed")]
+pub struct Disorbed;
+
+// @has 'funambulism/struct.Aesthesia.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia'
+// compile-flags:--cfg feature="aesthesia"
+#[doc(cfg(feature = "aesthesia"))]
+pub struct Aesthesia;
+
+// @has 'funambulism/struct.Pliothermic.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic'
+// compile-flags:--cfg feature="epopoeist"
+#[cfg(feature = "epopoeist")]
+#[doc(cfg(feature = "pliothermic"))]
+pub struct Pliothermic;
+
+// @has 'funambulism/struct.Simillimum.html'
+// @count - '//*[@class="stab portability"]' 0
+// compile-flags:--cfg feature="simillimum"
+#[cfg(feature = "simillimum")]
+#[doc(cfg(all()))]
+pub struct Simillimum;
diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs
new file mode 100644
index 000000000..633df661b
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-simplification.rs
@@ -0,0 +1,182 @@
+#![crate_name = "globuliferous"]
+#![feature(doc_cfg)]
+
+// @has 'globuliferous/index.html'
+// @count - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' '^ratel$'
+
+// @has 'globuliferous/ratel/index.html'
+// @count - '//*[@class="stab portability"]' 8
+// @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+// @matches - '//*[@class="stab portability"]' '^zoonosology$'
+// @matches - '//*[@class="stab portability"]' '^yusho$'
+// @matches - '//*[@class="stab portability"]' '^nunciative$'
+// @matches - '//*[@class="stab portability"]' '^thionic$'
+// @matches - '//*[@class="stab portability"]' '^zincic$'
+// @matches - '//*[@class="stab portability"]' '^cosmotellurian$'
+// @matches - '//*[@class="stab portability"]' '^aposiopesis$'
+#[doc(cfg(feature = "ratel"))]
+pub mod ratel {
+ // @has 'globuliferous/ratel/fn.ovicide.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ pub fn ovicide() {}
+
+ // @has 'globuliferous/ratel/fn.zoonosology.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology'
+ #[doc(cfg(feature = "zoonosology"))]
+ pub fn zoonosology() {}
+
+ // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ pub const DIAGRAPHICS: () = ();
+
+ // @has 'globuliferous/ratel/constant.YUSHO.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho'
+ #[doc(cfg(feature = "yusho"))]
+ pub const YUSHO: () = ();
+
+ // @has 'globuliferous/ratel/static.KEYBUGLE.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ pub static KEYBUGLE: () = ();
+
+ // @has 'globuliferous/ratel/static.NUNCIATIVE.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative'
+ #[doc(cfg(feature = "nunciative"))]
+ pub static NUNCIATIVE: () = ();
+
+ // @has 'globuliferous/ratel/type.Wrick.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ pub type Wrick = ();
+
+ // @has 'globuliferous/ratel/type.Thionic.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic'
+ #[doc(cfg(feature = "thionic"))]
+ pub type Thionic = ();
+
+ // @has 'globuliferous/ratel/struct.Eventration.html'
+ // @count - '//*[@class="stab portability"]' 1
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ pub struct Eventration;
+
+ // @has 'globuliferous/ratel/struct.Zincic.html'
+ // @count - '//*[@class="stab portability"]' 2
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic'
+ // @matches - '//*[@class="stab portability"]' 'crate feature rutherford'
+ #[doc(cfg(feature = "zincic"))]
+ pub struct Zincic {
+ pub rectigrade: (),
+
+ #[doc(cfg(feature = "rutherford"))]
+ pub rutherford: (),
+ }
+
+ // @has 'globuliferous/ratel/enum.Cosmotellurian.html'
+ // @count - '//*[@class="stab portability"]' 10
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian'
+ // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy'
+ // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus'
+ // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive'
+ // @matches - '//*[@class="stab portability"]' 'crate feature fuero'
+ // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile'
+ // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+ // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic'
+ // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+ // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever'
+ #[doc(cfg(feature = "cosmotellurian"))]
+ pub enum Cosmotellurian {
+ Groundsel {
+ jagger: (),
+
+ #[doc(cfg(feature = "xiphopagus"))]
+ xiphopagus: (),
+ },
+
+ #[doc(cfg(feature = "biotaxy"))]
+ Biotaxy {
+ glossography: (),
+
+ #[doc(cfg(feature = "juxtapositive"))]
+ juxtapositive: (),
+ },
+ }
+
+ impl Cosmotellurian {
+ pub fn uxoricide() {}
+
+ #[doc(cfg(feature = "fuero"))]
+ pub fn fuero() {}
+
+ pub const MAMELLE: () = ();
+
+ #[doc(cfg(feature = "palaeophile"))]
+ pub const PALAEOPHILE: () = ();
+ }
+
+ #[doc(cfg(feature = "broadcloth"))]
+ impl Cosmotellurian {
+ pub fn trabeculated() {}
+
+ #[doc(cfg(feature = "xanthocomic"))]
+ pub fn xanthocomic() {}
+
+ pub const BRACHIFEROUS: () = ();
+
+ #[doc(cfg(feature = "whosoever"))]
+ pub const WHOSOEVER: () = ();
+ }
+
+ // @has 'globuliferous/ratel/trait.Gnotobiology.html'
+ // @count - '//*[@class="stab portability"]' 4
+ // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+ // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic'
+ // @matches - '//*[@class="stab portability"]' 'crate feature summate'
+ // @matches - '//*[@class="stab portability"]' 'crate feature unctuous'
+ pub trait Gnotobiology {
+ const XYLOTHERAPY: ();
+
+ #[doc(cfg(feature = "unzymotic"))]
+ const UNZYMOTIC: ();
+
+ type Lepadoid;
+
+ #[doc(cfg(feature = "summate"))]
+ type Summate;
+
+ fn decalcomania();
+
+ #[doc(cfg(feature = "unctuous"))]
+ fn unctuous();
+ }
+
+ // @has 'globuliferous/ratel/trait.Aposiopesis.html'
+ // @count - '//*[@class="stab portability"]' 4
+ // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis'
+ // @matches - '//*[@class="stab portability"]' 'crate feature umbracious'
+ // @matches - '//*[@class="stab portability"]' 'crate feature uakari'
+ // @matches - '//*[@class="stab portability"]' 'crate feature rotograph'
+ #[doc(cfg(feature = "aposiopesis"))]
+ pub trait Aposiopesis {
+ const REDHIBITION: ();
+
+ #[doc(cfg(feature = "umbracious"))]
+ const UMBRACIOUS: ();
+
+ type Ophthalmoscope;
+
+ #[doc(cfg(feature = "uakari"))]
+ type Uakari;
+
+ fn meseems();
+
+ #[doc(cfg(feature = "rotograph"))]
+ fn rotograph();
+ }
+}
diff --git a/src/test/rustdoc/doc-cfg-target-feature.rs b/src/test/rustdoc/doc-cfg-target-feature.rs
new file mode 100644
index 000000000..f1b000dc8
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-target-feature.rs
@@ -0,0 +1,21 @@
+// only-x86_64
+// compile-flags:--test
+// should-fail
+// no-system-llvm
+
+// #49723: rustdoc didn't add target features when extracting or running doctests
+
+#![feature(doc_cfg)]
+
+/// Foo
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cfg_target_feature)]
+///
+/// #[cfg(target_feature = "sse")]
+/// assert!(false);
+/// ```
+#[doc(cfg(target_feature = "sse"))]
+pub unsafe fn foo() {}
diff --git a/src/test/rustdoc/doc-cfg-traits.rs b/src/test/rustdoc/doc-cfg-traits.rs
new file mode 100644
index 000000000..13407b2c7
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-traits.rs
@@ -0,0 +1,124 @@
+#![crate_name = "myrmecophagous"]
+#![feature(doc_cfg, associated_type_defaults)]
+
+// @has 'myrmecophagous/index.html'
+// @count - '//*[@class="stab portability"]' 2
+// @matches - '//*[@class="stab portability"]' '^jurisconsult$'
+// @matches - '//*[@class="stab portability"]' '^quarter$'
+
+pub trait Lea {}
+
+// @has 'myrmecophagous/trait.Vortoscope.html'
+// @count - '//*[@class="stab portability"]' 6
+// @matches - '//*[@class="stab portability"]' 'crate feature zibib'
+// @matches - '//*[@class="stab portability"]' 'crate feature poriform'
+// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia'
+// @matches - '//*[@class="stab portability"]' 'crate feature lea'
+// @matches - '//*[@class="stab portability"]' 'crate feature unit'
+// @matches - '//*[@class="stab portability"]' 'crate feature quarter'
+pub trait Vortoscope {
+ type Batology = ();
+
+ #[doc(cfg(feature = "zibib"))]
+ type Zibib = ();
+
+ const YAHRZEIT: () = ();
+
+ #[doc(cfg(feature = "poriform"))]
+ const PORIFORM: () = ();
+
+ fn javanais() {}
+
+ #[doc(cfg(feature = "ethopoeia"))]
+ fn ethopoeia() {}
+}
+
+#[doc(cfg(feature = "lea"))]
+impl<T: Lea> Vortoscope for T {}
+
+#[doc(cfg(feature = "unit"))]
+impl Vortoscope for () {}
+
+// @has 'myrmecophagous/trait.Jurisconsult.html'
+// @count - '//*[@class="stab portability"]' 7
+// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult'
+// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy'
+// @matches - '//*[@class="stab portability"]' 'crate feature boodle'
+// @matches - '//*[@class="stab portability"]' 'crate feature mistetch'
+// @matches - '//*[@class="stab portability"]' 'crate feature lea'
+// @matches - '//*[@class="stab portability"]' 'crate feature unit'
+// @matches - '//*[@class="stab portability"]' 'crate feature quarter'
+#[doc(cfg(feature = "jurisconsult"))]
+pub trait Jurisconsult {
+ type Urbanist = ();
+
+ #[doc(cfg(feature = "lithomancy"))]
+ type Lithomancy = ();
+
+ const UNIFILAR: () = ();
+
+ #[doc(cfg(feature = "boodle"))]
+ const BOODLE: () = ();
+
+ fn mersion() {}
+
+ #[doc(cfg(feature = "mistetch"))]
+ fn mistetch() {}
+}
+
+#[doc(cfg(feature = "lea"))]
+impl<T: Lea> Jurisconsult for T {}
+
+#[doc(cfg(feature = "unit"))]
+impl Jurisconsult for () {}
+
+// @has 'myrmecophagous/struct.Ultimogeniture.html'
+// @count - '//*[@class="stab portability"]' 8
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature zibib'
+// @matches - '//*[@class="stab portability"]' 'crate feature poriform'
+// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia'
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult'
+// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy'
+// @matches - '//*[@class="stab portability"]' 'crate feature boodle'
+// @matches - '//*[@class="stab portability"]' 'crate feature mistetch'
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature copy'
+#[derive(Clone)]
+pub struct Ultimogeniture;
+
+impl Vortoscope for Ultimogeniture {}
+
+#[doc(cfg(feature = "jurisconsult"))]
+impl Jurisconsult for Ultimogeniture {}
+
+#[doc(cfg(feature = "copy"))]
+impl Copy for Ultimogeniture {}
+
+// @has 'myrmecophagous/struct.Quarter.html'
+// @count - '//*[@class="stab portability"]' 9
+// @matches - '//*[@class="stab portability"]' 'crate feature quarter'
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature zibib'
+// @matches - '//*[@class="stab portability"]' 'crate feature poriform'
+// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia'
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult'
+// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy'
+// @matches - '//*[@class="stab portability"]' 'crate feature boodle'
+// @matches - '//*[@class="stab portability"]' 'crate feature mistetch'
+//
+// @matches - '//*[@class="stab portability"]' 'crate feature copy'
+#[doc(cfg(feature = "quarter"))]
+#[derive(Clone)]
+pub struct Quarter;
+
+#[doc(cfg(feature = "quarter"))]
+impl Vortoscope for Quarter {}
+
+#[doc(cfg(all(feature = "jurisconsult", feature = "quarter")))]
+impl Jurisconsult for Quarter {}
+
+#[doc(cfg(all(feature = "copy", feature = "quarter")))]
+impl Copy for Quarter {}
diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs
new file mode 100644
index 000000000..4cddb0b76
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg.rs
@@ -0,0 +1,101 @@
+#![feature(doc_cfg)]
+#![feature(target_feature, cfg_target_feature)]
+
+// @has doc_cfg/struct.Portable.html
+// @!has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' ''
+// @has - '//*[@id="method.unix_and_arm_only_function"]' 'fn unix_and_arm_only_function()'
+// @has - '//*[@class="stab portability"]' 'Available on Unix and ARM only.'
+// @has - '//*[@id="method.wasi_and_wasm32_only_function"]' 'fn wasi_and_wasm32_only_function()'
+// @has - '//*[@class="stab portability"]' 'Available on WASI and WebAssembly only.'
+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-left module-item"]//*[@class="stab portability"]' '\AARM\Z'
+// @count - '//*[@class="stab portability"]' 2
+#[doc(cfg(unix))]
+pub mod unix_only {
+ // @has doc_cfg/unix_only/fn.unix_only_function.html \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // 'Available on Unix only.'
+ // @count - '//*[@class="stab portability"]' 1
+ pub fn unix_only_function() {
+ content::should::be::irrelevant();
+ }
+
+ // @has doc_cfg/unix_only/trait.ArmOnly.html \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // 'Available on Unix and ARM only.'
+ // @count - '//*[@class="stab portability"]' 1
+ #[doc(cfg(target_arch = "arm"))]
+ pub trait ArmOnly {
+ fn unix_and_arm_only_function();
+ }
+
+ #[doc(cfg(target_arch = "arm"))]
+ impl ArmOnly for super::Portable {
+ fn unix_and_arm_only_function() {}
+ }
+}
+
+// @has doc_cfg/wasi_only/index.html \
+// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// 'Available on WASI only.'
+// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z'
+// @count - '//*[@class="stab portability"]' 2
+#[doc(cfg(target_os = "wasi"))]
+pub mod wasi_only {
+ // @has doc_cfg/wasi_only/fn.wasi_only_function.html \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // 'Available on WASI only.'
+ // @count - '//*[@class="stab portability"]' 1
+ pub fn wasi_only_function() {
+ content::should::be::irrelevant();
+ }
+
+ // @has doc_cfg/wasi_only/trait.Wasm32Only.html \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // 'Available on WASI and WebAssembly only.'
+ // @count - '//*[@class="stab portability"]' 1
+ #[doc(cfg(target_arch = "wasm32"))]
+ pub trait Wasm32Only {
+ fn wasi_and_wasm32_only_function();
+ }
+
+ #[doc(cfg(target_arch = "wasm32"))]
+ impl Wasm32Only for super::Portable {
+ fn wasi_and_wasm32_only_function() {}
+ }
+}
+
+// tagging a function with `#[target_feature]` creates a doc(cfg(target_feature)) node for that
+// item as well
+
+// the portability header is different on the module view versus the full view
+// @has doc_cfg/index.html
+// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z'
+
+// @has doc_cfg/fn.uses_target_feature.html
+// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// 'Available with target feature avx only.'
+#[target_feature(enable = "avx")]
+pub unsafe fn uses_target_feature() {
+ content::should::be::irrelevant();
+}
+
+// @has doc_cfg/fn.uses_cfg_target_feature.html
+// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// 'Available with target feature avx only.'
+#[doc(cfg(target_feature = "avx"))]
+pub fn uses_cfg_target_feature() {
+ uses_target_feature();
+}
+
+// multiple attributes should be allowed
+// @has doc_cfg/fn.multiple_attrs.html \
+// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// 'Available on x and y and z only.'
+#[doc(cfg(x))]
+#[doc(cfg(y), cfg(z))]
+pub fn multiple_attrs() {}
diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs
new file mode 100644
index 000000000..bfce46cf4
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs
@@ -0,0 +1,23 @@
+//! Test case for [#80737].
+//!
+//! A SomeTrait that is implemented for `&mut T where T: SomeTrait`
+//! should not be marked as "notable" for return values that do not
+//! have bounds on the trait itself.
+//!
+//! [#80737]: https://github.com/rust-lang/rust/issues/80737
+
+#![feature(rustdoc_internals)]
+#![no_std]
+
+#[doc(primitive = "reference")]
+/// Some useless docs, wouhou!
+///
+/// We need to put this in here, because notable traits
+/// that are implemented on foreign types don't show up.
+mod reference {}
+
+// @has doc_notable_trait_mut_t_is_not_an_iterator/fn.fn_no_matches.html
+// @!has - '//code[@class="content"]' 'Iterator'
+pub fn fn_no_matches<'a, T: 'a>() -> &'a mut T {
+ panic!()
+}
diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
new file mode 100644
index 000000000..b359dcea0
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
@@ -0,0 +1,21 @@
+//! Test case for [#78160].
+//!
+//! A SomeTrait that is implemented for `&mut T` should not be marked as
+//! "notable" for return values that are `&T`.
+//!
+//! [#78160]: https://github.com/rust-lang/rust/issues/78160
+
+#![feature(rustdoc_internals)]
+
+#[doc(primitive = "reference")]
+/// Some useless docs, wouhou!
+///
+/// We need to put this in here, because notable traits
+/// that are implemented on foreign types don't show up.
+mod reference {}
+
+// @has doc_notable_trait_mut_t_is_not_ref_t/fn.fn_no_matches.html
+// @!has - '//code[@class="content"]' "impl<'_, I> Iterator for &'_ mut I"
+pub fn fn_no_matches<'a, T: Iterator + 'a>() -> &'a T {
+ loop {}
+}
diff --git a/src/test/rustdoc/doc-notable_trait-slice.rs b/src/test/rustdoc/doc-notable_trait-slice.rs
new file mode 100644
index 000000000..b0d414027
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-slice.rs
@@ -0,0 +1,20 @@
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+pub struct OtherStruct;
+impl SomeTrait for &[SomeStruct] {}
+
+// @has doc_notable_trait_slice/fn.bare_fn_matches.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_matches() -> &'static [SomeStruct] {
+ &[]
+}
+
+// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
+// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
+ &[]
+}
diff --git a/src/test/rustdoc/doc-notable_trait.rs b/src/test/rustdoc/doc-notable_trait.rs
new file mode 100644
index 000000000..58a24b855
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait.rs
@@ -0,0 +1,36 @@
+#![feature(doc_notable_trait)]
+
+pub struct Wrapper<T> {
+ inner: T,
+}
+
+impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
+
+#[doc(notable_trait)]
+pub trait SomeTrait {
+ // @has doc_notable_trait/trait.SomeTrait.html
+ // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+ fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
+ Wrapper {
+ inner: self,
+ }
+ }
+}
+
+pub struct SomeStruct;
+impl SomeTrait for SomeStruct {}
+
+impl SomeStruct {
+ // @has doc_notable_trait/struct.SomeStruct.html
+ // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
+ // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+ pub fn new() -> SomeStruct {
+ SomeStruct
+ }
+}
+
+// @has doc_notable_trait/fn.bare_fn.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
+pub fn bare_fn() -> SomeStruct {
+ SomeStruct
+}
diff --git a/src/test/rustdoc/doc-proc-macro.rs b/src/test/rustdoc/doc-proc-macro.rs
new file mode 100644
index 000000000..19172ffa4
--- /dev/null
+++ b/src/test/rustdoc/doc-proc-macro.rs
@@ -0,0 +1,8 @@
+// Issue #52129: ICE when trying to document the `quote` proc-macro from proc_macro
+
+// As of this writing, we don't currently attempt to document proc-macros. However, we shouldn't
+// crash when we try.
+
+extern crate proc_macro;
+
+pub use proc_macro::*;
diff --git a/src/test/rustdoc/doctest-manual-crate-name.rs b/src/test/rustdoc/doctest-manual-crate-name.rs
new file mode 100644
index 000000000..3a5e3734e
--- /dev/null
+++ b/src/test/rustdoc/doctest-manual-crate-name.rs
@@ -0,0 +1,7 @@
+// compile-flags:--test
+
+//! ```
+//! #![crate_name="asdf"]
+//!
+//! println!("yo");
+//! ```
diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs
new file mode 100644
index 000000000..350c89741
--- /dev/null
+++ b/src/test/rustdoc/double-quote-escape.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+
+pub trait Foo<T> {
+ fn foo() {}
+}
+
+pub struct Bar;
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>'
+impl Foo<unsafe extern "C" fn()> for Bar {}
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
new file mode 100644
index 000000000..18f3900b2
--- /dev/null
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -0,0 +1,53 @@
+#![crate_name = "foo"]
+#![feature(doc_cfg)]
+
+// @has 'foo/index.html'
+// @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$'
+// @has '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@class="stab portability"]' 'sync'
+#[doc(cfg(feature = "sync"))]
+#[doc(cfg(feature = "sync"))]
+/// my feature sync struct
+pub struct Foo;
+
+// @has 'foo/bar/index.html'
+// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.'
+#[doc(cfg(feature = "sync"))]
+pub mod bar {
+ // @has 'foo/bar/struct.Bar.html'
+ // @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.'
+ #[doc(cfg(feature = "sync"))]
+ pub struct Bar;
+}
+
+// @has 'foo/baz/index.html'
+// @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.'
+#[doc(cfg(all(feature = "sync", feature = "send")))]
+pub mod baz {
+ // @has 'foo/baz/struct.Baz.html'
+ // @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.'
+ #[doc(cfg(feature = "sync"))]
+ pub struct Baz;
+}
+
+// @has 'foo/qux/index.html'
+// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.'
+#[doc(cfg(feature = "sync"))]
+pub mod qux {
+ // @has 'foo/qux/struct.Qux.html'
+ // @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.'
+ #[doc(cfg(all(feature = "sync", feature = "send")))]
+ pub struct Qux;
+}
+
+// @has 'foo/quux/index.html'
+// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync and crate feature send and foo only.'
+#[doc(cfg(all(feature = "sync", feature = "send", foo)))]
+pub mod quux {
+ // @has 'foo/quux/struct.Quux.html'
+ // @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync and crate feature send and foo and bar only.'
+ #[doc(cfg(all(feature = "send", feature = "sync", bar)))]
+ pub struct Quux;
+}
diff --git a/src/test/rustdoc/duplicate-flags.rs b/src/test/rustdoc/duplicate-flags.rs
new file mode 100644
index 000000000..dde36df2c
--- /dev/null
+++ b/src/test/rustdoc/duplicate-flags.rs
@@ -0,0 +1,4 @@
+// compile-flags: --document-private-items --document-private-items
+
+// @has duplicate_flags/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/duplicate_impls/impls.rs b/src/test/rustdoc/duplicate_impls/impls.rs
new file mode 100644
index 000000000..6875ad272
--- /dev/null
+++ b/src/test/rustdoc/duplicate_impls/impls.rs
@@ -0,0 +1,12 @@
+pub struct Foo;
+
+// just so that `Foo` doesn't show up on `Bar`s sidebar
+pub mod bar {
+ pub trait Bar {}
+}
+
+impl Foo {
+ pub fn new() -> Foo { Foo }
+}
+
+impl bar::Bar for Foo {}
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
new file mode 100644
index 000000000..84c9e4ac0
--- /dev/null
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -0,0 +1,14 @@
+// ignore-tidy-linelength
+
+// @has issue_33054/impls/struct.Foo.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Foo'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
+// @has issue_33054/impls/bar/trait.Bar.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
+// @count - '//*[@class="struct"]' 1
+pub mod impls;
+
+#[doc(inline)]
+pub use impls as impls2;
diff --git a/src/test/rustdoc/duplicated_impl.rs b/src/test/rustdoc/duplicated_impl.rs
new file mode 100644
index 000000000..4e901b31c
--- /dev/null
+++ b/src/test/rustdoc/duplicated_impl.rs
@@ -0,0 +1,14 @@
+// This test ensures that the same implementation doesn't show more than once.
+// It's a regression test for https://github.com/rust-lang/rust/issues/96036.
+
+#![crate_name = "foo"]
+
+// We check that there is only one "impl<T> Something<Whatever> for T" listed in the
+// blanket implementations.
+
+// @has 'foo/struct.Whatever.html'
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+
+pub trait Something<T> { }
+pub struct Whatever;
+impl<T> Something<Whatever> for T {}
diff --git a/src/test/rustdoc/early-unindent.rs b/src/test/rustdoc/early-unindent.rs
new file mode 100644
index 000000000..791a452c9
--- /dev/null
+++ b/src/test/rustdoc/early-unindent.rs
@@ -0,0 +1,26 @@
+// This is a regression for https://github.com/rust-lang/rust/issues/96079.
+
+#![crate_name = "foo"]
+
+pub mod app {
+ pub struct S;
+
+ impl S {
+ // @has 'foo/app/struct.S.html'
+ // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name'
+ /**
+ Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`).
+ */
+ pub fn whatever(&self) {}
+ }
+}
+
+pub mod enums {
+ pub enum Foo {
+ Bar,
+ }
+
+ impl Foo {
+ pub fn by_name(&self) {}
+ }
+}
diff --git a/src/test/rustdoc/edition-doctest.rs b/src/test/rustdoc/edition-doctest.rs
new file mode 100644
index 000000000..6de25996b
--- /dev/null
+++ b/src/test/rustdoc/edition-doctest.rs
@@ -0,0 +1,44 @@
+// compile-flags:--test
+
+/// ```rust,edition2018
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+/// "1".parse::<i32>()?
+/// + "2".parse::<i32>()?
+/// + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+/// "1".parse::<i32>()?
+/// + "foo".parse::<i32>()?
+/// + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+
+/// ```rust,edition2015,compile_fail,E0574
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+/// "1".parse::<i32>()?
+/// + "2".parse::<i32>()?
+/// + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+/// "1".parse::<i32>()?
+/// + "foo".parse::<i32>()?
+/// + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+pub fn foo() {}
diff --git a/src/test/rustdoc/edition-flag.rs b/src/test/rustdoc/edition-flag.rs
new file mode 100644
index 000000000..e54c7d296
--- /dev/null
+++ b/src/test/rustdoc/edition-flag.rs
@@ -0,0 +1,11 @@
+// compile-flags:--test
+// edition:2018
+
+/// ```rust
+/// fn main() {
+/// let _ = async { };
+/// }
+/// ```
+fn main() {
+ let _ = async { };
+}
diff --git a/src/test/rustdoc/elided-lifetime.rs b/src/test/rustdoc/elided-lifetime.rs
new file mode 100644
index 000000000..5a32554f9
--- /dev/null
+++ b/src/test/rustdoc/elided-lifetime.rs
@@ -0,0 +1,43 @@
+// aux-build:elided-lifetime.rs
+//
+// rust-lang/rust#75225
+//
+// Since Rust 2018 we encourage writing out <'_> explicitly to make it clear
+// that borrowing is occuring. Make sure rustdoc is following the same idiom.
+
+#![crate_name = "foo"]
+
+pub struct Ref<'a>(&'a u32);
+type ARef<'a> = Ref<'a>;
+
+// @has foo/fn.test1.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test1(a: &u32) -> Ref {
+ Ref(a)
+}
+
+// @has foo/fn.test2.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test2(a: &u32) -> Ref<'_> {
+ Ref(a)
+}
+
+// @has foo/fn.test3.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test3(a: &u32) -> ARef {
+ Ref(a)
+}
+
+// @has foo/fn.test4.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test4(a: &u32) -> ARef<'_> {
+ Ref(a)
+}
+
+// Ensure external paths in inlined docs also display elided lifetime
+// @has foo/bar/fn.test5.html
+// @matches - "Ref</a>&lt;'_&gt;"
+// @has foo/bar/fn.test6.html
+// @matches - "Ref</a>&lt;'_&gt;"
+#[doc(inline)]
+pub extern crate bar;
diff --git a/src/test/rustdoc/empty-doc-comment.rs b/src/test/rustdoc/empty-doc-comment.rs
new file mode 100644
index 000000000..b1dae930e
--- /dev/null
+++ b/src/test/rustdoc/empty-doc-comment.rs
@@ -0,0 +1,22 @@
+// Ensure that empty doc comments don't panic.
+
+/*!
+*/
+
+///
+///
+pub struct Foo;
+
+#[doc = "
+"]
+pub mod Mod {
+ //!
+ //!
+}
+
+/**
+*/
+pub mod Another {
+ #![doc = "
+"]
+}
diff --git a/src/test/rustdoc/empty-impl-block.rs b/src/test/rustdoc/empty-impl-block.rs
new file mode 100644
index 000000000..6a2a254f6
--- /dev/null
+++ b/src/test/rustdoc/empty-impl-block.rs
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// @has - '//*[@class="docblock"]' 'Hello empty impl block!'
+// @has - '//*[@class="item-info"]' 'This impl block contains no items.'
+/// Hello empty impl block!
+impl Foo {}
+// We ensure that this empty impl block without doc isn't rendered.
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1
+impl Foo {}
+
+// Just to ensure that empty trait impl blocks are rendered.
+pub struct Another;
+pub trait Bar {}
+
+// @has 'foo/struct.Another.html'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Another'
+impl Bar for Another {}
diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs
new file mode 100644
index 000000000..83902d6f7
--- /dev/null
+++ b/src/test/rustdoc/empty-impls.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send-for-Foo"]' 'impl Send for Foo'
+pub struct Foo;
+
+pub trait EmptyTrait {}
+
+// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait-for-Foo"]' 'impl EmptyTrait for Foo'
+impl EmptyTrait for Foo {}
+
+pub trait NotEmpty {
+ fn foo(&self);
+}
+
+// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty-for-Foo"]' 'impl NotEmpty for Foo'
+impl NotEmpty for Foo {
+ fn foo(&self) {}
+}
diff --git a/src/test/rustdoc/empty-mod-private.rs b/src/test/rustdoc/empty-mod-private.rs
new file mode 100644
index 000000000..c2a98049a
--- /dev/null
+++ b/src/test/rustdoc/empty-mod-private.rs
@@ -0,0 +1,16 @@
+// compile-flags: --document-private-items
+
+// @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
+// @has 'empty_mod_private/sidebar-items.js' 'foo'
+// @matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo'
+mod foo {}
+
+// @has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar'
+// @has 'empty_mod_private/sidebar-items.js' 'bar'
+// @matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar'
+mod bar {
+ // @has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
+ // @has 'empty_mod_private/bar/sidebar-items.js' 'baz'
+ // @matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz'
+ mod baz {}
+}
diff --git a/src/test/rustdoc/empty-mod-public.rs b/src/test/rustdoc/empty-mod-public.rs
new file mode 100644
index 000000000..d097fcf83
--- /dev/null
+++ b/src/test/rustdoc/empty-mod-public.rs
@@ -0,0 +1,14 @@
+// @has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo'
+// @has 'empty_mod_public/sidebar-items.js' 'foo'
+// @matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo'
+pub mod foo {}
+
+// @has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar'
+// @has 'empty_mod_public/sidebar-items.js' 'bar'
+// @matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar'
+pub mod bar {
+ // @has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
+ // @has 'empty_mod_public/bar/sidebar-items.js' 'baz'
+ // @matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz'
+ pub mod baz {}
+}
diff --git a/src/test/rustdoc/empty-section.rs b/src/test/rustdoc/empty-section.rs
new file mode 100644
index 000000000..665aa38b1
--- /dev/null
+++ b/src/test/rustdoc/empty-section.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+#![feature(negative_impls)]
+
+pub struct Foo;
+
+// @has foo/struct.Foo.html
+// @!has - 'Auto Trait Implementations'
+impl !Send for Foo {}
+impl !Sync for Foo {}
+impl !std::marker::Unpin for Foo {}
+impl !std::panic::RefUnwindSafe for Foo {}
+impl !std::panic::UnwindSafe for Foo {}
diff --git a/src/test/rustdoc/ensure-src-link.rs b/src/test/rustdoc/ensure-src-link.rs
new file mode 100644
index 000000000..9f8b0277e
--- /dev/null
+++ b/src/test/rustdoc/ensure-src-link.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// This test ensures that the [src] link is present on traits items.
+
+// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink"]' "source"
+pub use std::iter::Iterator;
diff --git a/src/test/rustdoc/enum-headings.rs b/src/test/rustdoc/enum-headings.rs
new file mode 100644
index 000000000..2e5c34391
--- /dev/null
+++ b/src/test/rustdoc/enum-headings.rs
@@ -0,0 +1,40 @@
+#![crate_name = "foo"]
+// @has foo/enum.Token.html
+/// A token!
+/// # First
+/// Some following text...
+// @has - '//h2[@id="first"]' "First"
+pub enum Token {
+ /// A declaration!
+ /// # Variant-First
+ /// Some following text...
+ // @has - '//h4[@id="variant-first"]' "Variant-First"
+ Declaration {
+ /// A version!
+ /// # Variant-Field-First
+ /// Some following text...
+ // @has - '//h5[@id="variant-field-first"]' "Variant-Field-First"
+ version: String,
+ },
+ /// A Zoople!
+ /// # Variant-First
+ Zoople(
+ // @has - '//h5[@id="variant-tuple-field-first"]' "Variant-Tuple-Field-First"
+ /// Zoople's first variant!
+ /// # Variant-Tuple-Field-First
+ /// Some following text...
+ usize,
+ ),
+ /// Unfinished business!
+ /// # Non-Exhaustive-First
+ /// Some following text...
+ // @has - '//h4[@id="non-exhaustive-first"]' "Non-Exhaustive-First"
+ #[non_exhaustive]
+ Unfinished {
+ /// This is x.
+ /// # X-First
+ /// Some following text...
+ // @has - '//h5[@id="x-first"]' "X-First"
+ x: usize,
+ },
+}
diff --git a/src/test/rustdoc/escape-deref-methods.rs b/src/test/rustdoc/escape-deref-methods.rs
new file mode 100644
index 000000000..a62ad2c40
--- /dev/null
+++ b/src/test/rustdoc/escape-deref-methods.rs
@@ -0,0 +1,35 @@
+#![crate_name = "foo"]
+
+use std::ops::{Deref, DerefMut};
+
+#[derive(Debug, Clone)]
+pub struct Title {
+ name: String,
+}
+
+#[derive(Debug, Clone)]
+pub struct TitleList {
+ pub members: Vec<Title>,
+}
+
+impl TitleList {
+ pub fn new() -> Self {
+ TitleList { members: Vec::new() }
+ }
+}
+
+impl Deref for TitleList {
+ type Target = Vec<Title>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.members
+ }
+}
+
+// @has foo/struct.TitleList.html
+// @has - '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Vec<Title>>'
+impl DerefMut for TitleList {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.members
+ }
+}
diff --git a/src/test/rustdoc/extern-default-method.no_href_on_anchor.html b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html
new file mode 100644
index 000000000..dab0a6495
--- /dev/null
+++ b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html
@@ -0,0 +1 @@
+<a class="fnname">provided</a>(&amp;self) \ No newline at end of file
diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs
new file mode 100644
index 000000000..8139f5b26
--- /dev/null
+++ b/src/test/rustdoc/extern-default-method.rs
@@ -0,0 +1,23 @@
+// aux-build:rustdoc-extern-default-method.rs
+// ignore-cross-compile
+// ignore-tidy-linelength
+
+extern crate rustdoc_extern_default_method as ext;
+
+// For this test, the dependency is compiled but not documented.
+//
+// Still, the struct from the external crate and its impl should be documented since
+// the struct is re-exported from this crate.
+// However, the method in the trait impl should *not* have a link (an `href` attribute) to
+// its corresponding item in the trait declaration since it would otherwise be broken.
+//
+// In older versions of rustdoc, the impl item (`a[@class="fnname"]`) used to link to
+// `#method.provided` – i.e. "to itself". Put in quotes since that was actually incorrect in
+// general: If the type `Struct` also had an inherent method called `provided`, the impl item
+// would link to that one even though those two methods are distinct items!
+
+// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
+// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]' 1
+// @snapshot no_href_on_anchor - '//*[@id="method.provided"]//a[@class="fnname"]'
+// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
+pub use ext::Struct;
diff --git a/src/test/rustdoc/extern-html-root-url-precedence.rs b/src/test/rustdoc/extern-html-root-url-precedence.rs
new file mode 100644
index 000000000..def6767ea
--- /dev/null
+++ b/src/test/rustdoc/extern-html-root-url-precedence.rs
@@ -0,0 +1,7 @@
+// compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0 --extern-html-root-takes-precedence
+
+// @has extern_html_root_url_precedence/index.html
+// --extern-html-root should take precedence if `--takes-precedence` is passed
+// @has - '//a/@href' 'https://example.com/core/0.1.0/core/iter/index.html'
+#[doc(no_inline)]
+pub use std::iter;
diff --git a/src/test/rustdoc/extern-html-root-url.rs b/src/test/rustdoc/extern-html-root-url.rs
new file mode 100644
index 000000000..17eedcf2a
--- /dev/null
+++ b/src/test/rustdoc/extern-html-root-url.rs
@@ -0,0 +1,18 @@
+// compile-flags:-Z unstable-options --extern-html-root-url html_root=https://example.com/override --extern-html-root-url no_html_root=https://example.com/override
+// aux-build:html_root.rs
+// aux-build:no_html_root.rs
+// NOTE: intentionally does not build any auxiliary docs
+
+extern crate html_root;
+extern crate no_html_root;
+
+// @has extern_html_root_url/index.html
+// `html_root_url` should override `--extern-html-root-url`
+// @has - '//a/@href' 'https://example.com/html_root/html_root/fn.foo.html'
+#[doc(no_inline)]
+pub use html_root::foo;
+
+#[doc(no_inline)]
+// `--extern-html-root-url` should apply if no `html_root_url` is given
+// @has - '//a/@href' 'https://example.com/override/no_html_root/fn.bar.html'
+pub use no_html_root::bar;
diff --git a/src/test/rustdoc/extern-impl-trait.rs b/src/test/rustdoc/extern-impl-trait.rs
new file mode 100644
index 000000000..8ab026afd
--- /dev/null
+++ b/src/test/rustdoc/extern-impl-trait.rs
@@ -0,0 +1,11 @@
+// aux-build:extern-impl-trait.rs
+
+#![crate_name = "foo"]
+
+extern crate extern_impl_trait;
+
+// @has 'foo/struct.X.html' '//h4[@class="code-header"]' "impl Foo<Associated = ()> + 'a"
+pub use extern_impl_trait::X;
+
+// @has 'foo/struct.Y.html' '//h4[@class="code-header"]' "impl ?Sized + Foo<Associated = ()> + 'a"
+pub use extern_impl_trait::Y;
diff --git a/src/test/rustdoc/extern-impl.rs b/src/test/rustdoc/extern-impl.rs
new file mode 100644
index 000000000..f357d65df
--- /dev/null
+++ b/src/test/rustdoc/extern-impl.rs
@@ -0,0 +1,27 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+pub struct Foo;
+
+impl Foo {
+ // @has - '//h4[@class="code-header"]' 'fn rust0()'
+ pub fn rust0() {}
+ // @has - '//h4[@class="code-header"]' 'fn rust1()'
+ pub extern "Rust" fn rust1() {}
+ // @has - '//h4[@class="code-header"]' 'extern "C" fn c0()'
+ pub extern fn c0() {}
+ // @has - '//h4[@class="code-header"]' 'extern "C" fn c1()'
+ pub extern "C" fn c1() {}
+ // @has - '//h4[@class="code-header"]' 'extern "system" fn system0()'
+ pub extern "system" fn system0() {}
+}
+
+// @has foo/trait.Bar.html
+pub trait Bar {}
+
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for fn()'
+impl Bar for fn() {}
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "C" fn()'
+impl Bar for extern fn() {}
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "system" fn()'
+impl Bar for extern "system" fn() {}
diff --git a/src/test/rustdoc/extern-links.rs b/src/test/rustdoc/extern-links.rs
new file mode 100644
index 000000000..0383ccf7d
--- /dev/null
+++ b/src/test/rustdoc/extern-links.rs
@@ -0,0 +1,21 @@
+// aux-build:extern-links.rs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+pub extern crate extern_links;
+
+// @!has foo/index.html '//a' 'extern_links'
+#[doc(no_inline)]
+pub use extern_links as extern_links2;
+
+// @!has foo/index.html '//a' 'Foo'
+#[doc(no_inline)]
+pub use extern_links::Foo;
+
+#[doc(hidden)]
+pub mod hidden {
+ // @!has foo/hidden/extern_links/index.html
+ // @!has foo/hidden/extern_links/struct.Foo.html
+ pub use extern_links;
+}
diff --git a/src/test/rustdoc/extern-method.rs b/src/test/rustdoc/extern-method.rs
new file mode 100644
index 000000000..9cf5fc190
--- /dev/null
+++ b/src/test/rustdoc/extern-method.rs
@@ -0,0 +1,19 @@
+// aux-build:rustdoc-extern-method.rs
+// ignore-cross-compile
+
+#![feature(unboxed_closures)]
+
+extern crate rustdoc_extern_method as foo;
+
+// @has extern_method/trait.Foo.html //pre "pub trait Foo"
+// @has - '//*[@id="tymethod.foo"]//h4[@class="code-header"]' 'extern "rust-call" fn foo'
+// @has - '//*[@id="method.foo_"]//h4[@class="code-header"]' 'extern "rust-call" fn foo_'
+pub use foo::Foo;
+
+// @has extern_method/trait.Bar.html //pre "pub trait Bar"
+pub trait Bar {
+ // @has - '//*[@id="tymethod.bar"]//h4[@class="code-header"]' 'extern "rust-call" fn bar'
+ extern "rust-call" fn bar(&self, _: ());
+ // @has - '//*[@id="method.bar_"]//h4[@class="code-header"]' 'extern "rust-call" fn bar_'
+ extern "rust-call" fn bar_(&self, _: ()) { }
+}
diff --git a/src/test/rustdoc/external-cross.rs b/src/test/rustdoc/external-cross.rs
new file mode 100644
index 000000000..3f8e16882
--- /dev/null
+++ b/src/test/rustdoc/external-cross.rs
@@ -0,0 +1,10 @@
+// aux-build:external-cross.rs
+// ignore-cross-compile
+
+#![crate_name="host"]
+
+extern crate external_cross;
+
+// @has host/struct.NeedMoreDocs.html
+// @has - '//h2' 'Cross-crate imported docs'
+pub use external_cross::NeedMoreDocs;
diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs
new file mode 100644
index 000000000..bd322d67a
--- /dev/null
+++ b/src/test/rustdoc/external-doc.rs
@@ -0,0 +1,14 @@
+// @has external_doc/struct.IncludeStrDocs.html
+// @has - '//h2' 'External Docs'
+// @has - '//h3' 'Inline Docs'
+#[doc = include_str!("auxiliary/external-doc.md")]
+/// ## Inline Docs
+pub struct IncludeStrDocs;
+
+macro_rules! dir { () => { "auxiliary" } }
+
+// @has external_doc/struct.EagerExpansion.html
+// @has - '//h2' 'External Docs'
+#[doc = include_str!(concat!(dir!(), "/external-doc.md"))]
+/// ## Inline Docs
+pub struct EagerExpansion;
diff --git a/src/test/rustdoc/external-macro-src.rs b/src/test/rustdoc/external-macro-src.rs
new file mode 100644
index 000000000..359551ab7
--- /dev/null
+++ b/src/test/rustdoc/external-macro-src.rs
@@ -0,0 +1,12 @@
+// aux-build:external-macro-src.rs
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate external_macro_src;
+
+// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source'
+
+// @has foo/struct.Foo.html
+// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source'
+make_foo!();
diff --git a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs
new file mode 100644
index 000000000..da76381e4
--- /dev/null
+++ b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs
@@ -0,0 +1,8 @@
+#![feature(doc_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0
+#[cfg(not(test))]
+pub fn foo() {}
diff --git a/src/test/rustdoc/ffi.rs b/src/test/rustdoc/ffi.rs
new file mode 100644
index 000000000..8140dfc72
--- /dev/null
+++ b/src/test/rustdoc/ffi.rs
@@ -0,0 +1,12 @@
+// aux-build:rustdoc-ffi.rs
+// ignore-cross-compile
+
+extern crate rustdoc_ffi as lib;
+
+// @has ffi/fn.foreigner.html //pre 'pub unsafe extern "C" fn foreigner(cold_as_ice: u32)'
+pub use lib::foreigner;
+
+extern "C" {
+ // @has ffi/fn.another.html //pre 'pub unsafe extern "C" fn another(cold_as_ice: u32)'
+ pub fn another(cold_as_ice: u32);
+}
diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs
new file mode 100644
index 000000000..4c4ffddc8
--- /dev/null
+++ b/src/test/rustdoc/fn-bound.rs
@@ -0,0 +1,21 @@
+// Regression test for #100143
+
+use std::iter::Peekable;
+
+pub struct Span<F: Fn(&i32)> {
+ inner: Peekable<ConditionalIterator<F>>,
+}
+
+pub struct ConditionalIterator<F> {
+ f: F,
+}
+
+
+// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
+impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
+ type Item = ();
+
+ fn next(&mut self) -> Option<Self::Item> {
+ todo!()
+ }
+}
diff --git a/src/test/rustdoc/fn-pointer-arg-name.rs b/src/test/rustdoc/fn-pointer-arg-name.rs
new file mode 100644
index 000000000..4293d849d
--- /dev/null
+++ b/src/test/rustdoc/fn-pointer-arg-name.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+pub fn f(callback: fn(len: usize, foo: u32)) {}
diff --git a/src/test/rustdoc/fn-sidebar.rs b/src/test/rustdoc/fn-sidebar.rs
new file mode 100644
index 000000000..2fe8ebec1
--- /dev/null
+++ b/src/test/rustdoc/fn-sidebar.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="sidebar-elems"]' ''
+pub fn bar() {}
+
+// @has foo/constant.BAR.html
+// @has - '//*[@class="sidebar-elems"]' ''
+pub const BAR: u32 = 0;
diff --git a/src/test/rustdoc/fn-type.rs b/src/test/rustdoc/fn-type.rs
new file mode 100644
index 000000000..3959aeb6c
--- /dev/null
+++ b/src/test/rustdoc/fn-type.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+#![crate_type = "lib"]
+
+pub struct Foo<'a, T> {
+ pub generic: fn(val: &T) -> T,
+
+ pub lifetime: fn(val: &'a i32) -> i32,
+ pub hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32),
+}
+
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.generic"]' "generic: fn(val: &T) -> T"
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.lifetime"]' "lifetime: fn(val: &'a i32) -> i32"
+// @has 'foo/struct.Foo.html' '//span[@id="structfield.hrtb_lifetime"]' "hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32)"
diff --git a/src/test/rustdoc/force-target-feature.rs b/src/test/rustdoc/force-target-feature.rs
new file mode 100644
index 000000000..b6c10e834
--- /dev/null
+++ b/src/test/rustdoc/force-target-feature.rs
@@ -0,0 +1,11 @@
+// only-x86_64
+// compile-flags:--test -C target-feature=+avx
+// should-fail
+
+/// (written on a spider's web) Some Struct
+///
+/// ```
+/// panic!("oh no");
+/// ```
+#[doc(cfg(target_feature = "avx"))]
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/foreigntype-reexport.rs b/src/test/rustdoc/foreigntype-reexport.rs
new file mode 100644
index 000000000..1dec0ef3e
--- /dev/null
+++ b/src/test/rustdoc/foreigntype-reexport.rs
@@ -0,0 +1,56 @@
+#![feature(extern_types)]
+
+mod sub {
+ extern "C" {
+ /// Another extern type.
+ pub type C2;
+ pub fn f2();
+ pub static K: usize;
+ }
+}
+
+pub mod sub2 {
+ extern "C" {
+ // @has foreigntype_reexport/sub2/foreigntype.C.html
+ pub type C;
+ // @has foreigntype_reexport/sub2/fn.f.html
+ pub fn f();
+ // @has foreigntype_reexport/sub2/static.K3.html
+ pub static K3: usize;
+ }
+}
+
+mod sub3 {
+ extern "C" {
+ pub type C4;
+ pub fn f4();
+ pub static K4: usize;
+ type X4;
+ }
+}
+
+// @has foreigntype_reexport/foreigntype.C2.html
+// @has foreigntype_reexport/fn.f2.html
+// @has foreigntype_reexport/static.K2.html
+// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C2'
+// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f2'
+// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K2'
+pub use self::sub::{f2, C2, K as K2};
+
+// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C'
+// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f'
+// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K3'
+// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::C as C3;'
+// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::f as f3;'
+// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::K3;'
+pub use self::sub2::{f as f3, C as C3, K3};
+
+// @has foreigntype_reexport/foreigntype.C4.html
+// @has foreigntype_reexport/fn.f4.html
+// @has foreigntype_reexport/static.K4.html
+// @!has foreigntype_reexport/foreigntype.X4.html
+// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C4'
+// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f4'
+// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K4'
+// @!has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'X4'
+pub use self::sub3::*;
diff --git a/src/test/rustdoc/foreigntype.rs b/src/test/rustdoc/foreigntype.rs
new file mode 100644
index 000000000..891cdd5fe
--- /dev/null
+++ b/src/test/rustdoc/foreigntype.rs
@@ -0,0 +1,18 @@
+#![feature(extern_types)]
+
+extern "C" {
+ // @has foreigntype/foreigntype.ExtType.html
+ pub type ExtType;
+}
+
+impl ExtType {
+ // @has - '//a[@class="fnname"]' 'do_something'
+ pub fn do_something(&self) {}
+}
+
+pub trait Trait {}
+
+// @has foreigntype/trait.Trait.html '//a[@class="foreigntype"]' 'ExtType'
+impl Trait for ExtType {}
+
+// @has foreigntype/index.html '//a[@class="foreigntype"]' 'ExtType'
diff --git a/src/test/rustdoc/generic-associated-types/gats.rs b/src/test/rustdoc/generic-associated-types/gats.rs
new file mode 100644
index 000000000..ae981b949
--- /dev/null
+++ b/src/test/rustdoc/generic-associated-types/gats.rs
@@ -0,0 +1,34 @@
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+// @has foo/trait.LendingIterator.html
+pub trait LendingIterator {
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
+ type Item<'a> where Self: 'a;
+
+ // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
+ // "fn next<'a>(&'a self) -> Self::Item<'a>"
+ // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]//a[@href="trait.LendingIterator.html#associatedtype.Item"]' \
+ // "Item"
+ fn next<'a>(&'a self) -> Self::Item<'a>;
+}
+
+// @has foo/trait.LendingIterator.html
+// @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item<'a> = ()"
+impl LendingIterator for () {
+ type Item<'a> = ();
+
+ fn next<'a>(&self) -> () {}
+}
+
+pub struct Infinite<T>(T);
+
+// @has foo/trait.LendingIterator.html
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
+impl<T> LendingIterator for Infinite<T> {
+ type Item<'a> where Self: 'a = &'a T;
+
+ fn next<'a>(&'a self) -> Self::Item<'a> {
+ &self.0
+ }
+}
diff --git a/src/test/rustdoc/generic-associated-types/issue-94683.rs b/src/test/rustdoc/generic-associated-types/issue-94683.rs
new file mode 100644
index 000000000..38ecf5283
--- /dev/null
+++ b/src/test/rustdoc/generic-associated-types/issue-94683.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+pub trait Trait {
+ type Gat<'a>;
+}
+
+// Make sure that the elided lifetime shows up
+
+// @has foo/type.T.html
+// @has - "pub type T = "
+// @has - "&lt;'_&gt;"
+pub type T = fn(&<() as Trait>::Gat<'_>);
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
new file mode 100644
index 000000000..c6beed70a
--- /dev/null
+++ b/src/test/rustdoc/generic-impl.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+use std::fmt;
+
+// @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' ''
+pub struct Bar;
+
+// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+pub struct Foo;
+// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString'
+
+impl fmt::Display for Foo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Foo")
+ }
+}
diff --git a/src/test/rustdoc/generic_const_exprs.rs b/src/test/rustdoc/generic_const_exprs.rs
new file mode 100644
index 000000000..6ff591639
--- /dev/null
+++ b/src/test/rustdoc/generic_const_exprs.rs
@@ -0,0 +1,24 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/92859>.
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+#![crate_name = "foo"]
+
+// @has 'foo/trait.Foo.html'
+
+pub trait Foo: Sized {
+ const WIDTH: usize;
+
+ fn arrayify(self) -> [Self; Self::WIDTH];
+}
+
+impl<T: Sized> Foo for T {
+ const WIDTH: usize = 1;
+
+ // @has - '//*[@id="tymethod.arrayify"]/*[@class="code-header"]' \
+ // 'fn arrayify(self) -> [Self; Self::WIDTH]'
+ fn arrayify(self) -> [Self; Self::WIDTH] {
+ [self]
+ }
+}
diff --git a/src/test/rustdoc/hidden-impls.rs b/src/test/rustdoc/hidden-impls.rs
new file mode 100644
index 000000000..8f33a6604
--- /dev/null
+++ b/src/test/rustdoc/hidden-impls.rs
@@ -0,0 +1,17 @@
+#![crate_name = "foo"]
+
+mod hidden {
+ #[derive(Clone)]
+ pub struct Foo;
+}
+
+#[doc(hidden)]
+pub mod __hidden {
+ pub use hidden::Foo;
+}
+
+// @has foo/trait.Clone.html
+// @!has - 'Foo'
+// @has implementors/core/clone/trait.Clone.js
+// @!has - 'Foo'
+pub use std::clone::Clone;
diff --git a/src/test/rustdoc/hidden-line.rs b/src/test/rustdoc/hidden-line.rs
new file mode 100644
index 000000000..f2f6173d2
--- /dev/null
+++ b/src/test/rustdoc/hidden-line.rs
@@ -0,0 +1,19 @@
+/// The '# ' lines should be removed from the output, but the #[derive] should be
+/// retained.
+///
+/// ```rust
+/// # #[derive(PartialEq)] // invisible
+/// # struct Foo; // invisible
+///
+/// #[derive(PartialEq)] // Bar
+/// struct Bar(Foo);
+///
+/// fn test() {
+/// let x = Bar(Foo);
+/// assert_eq!(x, x); // check that the derivings worked
+/// }
+/// ```
+pub fn foo() {}
+
+// @!has hidden_line/fn.foo.html invisible
+// @matches - //pre "#\[derive\(PartialEq\)\] // Bar"
diff --git a/src/test/rustdoc/hidden-methods.rs b/src/test/rustdoc/hidden-methods.rs
new file mode 100644
index 000000000..27181d489
--- /dev/null
+++ b/src/test/rustdoc/hidden-methods.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+#[doc(hidden)]
+pub mod hidden {
+ pub struct Foo;
+
+ impl Foo {
+ #[doc(hidden)]
+ pub fn this_should_be_hidden() {}
+ }
+
+ pub struct Bar;
+
+ impl Bar {
+ fn this_should_be_hidden() {}
+ }
+}
+
+// @has foo/struct.Foo.html
+// @!has - 'Methods'
+// @!has - '//code' 'impl Foo'
+// @!has - 'this_should_be_hidden'
+pub use hidden::Foo;
+
+// @has foo/struct.Bar.html
+// @!has - 'Methods'
+// @!has - '//code' 'impl Bar'
+// @!has - 'this_should_be_hidden'
+pub use hidden::Bar;
diff --git a/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs
new file mode 100644
index 000000000..95b3e9b65
--- /dev/null
+++ b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs
@@ -0,0 +1,31 @@
+// compile-flags: -Z unstable-options --document-hidden-items
+
+// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+ #[doc(hidden)]
+ type Foo;
+ type Bar;
+ #[doc(hidden)]
+ fn f();
+ fn g();
+}
+
+// @has foo/struct.S.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+ type Foo = ();
+ type Bar = ();
+ fn f() {}
+ fn g() {}
+}
diff --git a/src/test/rustdoc/hidden-trait-methods.rs b/src/test/rustdoc/hidden-trait-methods.rs
new file mode 100644
index 000000000..e924ba7d0
--- /dev/null
+++ b/src/test/rustdoc/hidden-trait-methods.rs
@@ -0,0 +1,29 @@
+// test for trait methods with `doc(hidden)`.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+ #[doc(hidden)]
+ type Foo;
+ type Bar;
+ #[doc(hidden)]
+ fn f();
+ fn g();
+}
+
+// @has foo/struct.S.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+ type Foo = ();
+ type Bar = ();
+ fn f() {}
+ fn g() {}
+}
diff --git a/src/test/rustdoc/hidden-trait-struct-impls.rs b/src/test/rustdoc/hidden-trait-struct-impls.rs
new file mode 100644
index 000000000..cc3f63377
--- /dev/null
+++ b/src/test/rustdoc/hidden-trait-struct-impls.rs
@@ -0,0 +1,22 @@
+#![crate_name = "foo"]
+
+#[doc(hidden)]
+pub trait Foo {}
+
+trait Dark {}
+
+pub trait Bam {}
+
+pub struct Bar;
+
+struct Hidden;
+
+// @!has foo/struct.Bar.html '//*[@id="impl-Foo-for-Bar"]' 'impl Foo for Bar'
+impl Foo for Bar {}
+// @!has foo/struct.Bar.html '//*[@id="impl-Dark-for-Bar"]' 'impl Dark for Bar'
+impl Dark for Bar {}
+// @has foo/struct.Bar.html '//*[@id="impl-Bam-for-Bar"]' 'impl Bam for Bar'
+// @has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Bar'
+impl Bam for Bar {}
+// @!has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Hidden'
+impl Bam for Hidden {}
diff --git a/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs
new file mode 100644
index 000000000..644a6e1cf
--- /dev/null
+++ b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs
@@ -0,0 +1,82 @@
+// Test that certain unevaluated constant expression arguments that are
+// deemed too verbose or complex and that may leak private or
+// `doc(hidden)` struct fields are not displayed in the documentation.
+//
+// Read the documentation of `rustdoc::clean::utils::print_const_expr`
+// for further details.
+#![feature(const_trait_impl, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+// @has hide_complex_unevaluated_const_arguments/trait.Stage.html
+pub trait Stage {
+ // A helper constant that prevents const expressions containing it
+ // from getting fully evaluated since it doesn't have a body and
+ // thus is non-reducible. This allows us to specifically test the
+ // pretty-printing of *unevaluated* consts.
+ const ABSTRACT: usize;
+
+ // Currently considered "overly complex" by the `generic_const_exprs`
+ // feature. If / once this expression kind gets supported, this
+ // unevaluated const expression could leak the private struct field.
+ //
+ // FIXME: Once the line below compiles, make this a test that
+ // ensures that the private field is not printed.
+ //
+ //const ARRAY0: [u8; Struct { private: () } + Self::ABSTRACT];
+
+ // This assoc. const could leak the private assoc. function `Struct::new`.
+ // Ensure that this does not happen.
+ //
+ // @has - '//*[@id="associatedconstant.ARRAY1"]' \
+ // 'const ARRAY1: [u8; { _ }]'
+ const ARRAY1: [u8; Struct::new(/* ... */) + Self::ABSTRACT * 1_000];
+
+ // @has - '//*[@id="associatedconstant.VERBOSE"]' \
+ // 'const VERBOSE: [u16; { _ }]'
+ const VERBOSE: [u16; compute("thing", 9 + 9) * Self::ABSTRACT];
+
+ // Check that we do not leak the private struct field contained within
+ // the path. The output could definitely be improved upon
+ // (e.g. printing sth. akin to `<Self as Helper<{ _ }>>::OUT`) but
+ // right now “safe is safe”.
+ //
+ // @has - '//*[@id="associatedconstant.PATH"]' \
+ // 'const PATH: usize = _'
+ const PATH: usize = <Self as Helper<{ Struct { private: () } }>>::OUT;
+}
+
+const fn compute(input: &str, extra: usize) -> usize {
+ input.len() + extra
+}
+
+pub trait Helper<const S: Struct> {
+ const OUT: usize;
+}
+
+impl<const S: Struct, St: Stage + ?Sized> Helper<S> for St {
+ const OUT: usize = St::ABSTRACT;
+}
+
+// Currently in rustdoc, const arguments are not evaluated in this position
+// and therefore they fall under the realm of `print_const_expr`.
+// If rustdoc gets patched to evaluate const arguments, it is fine to replace
+// this test as long as one can ensure that private fields are not leaked!
+//
+// @has hide_complex_unevaluated_const_arguments/trait.Sub.html \
+// '//*[@class="rust trait"]' \
+// 'pub trait Sub: Sup<{ _ }, { _ }> { }'
+pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {}
+
+pub trait Sup<const N: usize, const S: Struct> {}
+
+pub struct Struct { private: () }
+
+impl Struct {
+ const fn new() -> Self { Self { private: () } }
+}
+
+impl const std::ops::Add<usize> for Struct {
+ type Output = usize;
+
+ fn add(self, _: usize) -> usize { 0 }
+}
diff --git a/src/test/rustdoc/hide-complex-unevaluated-consts.rs b/src/test/rustdoc/hide-complex-unevaluated-consts.rs
new file mode 100644
index 000000000..ba623246a
--- /dev/null
+++ b/src/test/rustdoc/hide-complex-unevaluated-consts.rs
@@ -0,0 +1,71 @@
+// Regression test for issue #97933.
+//
+// Test that certain unevaluated constant expressions that are
+// deemed too verbose or complex and that may leak private or
+// `doc(hidden)` struct fields are not displayed in the documentation.
+//
+// Read the documentation of `rustdoc::clean::utils::print_const_expr`
+// for further details.
+
+// @has hide_complex_unevaluated_consts/trait.Container.html
+pub trait Container {
+ // A helper constant that prevents const expressions containing it
+ // from getting fully evaluated since it doesn't have a body and
+ // thus is non-reducible. This allows us to specifically test the
+ // pretty-printing of *unevaluated* consts.
+ const ABSTRACT: i32;
+
+ // Ensure that the private field does not get leaked:
+ //
+ // @has - '//*[@id="associatedconstant.STRUCT0"]' \
+ // 'const STRUCT0: Struct = _'
+ const STRUCT0: Struct = Struct { private: () };
+
+ // @has - '//*[@id="associatedconstant.STRUCT1"]' \
+ // 'const STRUCT1: (Struct,) = _'
+ const STRUCT1: (Struct,) = (Struct{private: /**/()},);
+
+ // Although the struct field is public here, check that it is not
+ // displayed. In a future version of rustdoc, we definitely want to
+ // show it. However for the time being, the printing logic is a bit
+ // conservative.
+ //
+ // @has - '//*[@id="associatedconstant.STRUCT2"]' \
+ // 'const STRUCT2: Record = _'
+ const STRUCT2: Record = Record { public: 5 };
+
+ // Test that we do not show the incredibly verbose match expr:
+ //
+ // @has - '//*[@id="associatedconstant.MATCH0"]' \
+ // 'const MATCH0: i32 = _'
+ const MATCH0: i32 = match 234 {
+ 0 => 1,
+ _ => Self::ABSTRACT,
+ };
+
+ // @has - '//*[@id="associatedconstant.MATCH1"]' \
+ // 'const MATCH1: bool = _'
+ const MATCH1: bool = match Self::ABSTRACT {
+ _ => true,
+ };
+
+ // Check that we hide complex (arithmetic) operations.
+ // In this case, it is a bit unfortunate since the expression
+ // is not *that* verbose and it might be quite useful to the reader.
+ //
+ // However in general, the expression might be quite large and
+ // contain match expressions and structs with private fields.
+ // We would need to recurse over the whole expression and even more
+ // importantly respect operator precedence when pretty-printing
+ // the potentially partially censored expression.
+ // For now, the implementation is quite simple and the choices
+ // rather conservative.
+ //
+ // @has - '//*[@id="associatedconstant.ARITH_OPS"]' \
+ // 'const ARITH_OPS: i32 = _'
+ const ARITH_OPS: i32 = Self::ABSTRACT * 2 + 1;
+}
+
+pub struct Struct { private: () }
+
+pub struct Record { pub public: i32 }
diff --git a/src/test/rustdoc/hide-unstable-trait.rs b/src/test/rustdoc/hide-unstable-trait.rs
new file mode 100644
index 000000000..c30d6ed7b
--- /dev/null
+++ b/src/test/rustdoc/hide-unstable-trait.rs
@@ -0,0 +1,11 @@
+// aux-build:unstable-trait.rs
+
+#![crate_name = "foo"]
+#![feature(private_trait)]
+
+extern crate unstable_trait;
+
+// @has foo/struct.Foo.html 'bar'
+// @has foo/struct.Foo.html 'bar2'
+#[doc(inline)]
+pub use unstable_trait::Foo;
diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs
new file mode 100644
index 000000000..b75b8de52
--- /dev/null
+++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs
@@ -0,0 +1,61 @@
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+pub trait Trait<'x> {}
+
+// @has foo/fn.test1.html
+// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
+pub fn test1<T>()
+where
+ for<'a> &'a T: Iterator,
+{
+}
+
+// @has foo/fn.test2.html
+// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>,"
+pub fn test2<T>()
+where
+ for<'a, 'b> &'a T: Trait<'b>,
+{
+}
+
+// @has foo/fn.test3.html
+// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
+pub fn test3<F>()
+where
+ F: for<'a, 'b> Fn(&'a u8, &'b u8),
+{
+}
+
+// @has foo/struct.Foo.html
+pub struct Foo<'a> {
+ _x: &'a u8,
+ pub some_trait: &'a dyn for<'b> Trait<'b>,
+ pub some_func: for<'c> fn(val: &'c i32) -> i32,
+}
+
+// @has - '//span[@id="structfield.some_func"]' "some_func: for<'c> fn(val: &'c i32) -> i32"
+// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
+
+impl<'a> Foo<'a> {
+ // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>,"
+ pub fn bar<T>()
+ where
+ T: Trait<'a>,
+ {
+ }
+}
+
+// @has foo/trait.B.html
+pub trait B<'x> {}
+
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
+impl<'a> B<'a> for dyn for<'b> Trait<'b> {}
+
+// @has foo/struct.Bar.html
+// @has - '//span[@id="structfield.bar"]' "bar: &'a (dyn for<'b> Trait<'b> + Unpin)"
+// @has - '//span[@id="structfield.baz"]' "baz: &'a (dyn Unpin + for<'b> Trait<'b>)"
+pub struct Bar<'a> {
+ pub bar: &'a (dyn for<'b> Trait<'b> + Unpin),
+ pub baz: &'a (dyn Unpin + for<'b> Trait<'b>),
+}
diff --git a/src/test/rustdoc/impl-box.rs b/src/test/rustdoc/impl-box.rs
new file mode 100644
index 000000000..592b6c985
--- /dev/null
+++ b/src/test/rustdoc/impl-box.rs
@@ -0,0 +1,16 @@
+// https://github.com/rust-lang/rust/issues/92940
+//
+// Show traits implemented on fundamental types that wrap local ones.
+
+pub struct MyType;
+
+// @has 'impl_box/struct.MyType.html'
+// @has '-' '//*[@id="impl-Iterator-for-Box%3CMyType%3E"]' 'impl Iterator for Box<MyType>'
+
+impl Iterator for Box<MyType> {
+ type Item = ();
+
+ fn next(&mut self) -> Option<Self::Item> {
+ todo!()
+ }
+}
diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs
new file mode 100644
index 000000000..d1d39ccff
--- /dev/null
+++ b/src/test/rustdoc/impl-disambiguation.rs
@@ -0,0 +1,30 @@
+#![crate_name = "foo"]
+
+pub trait Foo {}
+
+pub struct Bar<T> { field: T }
+
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl Foo for Bar<u8>"
+impl Foo for Bar<u8> {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl Foo for Bar<u16>"
+impl Foo for Bar<u16> {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl<'a> Foo for &'a Bar<u8>"
+impl<'a> Foo for &'a Bar<u8> {}
+
+pub mod mod1 {
+ pub struct Baz {}
+}
+
+pub mod mod2 {
+ pub enum Baz {}
+}
+
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl Foo for foo::mod1::Baz"
+impl Foo for mod1::Baz {}
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl<'a> Foo for &'a foo::mod2::Baz"
+impl<'a> Foo for &'a mod2::Baz {}
diff --git a/src/test/rustdoc/impl-everywhere.rs b/src/test/rustdoc/impl-everywhere.rs
new file mode 100644
index 000000000..44885d430
--- /dev/null
+++ b/src/test/rustdoc/impl-everywhere.rs
@@ -0,0 +1,30 @@
+#![crate_name = "foo"]
+
+pub trait Foo {}
+pub trait Foo2 {}
+
+pub struct Bar;
+
+impl Foo for Bar {}
+impl Foo2 for Bar {}
+
+// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo"
+// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "-> &'x impl Foo"
+pub fn foo<'x>(x: &'x impl Foo) -> &'x impl Foo {
+ x
+}
+
+// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' "x: &'x impl Foo"
+// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' '-> impl Foo2'
+pub fn foo2<'x>(_x: &'x impl Foo) -> impl Foo2 {
+ Bar
+}
+
+// @has foo/fn.foo_foo.html '//section[@id="main-content"]//pre' '-> impl Foo + Foo2'
+pub fn foo_foo() -> impl Foo + Foo2 {
+ Bar
+}
+
+// @has foo/fn.foo_foo_foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo + Foo2"
+pub fn foo_foo_foo<'x>(_x: &'x (impl Foo + Foo2)) {
+}
diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs
new file mode 100644
index 000000000..6c5e79d5a
--- /dev/null
+++ b/src/test/rustdoc/impl-parts-crosscrate.rs
@@ -0,0 +1,20 @@
+// aux-build:rustdoc-impl-parts-crosscrate.rs
+// ignore-cross-compile
+
+#![feature(negative_impls)]
+
+extern crate rustdoc_impl_parts_crosscrate;
+
+pub struct Bar<T> { t: T }
+
+// The output file is html embedded in javascript, so the html tags
+// aren't stripped by the processing script and we can't check for the
+// full impl string. Instead, just make sure something from each part
+// is mentioned.
+
+// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnAutoTrait.js Bar
+// @has - Send
+// @has - !AnAutoTrait
+// @has - Copy
+impl<T: Send> !rustdoc_impl_parts_crosscrate::AnAutoTrait for Bar<T>
+ where T: Copy {}
diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs
new file mode 100644
index 000000000..249158c1a
--- /dev/null
+++ b/src/test/rustdoc/impl-parts.rs
@@ -0,0 +1,12 @@
+#![feature(negative_impls)]
+#![feature(auto_traits)]
+
+pub auto trait AnAutoTrait {}
+
+pub struct Foo<T> { field: T }
+
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs
new file mode 100644
index 000000000..54c3f856d
--- /dev/null
+++ b/src/test/rustdoc/impl-trait-alias.rs
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+
+trait MyTrait {}
+impl MyTrait for i32 {}
+
+// @has impl_trait_alias/type.Foo.html 'Foo'
+/// debug type
+pub type Foo = impl MyTrait;
+
+// @has impl_trait_alias/fn.foo.html 'foo'
+/// debug function
+pub fn foo() -> Foo {
+ 1
+}
diff --git a/src/test/rustdoc/implementor-stable-version.rs b/src/test/rustdoc/implementor-stable-version.rs
new file mode 100644
index 000000000..a1f3fd5a8
--- /dev/null
+++ b/src/test/rustdoc/implementor-stable-version.rs
@@ -0,0 +1,21 @@
+#![stable(feature = "bar", since = "OLD 1.0")]
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#[stable(feature = "bar", since = "OLD 1.0")]
+pub trait Bar {}
+
+#[stable(feature = "baz", since = "OLD 1.0")]
+pub trait Baz {}
+
+#[stable(feature = "baz", since = "OLD 1.0")]
+pub struct Foo;
+
+// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
+#[stable(feature = "foobar", since = "NEW 2.0")]
+impl Bar for Foo {}
+
+// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
+#[stable(feature = "foobaz", since = "OLD 1.0")]
+impl Baz for Foo {}
diff --git a/src/test/rustdoc/include_str_cut.rs b/src/test/rustdoc/include_str_cut.rs
new file mode 100644
index 000000000..cbc1ba8db
--- /dev/null
+++ b/src/test/rustdoc/include_str_cut.rs
@@ -0,0 +1,7 @@
+#![crate_name = "foo"]
+#![no_std]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="docblock"]' 'inc2 x'
+#[doc = include_str!("short-line.md")]
+pub fn foo() {}
diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs
new file mode 100644
index 000000000..be668a127
--- /dev/null
+++ b/src/test/rustdoc/index-page.rs
@@ -0,0 +1,11 @@
+// aux-build:all-item-types.rs
+// build-aux-docs
+// compile-flags: -Z unstable-options --enable-index-page
+
+#![crate_name = "foo"]
+
+// @has foo/../index.html
+// @has - '//span[@class="in-band"]' 'List of all crates'
+// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo'
+// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types'
+pub struct Foo;
diff --git a/src/test/rustdoc/infinite-redirection.rs b/src/test/rustdoc/infinite-redirection.rs
new file mode 100644
index 000000000..96a43323c
--- /dev/null
+++ b/src/test/rustdoc/infinite-redirection.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+// This test ensures that there is no "infinite redirection" file generated (a
+// file which redirects to itself).
+
+// We check it's not a redirection file.
+// @has 'foo/builders/struct.ActionRowBuilder.html'
+// @has - '//*[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+
+// And that the link in the module is targetting it.
+// @has 'foo/builders/index.html'
+// @has - '//a[@href="struct.ActionRowBuilder.html"]' 'ActionRowBuilder'
+
+mod auto {
+ mod action_row {
+ pub struct ActionRowBuilder;
+ }
+
+ #[doc(hidden)]
+ pub mod builders {
+ pub use super::action_row::ActionRowBuilder;
+ }
+}
+
+pub use auto::*;
+
+pub mod builders {
+ pub use crate::auto::builders::*;
+}
diff --git a/src/test/rustdoc/inline-default-methods.rs b/src/test/rustdoc/inline-default-methods.rs
new file mode 100644
index 000000000..c97644e7f
--- /dev/null
+++ b/src/test/rustdoc/inline-default-methods.rs
@@ -0,0 +1,9 @@
+// aux-build:inline-default-methods.rs
+// ignore-cross-compile
+
+extern crate inline_default_methods;
+
+// @has inline_default_methods/trait.Foo.html
+// @has - '//*[@class="rust trait"]' 'fn bar(&self);'
+// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }'
+pub use inline_default_methods::Foo;
diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs
new file mode 100644
index 000000000..8f0c4e5e6
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/add-docs.rs
@@ -0,0 +1,9 @@
+// aux-build:add-docs.rs
+
+extern crate inner;
+
+
+// @has add_docs/struct.MyStruct.html
+// @has add_docs/struct.MyStruct.html "Doc comment from ‘pub use’, Doc comment from definition"
+/// Doc comment from 'pub use',
+pub use inner::MyStruct;
diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs
new file mode 100644
index 000000000..231805a52
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/assoc-items.rs
@@ -0,0 +1,42 @@
+// aux-build:assoc-items.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+extern crate assoc_items;
+
+// @has foo/struct.MyStruct.html
+// @!has - 'PrivateConst'
+// @has - '//*[@id="associatedconstant.PublicConst"]' 'pub const PublicConst: u8'
+// @has - '//*[@class="docblock"]' 'docs for PublicConst'
+// @!has - 'private_method'
+// @has - '//*[@id="method.public_method"]' 'pub fn public_method()'
+// @has - '//*[@class="docblock"]' 'docs for public_method'
+// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
+// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
+// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
+// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
+// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
+// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
+// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
+// @has - '//*[@class="docblock"]' 'dox for method_no_default'
+// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
+// @has - '//div[@class="docblock"]' 'docs for method_with_default'
+pub use assoc_items::MyStruct;
+
+// @has foo/trait.MyTrait.html
+// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
+// @has - '//*[@class="docblock"]' 'docs for ConstNoDefault'
+// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
+// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault'
+// @has - '//*[@class="docblock"]' 'docs for TypeNoDefault'
+// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//*[@id="tymethod.method_no_default"]' 'fn method_no_default()'
+// @has - '//*[@class="docblock"]' 'docs for method_no_default'
+// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
+// @has - '//*[@class="docblock"]' 'docs for method_with_default'
+pub use assoc_items::MyTrait;
diff --git a/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs
new file mode 100644
index 000000000..85efa508f
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs
@@ -0,0 +1,4 @@
+#![crate_name = "inner"]
+
+/// Doc comment from definition
+pub struct MyStruct;
diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs
new file mode 100644
index 000000000..5fa299914
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs
@@ -0,0 +1,38 @@
+#![feature(associated_type_defaults)]
+
+pub struct MyStruct;
+
+impl MyStruct {
+ /// docs for PrivateConst
+ const PrivateConst: i8 = -123;
+ /// docs for PublicConst
+ pub const PublicConst: u8 = 123;
+ /// docs for private_method
+ fn private_method() {}
+ /// docs for public_method
+ pub fn public_method() {}
+}
+
+pub trait MyTrait {
+ /// docs for ConstNoDefault
+ const ConstNoDefault: i16;
+ /// docs for ConstWithDefault
+ const ConstWithDefault: u16 = 12345;
+ /// docs for TypeNoDefault
+ type TypeNoDefault;
+ /// docs for TypeWithDefault
+ type TypeWithDefault = u32;
+ /// docs for method_no_default
+ fn method_no_default();
+ /// docs for method_with_default
+ fn method_with_default() {}
+}
+
+impl MyTrait for MyStruct {
+ /// dox for ConstNoDefault
+ const ConstNoDefault: i16 = -12345;
+ /// dox for TypeNoDefault
+ type TypeNoDefault = i32;
+ /// dox for method_no_default
+ fn method_no_default() {}
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs b/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs
new file mode 100644
index 000000000..cde7f68ff
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs
@@ -0,0 +1,5 @@
+#![crate_name = "inner"]
+
+pub struct SomeStruct;
+
+pub fn some_fn() {}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs
new file mode 100644
index 000000000..ce60bbfb4
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs
@@ -0,0 +1,16 @@
+#![feature(specialization)]
+
+#![crate_name = "foo"]
+
+pub trait Item {
+ fn foo();
+ fn bar();
+ fn baz() {}
+}
+
+pub struct Foo;
+
+impl Item for Foo {
+ default fn foo() {}
+ fn bar() {}
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs
new file mode 100644
index 000000000..401a6a44a
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs
@@ -0,0 +1,8 @@
+pub trait MyTrait {
+ /// docs for my_trait_method
+ fn my_trait_method() {}
+}
+
+pub struct MyStruct;
+
+impl MyTrait for MyStruct {}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
new file mode 100644
index 000000000..913ba8f2a
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
@@ -0,0 +1,28 @@
+// edition:2018
+
+use std::ops::Deref;
+
+pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
+
+pub fn func2<T>(
+ _x: impl Deref<Target = Option<T>> + Iterator<Item = T>,
+ _y: impl Iterator<Item = u8>,
+) {}
+
+pub fn func3(_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone) {}
+
+pub fn func4<T: Iterator<Item = impl Clone>>(_x: T) {}
+
+pub async fn async_fn() {}
+
+pub struct Foo;
+
+impl Foo {
+ pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
+}
+
+pub struct Bar;
+
+impl Bar {
+ pub async fn async_foo(&self) {}
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs
new file mode 100644
index 000000000..b003fb357
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs
@@ -0,0 +1,18 @@
+pub mod my_trait {
+ pub trait MyTrait {
+ fn my_fn(&self) -> Self;
+ }
+}
+
+pub mod prelude {
+ #[doc(inline)]
+ pub use crate::my_trait::MyTrait;
+}
+
+pub struct SomeStruct;
+
+impl my_trait::MyTrait for SomeStruct {
+ fn my_fn(&self) -> SomeStruct {
+ SomeStruct
+ }
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs b/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs
new file mode 100644
index 000000000..4e1f1918e
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs
@@ -0,0 +1,7 @@
+#![crate_name="bar"]
+
+pub trait Bar {}
+pub struct Foo;
+
+impl<'a> Bar for &'a char {}
+impl Bar for Foo {}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs b/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs
new file mode 100644
index 000000000..5615a4fdd
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs
@@ -0,0 +1,25 @@
+#![crate_name = "qwop"]
+
+/// (written on a spider's web) Some Macro
+#[macro_export]
+macro_rules! some_macro {
+ () => {
+ println!("this is some macro, for sure");
+ };
+}
+
+/// Some other macro, to fill space.
+#[macro_export]
+macro_rules! other_macro {
+ () => {
+ println!("this is some other macro, whatev");
+ };
+}
+
+/// This macro is so cool, it's Super.
+#[macro_export]
+macro_rules! super_macro {
+ () => {
+ println!("is it a bird? a plane? no, it's Super Macro!");
+ };
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/macros.rs b/src/test/rustdoc/inline_cross/auxiliary/macros.rs
new file mode 100644
index 000000000..651ae2f1a
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/macros.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+/// docs for my_macro
+#[unstable(feature = "macro_test", issue = "none")]
+#[deprecated(since = "1.2.3", note = "text")]
+#[macro_export]
+macro_rules! my_macro {
+ () => {};
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs
new file mode 100644
index 000000000..d8e5746f3
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs
@@ -0,0 +1,47 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+
+#![crate_type="proc-macro"]
+#![crate_name="some_macros"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+macro_rules! make_attr_macro {
+ ($name:ident) => {
+ /// Generated doc comment
+ #[proc_macro_attribute]
+ pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream {
+ panic!()
+ }
+ }
+}
+
+make_attr_macro!(first_attr);
+make_attr_macro!(second_attr);
+
+/// a proc-macro that swallows its input and does nothing.
+#[proc_macro]
+pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+/// a proc-macro attribute that passes its item through verbatim.
+#[proc_macro_attribute]
+pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ item
+}
+
+/// a derive attribute that adds nothing to its input.
+#[proc_macro_derive(SomeDerive)]
+pub fn some_derive(_item: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+/// Doc comment from the original crate
+#[proc_macro]
+pub fn reexported_macro(_input: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs b/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs
new file mode 100644
index 000000000..2e5290782
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+pub mod iter {
+ mod range {
+ pub struct StepBy;
+ }
+ pub use self::range::StepBy as DeprecatedStepBy;
+ pub struct StepBy;
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs
new file mode 100644
index 000000000..6357b76df
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs
@@ -0,0 +1,12 @@
+pub struct Bar;
+
+impl Bar {
+ pub fn bar(_: u8) -> hidden::Hidden {
+ hidden::Hidden
+ }
+}
+
+#[doc(hidden)]
+pub mod hidden {
+ pub struct Hidden;
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs
new file mode 100644
index 000000000..0c75b3127
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs
@@ -0,0 +1,4 @@
+#[doc(hidden)]
+pub struct Foo;
+
+pub struct Bar;
diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs
new file mode 100644
index 000000000..4e461d3bc
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs
@@ -0,0 +1,34 @@
+pub struct Foo;
+
+pub trait Woof {}
+pub trait Bark {}
+
+mod private {
+ // should be shown
+ impl ::Woof for ::Foo {}
+
+ pub trait Bar {}
+ pub struct Wibble;
+
+ // these should not be shown
+ impl Bar for ::Foo {}
+ impl Bar for Wibble {}
+ impl ::Bark for Wibble {}
+ impl ::Woof for Wibble {}
+}
+
+#[doc(hidden)]
+pub mod hidden {
+ // should be shown
+ impl ::Bark for ::Foo {}
+
+ pub trait Qux {}
+ pub struct Wobble;
+
+
+ // these should only be shown if they're re-exported correctly
+ impl Qux for ::Foo {}
+ impl Qux for Wobble {}
+ impl ::Bark for Wobble {}
+ impl ::Woof for Wobble {}
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs
new file mode 100644
index 000000000..11d8733c4
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs
@@ -0,0 +1,13 @@
+use std::fmt;
+
+pub trait Bar {}
+
+impl<'a> Bar + 'a {
+ pub fn bar(&self) -> usize { 42 }
+}
+
+impl<'a> fmt::Debug for Bar + 'a {
+ fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+ Ok(())
+ }
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs
new file mode 100644
index 000000000..e5bc7969b
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs
@@ -0,0 +1,13 @@
+#![crate_name = "inner"]
+
+pub struct SomeStruct;
+
+fn asdf() {
+ const _FOO: () = {
+ impl Clone for SomeStruct {
+ fn clone(&self) -> Self {
+ SomeStruct
+ }
+ }
+ };
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs
new file mode 100644
index 000000000..75efbe0db
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs
@@ -0,0 +1,5 @@
+pub mod asdf {
+ pub struct SomeStruct;
+}
+
+pub trait SomeTrait {}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs
new file mode 100644
index 000000000..25b4c202e
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs
@@ -0,0 +1 @@
+pub struct SomethingElse;
diff --git a/src/test/rustdoc/inline_cross/cross-glob.rs b/src/test/rustdoc/inline_cross/cross-glob.rs
new file mode 100644
index 000000000..f97da11a9
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/cross-glob.rs
@@ -0,0 +1,11 @@
+// aux-build:cross-glob.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate inner;
+
+// @has cross_glob/struct.SomeStruct.html
+// @has cross_glob/fn.some_fn.html
+// @!has cross_glob/index.html '//code' 'pub use inner::*;'
+#[doc(inline)]
+pub use inner::*;
diff --git a/src/test/rustdoc/inline_cross/default-trait-method.rs b/src/test/rustdoc/inline_cross/default-trait-method.rs
new file mode 100644
index 000000000..a4ec73a12
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/default-trait-method.rs
@@ -0,0 +1,20 @@
+// aux-build:default-trait-method.rs
+
+extern crate foo;
+
+// @has default_trait_method/trait.Item.html
+// @has - '//*[@id="tymethod.foo"]' 'fn foo()'
+// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()'
+// @has - '//*[@id="tymethod.bar"]' 'fn bar()'
+// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()'
+// @has - '//*[@id="method.baz"]' 'fn baz()'
+// @!has - '//*[@id="method.baz"]' 'default fn baz()'
+pub use foo::Item;
+
+// @has default_trait_method/struct.Foo.html
+// @has - '//*[@id="method.foo"]' 'default fn foo()'
+// @has - '//*[@id="method.bar"]' 'fn bar()'
+// @!has - '//*[@id="method.bar"]' 'default fn bar()'
+// @has - '//*[@id="method.baz"]' 'fn baz()'
+// @!has - '//*[@id="method.baz"]' 'default fn baz()'
+pub use foo::Foo;
diff --git a/src/test/rustdoc/inline_cross/hidden-use.rs b/src/test/rustdoc/inline_cross/hidden-use.rs
new file mode 100644
index 000000000..97715737f
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/hidden-use.rs
@@ -0,0 +1,12 @@
+// aux-build:rustdoc-hidden.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_hidden;
+
+// @has hidden_use/index.html
+// @!has - 'rustdoc_hidden'
+// @!has - 'Bar'
+// @!has hidden_use/struct.Bar.html
+#[doc(hidden)]
+pub use rustdoc_hidden::Bar;
diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
new file mode 100644
index 000000000..9b67022fd
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
@@ -0,0 +1,12 @@
+// aux-build:impl-inline-without-trait.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+extern crate impl_inline_without_trait;
+
+// @has 'foo/struct.MyStruct.html'
+// @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
+// @has - '//div[@class="docblock"]' 'docs for my_trait_method'
+pub use impl_inline_without_trait::MyStruct;
diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs
new file mode 100644
index 000000000..ef615472b
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/impl_trait.rs
@@ -0,0 +1,40 @@
+// aux-build:impl_trait_aux.rs
+// edition:2018
+
+extern crate impl_trait_aux;
+
+// @has impl_trait/fn.func.html
+// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
+// @!has - '//pre[@class="rust fn"]' 'where'
+pub use impl_trait_aux::func;
+
+// @has impl_trait/fn.func2.html
+// @has - '//pre[@class="rust fn"]' "func2<T>("
+// @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
+// @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)"
+// @!has - '//pre[@class="rust fn"]' 'where'
+pub use impl_trait_aux::func2;
+
+// @has impl_trait/fn.func3.html
+// @has - '//pre[@class="rust fn"]' "func3("
+// @has - '//pre[@class="rust fn"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
+// @!has - '//pre[@class="rust fn"]' 'where'
+pub use impl_trait_aux::func3;
+
+// @has impl_trait/fn.func4.html
+// @has - '//pre[@class="rust fn"]' "func4<T>("
+// @has - '//pre[@class="rust fn"]' "T: Iterator<Item = impl Clone>,"
+pub use impl_trait_aux::func4;
+
+// @has impl_trait/fn.async_fn.html
+// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()"
+pub use impl_trait_aux::async_fn;
+
+// @has impl_trait/struct.Foo.html
+// @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
+// @!has - '//*[@id="method.method"]//h4[@class="code-header"]' 'where'
+pub use impl_trait_aux::Foo;
+
+// @has impl_trait/struct.Bar.html
+// @has - '//*[@id="method.async_foo"]' "pub async fn async_foo("
+pub use impl_trait_aux::Bar;
diff --git a/src/test/rustdoc/inline_cross/implementors-js.rs b/src/test/rustdoc/inline_cross/implementors-js.rs
new file mode 100644
index 000000000..c79f05d8d
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/implementors-js.rs
@@ -0,0 +1,25 @@
+// aux-build:implementors_inline.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate implementors_inline;
+
+// @!has implementors/implementors_js/trait.MyTrait.js
+// @has implementors/implementors_inline/my_trait/trait.MyTrait.js
+// @!has implementors/implementors_inline/prelude/trait.MyTrait.js
+// @has implementors_inline/my_trait/trait.MyTrait.html
+// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+// @has implementors_js/trait.MyTrait.html
+// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+/// When re-exporting this trait, the HTML will be inlined,
+/// but, vitally, the JavaScript will be located only at the
+/// one canonical path.
+pub use implementors_inline::prelude::MyTrait;
+
+pub struct OtherStruct;
+
+impl MyTrait for OtherStruct {
+ fn my_fn(&self) -> OtherStruct {
+ OtherStruct
+ }
+}
diff --git a/src/test/rustdoc/inline_cross/inline_hidden.rs b/src/test/rustdoc/inline_cross/inline_hidden.rs
new file mode 100644
index 000000000..dcceaadb9
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/inline_hidden.rs
@@ -0,0 +1,12 @@
+// aux-build:rustdoc-hidden.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_hidden;
+
+#[doc(no_inline)]
+pub use rustdoc_hidden::Foo;
+
+// @has inline_hidden/fn.foo.html
+// @!has - '//a/@title' 'Foo'
+pub fn foo(_: Foo) {}
diff --git a/src/test/rustdoc/inline_cross/issue-28480.rs b/src/test/rustdoc/inline_cross/issue-28480.rs
new file mode 100644
index 000000000..99f5b9007
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-28480.rs
@@ -0,0 +1,13 @@
+// aux-build:rustdoc-hidden-sig.rs
+// build-aux-docs
+// ignore-cross-compile
+
+// @has rustdoc_hidden_sig/struct.Bar.html
+// @!has - '//a/@title' 'Hidden'
+// @has - '//a' 'u8'
+extern crate rustdoc_hidden_sig;
+
+// @has issue_28480/struct.Bar.html
+// @!has - '//a/@title' 'Hidden'
+// @has - '//a' 'u8'
+pub use rustdoc_hidden_sig::Bar;
diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs
new file mode 100644
index 000000000..be8585dd1
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs
@@ -0,0 +1,27 @@
+// aux-build:rustdoc-nonreachable-impls.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_nonreachable_impls;
+
+// @has issue_31948_1/struct.Wobble.html
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
+pub use rustdoc_nonreachable_impls::hidden::Wobble;
+
+// @has issue_31948_1/trait.Bark.html
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+pub use rustdoc_nonreachable_impls::Bark;
+
+// @has issue_31948_1/trait.Woof.html
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+pub use rustdoc_nonreachable_impls::Woof;
+
+// @!has issue_31948_1/trait.Bar.html
+// @!has issue_31948_1/trait.Qux.html
diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs
new file mode 100644
index 000000000..7aa994f19
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs
@@ -0,0 +1,21 @@
+// aux-build:rustdoc-nonreachable-impls.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_nonreachable_impls;
+
+// @has issue_31948_2/struct.Wobble.html
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
+pub use rustdoc_nonreachable_impls::hidden::Wobble;
+
+// @has issue_31948_2/trait.Qux.html
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+pub use rustdoc_nonreachable_impls::hidden::Qux;
+
+// @!has issue_31948_2/trait.Bar.html
+// @!has issue_31948_2/trait.Woof.html
+// @!has issue_31948_2/trait.Bark.html
diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs
new file mode 100644
index 000000000..7bf4110d3
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-31948.rs
@@ -0,0 +1,29 @@
+// aux-build:rustdoc-nonreachable-impls.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_nonreachable_impls;
+
+// @has issue_31948/struct.Foo.html
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
+pub use rustdoc_nonreachable_impls::Foo;
+
+// @has issue_31948/trait.Bark.html
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
+pub use rustdoc_nonreachable_impls::Bark;
+
+// @has issue_31948/trait.Woof.html
+// @has - '//h3[@class="code-header in-band"]' 'for Foo'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
+pub use rustdoc_nonreachable_impls::Woof;
+
+// @!has issue_31948/trait.Bar.html
+// @!has issue_31948/trait.Qux.html
+// @!has issue_31948/struct.Wibble.html
+// @!has issue_31948/struct.Wobble.html
diff --git a/src/test/rustdoc/inline_cross/issue-32881.rs b/src/test/rustdoc/inline_cross/issue-32881.rs
new file mode 100644
index 000000000..8052339a8
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-32881.rs
@@ -0,0 +1,11 @@
+// aux-build:rustdoc-trait-object-impl.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_trait_object_impl;
+
+// @has issue_32881/trait.Bar.html
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> dyn Bar"
+// @has - '//h3[@class="code-header in-band"]' "impl<'a> Debug for dyn Bar"
+
+pub use rustdoc_trait_object_impl::Bar;
diff --git a/src/test/rustdoc/inline_cross/issue-33113.rs b/src/test/rustdoc/inline_cross/issue-33113.rs
new file mode 100644
index 000000000..c60859bbc
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-33113.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-33113.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate bar;
+
+// @has issue_33113/trait.Bar.html
+// @has - '//h3[@class="code-header in-band"]' "for &'a char"
+// @has - '//h3[@class="code-header in-band"]' "for Foo"
+pub use bar::Bar;
diff --git a/src/test/rustdoc/inline_cross/macro-vis.rs b/src/test/rustdoc/inline_cross/macro-vis.rs
new file mode 100644
index 000000000..9fefd38ad
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/macro-vis.rs
@@ -0,0 +1,36 @@
+// aux-build:macro-vis.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#[macro_use] extern crate qwop;
+
+// @has macro_vis/macro.some_macro.html
+// @has macro_vis/index.html '//a/@href' 'macro.some_macro.html'
+pub use qwop::some_macro;
+
+// @has macro_vis/macro.renamed_macro.html
+// @!has - '//pre' 'some_macro'
+// @has macro_vis/index.html '//a/@href' 'macro.renamed_macro.html'
+#[doc(inline)]
+pub use qwop::some_macro as renamed_macro;
+
+// @!has macro_vis/macro.other_macro.html
+// @!has macro_vis/index.html '//a/@href' 'macro.other_macro.html'
+// @!has - '//code' 'pub use qwop::other_macro;'
+#[doc(hidden)]
+pub use qwop::other_macro;
+
+// @has macro_vis/index.html '//code' 'pub use qwop::super_macro;'
+// @!has macro_vis/macro.super_macro.html
+#[doc(no_inline)]
+pub use qwop::super_macro;
+
+// @has macro_vis/macro.this_is_dope.html
+// @has macro_vis/index.html '//a/@href' 'macro.this_is_dope.html'
+/// What it says on the tin.
+#[macro_export]
+macro_rules! this_is_dope {
+ () => {
+ println!("yo check this out");
+ };
+}
diff --git a/src/test/rustdoc/inline_cross/macros.rs b/src/test/rustdoc/inline_cross/macros.rs
new file mode 100644
index 000000000..5daa0d4ba
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/macros.rs
@@ -0,0 +1,19 @@
+// aux-build:macros.rs
+// build-aux-docs
+
+#![feature(macro_test)]
+#![crate_name = "foo"]
+
+extern crate macros;
+
+// @has foo/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// Deprecated
+// @has - '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// Experimental
+
+// @has foo/macro.my_macro.html
+// @has - '//*[@class="docblock"]' 'docs for my_macro'
+// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text'
+// @has - '//*[@class="stab unstable"]' 'macro_test'
+// @has - '//a/@href' '../src/macros/macros.rs.html#8'
+pub use macros::my_macro;
diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs
new file mode 100644
index 000000000..532a295c0
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/proc_macro.rs
@@ -0,0 +1,36 @@
+// aux-build:proc_macro.rs
+// build-aux-docs
+
+extern crate some_macros;
+
+// @has proc_macro/index.html
+// @has - '//a/@href' 'macro.some_proc_macro.html'
+// @has - '//a/@href' 'attr.some_proc_attr.html'
+// @has - '//a/@href' 'derive.SomeDerive.html'
+// @has proc_macro/macro.some_proc_macro.html
+// @has proc_macro/attr.some_proc_attr.html
+// @has proc_macro/derive.SomeDerive.html
+
+// @has proc_macro/macro.some_proc_macro.html
+// @has - 'a proc-macro that swallows its input and does nothing.'
+pub use some_macros::some_proc_macro;
+
+// @has proc_macro/macro.reexported_macro.html
+// @has - 'Doc comment from the original crate'
+pub use some_macros::reexported_macro;
+
+// @has proc_macro/attr.some_proc_attr.html
+// @has - 'a proc-macro attribute that passes its item through verbatim.'
+pub use some_macros::some_proc_attr;
+
+// @has proc_macro/derive.SomeDerive.html
+// @has - 'a derive attribute that adds nothing to its input.'
+pub use some_macros::SomeDerive;
+
+// @has proc_macro/attr.first_attr.html
+// @has - 'Generated doc comment'
+pub use some_macros::first_attr;
+
+// @has proc_macro/attr.second_attr.html
+// @has - 'Generated doc comment'
+pub use some_macros::second_attr;
diff --git a/src/test/rustdoc/inline_cross/renamed-via-module.rs b/src/test/rustdoc/inline_cross/renamed-via-module.rs
new file mode 100644
index 000000000..cdedbf070
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/renamed-via-module.rs
@@ -0,0 +1,24 @@
+// aux-build:renamed-via-module.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "bar"]
+
+extern crate foo;
+
+// @has foo/iter/index.html
+// @has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
+// @has - '//a/[@href="struct.StepBy.html"]' "StepBy"
+// @has foo/iter/struct.DeprecatedStepBy.html
+// @has - '//h1' "Struct foo::iter::DeprecatedStepBy"
+// @has foo/iter/struct.StepBy.html
+// @has - '//h1' "Struct foo::iter::StepBy"
+
+// @has bar/iter/index.html
+// @has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
+// @has - '//a/[@href="struct.StepBy.html"]' "StepBy"
+// @has bar/iter/struct.DeprecatedStepBy.html
+// @has - '//h1' "Struct bar::iter::DeprecatedStepBy"
+// @has bar/iter/struct.StepBy.html
+// @has - '//h1' "Struct bar::iter::StepBy"
+pub use foo::iter;
diff --git a/src/test/rustdoc/inline_cross/trait-vis.rs b/src/test/rustdoc/inline_cross/trait-vis.rs
new file mode 100644
index 000000000..363c52a33
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/trait-vis.rs
@@ -0,0 +1,7 @@
+// aux-build:trait-vis.rs
+
+extern crate inner;
+
+// @has trait_vis/struct.SomeStruct.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
+pub use inner::SomeStruct;
diff --git a/src/test/rustdoc/inline_cross/use_crate.rs b/src/test/rustdoc/inline_cross/use_crate.rs
new file mode 100644
index 000000000..00e0f041c
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/use_crate.rs
@@ -0,0 +1,27 @@
+// aux-build:use_crate.rs
+// aux-build:use_crate_2.rs
+// build-aux-docs
+// edition:2018
+// compile-flags:--extern use_crate --extern use_crate_2
+
+// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it
+// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement
+// in docs... unless you added `#[doc(inline)]`.
+
+#![crate_name = "local"]
+
+// @!has-dir local/use_crate
+// @has local/index.html
+// @has - '//code' 'pub use use_crate'
+pub use use_crate;
+
+// @has-dir local/asdf
+// @has local/asdf/index.html
+// @has local/index.html '//a/@href' 'asdf/index.html'
+pub use use_crate::asdf;
+
+// @has-dir local/use_crate_2
+// @has local/use_crate_2/index.html
+// @has local/index.html '//a/@href' 'use_crate_2/index.html'
+#[doc(inline)]
+pub use use_crate_2;
diff --git a/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs b/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs
new file mode 100644
index 000000000..a2f0d65ef
--- /dev/null
+++ b/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs
@@ -0,0 +1,25 @@
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+mod mod1 {
+ extern "C" {
+ pub fn public_fn();
+ fn private_fn();
+ }
+}
+
+pub use mod1::*;
+
+// @has foo/index.html
+// @has - "mod1"
+// @has - "public_fn"
+// @!has - "private_fn"
+// @has foo/fn.public_fn.html
+// @!has foo/fn.private_fn.html
+
+// @has foo/mod1/index.html
+// @has - "public_fn"
+// @has - "private_fn"
+// @has foo/mod1/fn.public_fn.html
+// @has foo/mod1/fn.private_fn.html
diff --git a/src/test/rustdoc/inline_local/glob-extern.rs b/src/test/rustdoc/inline_local/glob-extern.rs
new file mode 100644
index 000000000..686e55de3
--- /dev/null
+++ b/src/test/rustdoc/inline_local/glob-extern.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+
+mod mod1 {
+ extern "C" {
+ pub fn public_fn();
+ fn private_fn();
+ }
+}
+
+pub use mod1::*;
+
+// @has foo/index.html
+// @!has - "mod1"
+// @has - "public_fn"
+// @!has - "private_fn"
+// @has foo/fn.public_fn.html
+// @!has foo/fn.private_fn.html
+
+// @!has foo/mod1/index.html
+// @has foo/mod1/fn.public_fn.html
+// @!has foo/mod1/fn.private_fn.html
diff --git a/src/test/rustdoc/inline_local/glob-private-document-private-items.rs b/src/test/rustdoc/inline_local/glob-private-document-private-items.rs
new file mode 100644
index 000000000..f16d21ecd
--- /dev/null
+++ b/src/test/rustdoc/inline_local/glob-private-document-private-items.rs
@@ -0,0 +1,48 @@
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+mod mod1 {
+ mod mod2 {
+ pub struct Mod2Public;
+ struct Mod2Private;
+ }
+ pub use self::mod2::*;
+
+ pub struct Mod1Public;
+ struct Mod1Private;
+}
+pub use mod1::*;
+
+// @has foo/index.html
+// @has - "mod1"
+// @has - "Mod1Public"
+// @!has - "Mod1Private"
+// @!has - "mod2"
+// @has - "Mod2Public"
+// @!has - "Mod2Private"
+// @has foo/struct.Mod1Public.html
+// @!has foo/struct.Mod1Private.html
+// @has foo/struct.Mod2Public.html
+// @!has foo/struct.Mod2Private.html
+
+// @has foo/mod1/index.html
+// @has - "mod2"
+// @has - "Mod1Public"
+// @has - "Mod1Private"
+// @!has - "Mod2Public"
+// @!has - "Mod2Private"
+// @has foo/mod1/struct.Mod1Public.html
+// @has foo/mod1/struct.Mod1Private.html
+// @!has foo/mod1/struct.Mod2Public.html
+// @!has foo/mod1/struct.Mod2Private.html
+
+// @has foo/mod1/mod2/index.html
+// @has - "Mod2Public"
+// @has - "Mod2Private"
+// @has foo/mod1/mod2/struct.Mod2Public.html
+// @has foo/mod1/mod2/struct.Mod2Private.html
+
+// @!has foo/mod2/index.html
+// @!has foo/mod2/struct.Mod2Public.html
+// @!has foo/mod2/struct.Mod2Private.html
diff --git a/src/test/rustdoc/inline_local/glob-private.rs b/src/test/rustdoc/inline_local/glob-private.rs
new file mode 100644
index 000000000..d294d590e
--- /dev/null
+++ b/src/test/rustdoc/inline_local/glob-private.rs
@@ -0,0 +1,42 @@
+#![crate_name = "foo"]
+
+mod mod1 {
+ mod mod2 {
+ pub struct Mod2Public;
+ struct Mod2Private;
+ }
+ pub use self::mod2::*;
+
+ pub struct Mod1Public;
+ struct Mod1Private;
+}
+pub use mod1::*;
+
+// @has foo/index.html
+// @!has - "mod1"
+// @has - "Mod1Public"
+// @!has - "Mod1Private"
+// @!has - "mod2"
+// @has - "Mod2Public"
+// @!has - "Mod2Private"
+// @has foo/struct.Mod1Public.html
+// @!has foo/struct.Mod1Private.html
+// @has foo/struct.Mod2Public.html
+// @!has foo/struct.Mod2Private.html
+
+// @has-dir foo/mod1
+// @!has foo/mod1/index.html
+// @has foo/mod1/struct.Mod1Public.html
+// @!has foo/mod1/struct.Mod1Private.html
+// @!has foo/mod1/struct.Mod2Public.html
+// @!has foo/mod1/struct.Mod2Private.html
+
+// @has-dir foo/mod1/mod2
+// @!has foo/mod1/mod2/index.html
+// @has foo/mod1/mod2/struct.Mod2Public.html
+// @!has foo/mod1/mod2/struct.Mod2Private.html
+
+// @!has-dir foo/mod2
+// @!has foo/mod2/index.html
+// @!has foo/mod2/struct.Mod2Public.html
+// @!has foo/mod2/struct.Mod2Private.html
diff --git a/src/test/rustdoc/inline_local/hidden-use.rs b/src/test/rustdoc/inline_local/hidden-use.rs
new file mode 100644
index 000000000..a972d376a
--- /dev/null
+++ b/src/test/rustdoc/inline_local/hidden-use.rs
@@ -0,0 +1,10 @@
+mod private {
+ pub struct Foo {}
+}
+
+// @has hidden_use/index.html
+// @!has - 'private'
+// @!has - 'Foo'
+// @!has hidden_use/struct.Foo.html
+#[doc(hidden)]
+pub use private::Foo;
diff --git a/src/test/rustdoc/inline_local/issue-28537.rs b/src/test/rustdoc/inline_local/issue-28537.rs
new file mode 100644
index 000000000..da9cc4c94
--- /dev/null
+++ b/src/test/rustdoc/inline_local/issue-28537.rs
@@ -0,0 +1,17 @@
+#[doc(hidden)]
+pub mod foo {
+ pub struct Foo;
+}
+
+mod bar {
+ pub use self::bar::Bar;
+ mod bar {
+ pub struct Bar;
+ }
+}
+
+// @has issue_28537/struct.Foo.html
+pub use foo::Foo;
+
+// @has issue_28537/struct.Bar.html
+pub use self::bar::Bar;
diff --git a/src/test/rustdoc/inline_local/issue-32343.rs b/src/test/rustdoc/inline_local/issue-32343.rs
new file mode 100644
index 000000000..5620ae0dc
--- /dev/null
+++ b/src/test/rustdoc/inline_local/issue-32343.rs
@@ -0,0 +1,23 @@
+// @!has issue_32343/struct.Foo.html
+// @has issue_32343/index.html
+// @has - '//code' 'pub use foo::Foo'
+// @!has - '//code/a' 'Foo'
+#[doc(no_inline)]
+pub use foo::Foo;
+
+// @!has issue_32343/struct.Bar.html
+// @has issue_32343/index.html
+// @has - '//code' 'pub use foo::Bar'
+// @has - '//code/a' 'Bar'
+#[doc(no_inline)]
+pub use foo::Bar;
+
+mod foo {
+ pub struct Foo;
+ pub struct Bar;
+}
+
+pub mod bar {
+ // @has issue_32343/bar/struct.Bar.html
+ pub use ::foo::Bar;
+}
diff --git a/src/test/rustdoc/inline_local/macro_by_example.rs b/src/test/rustdoc/inline_local/macro_by_example.rs
new file mode 100644
index 000000000..dacc7cfb3
--- /dev/null
+++ b/src/test/rustdoc/inline_local/macro_by_example.rs
@@ -0,0 +1,17 @@
+/// docs for foo
+#[deprecated(since = "1.2.3", note = "text")]
+#[macro_export]
+macro_rules! foo {
+ ($($tt:tt)*) => {}
+}
+
+// @has macro_by_example/macros/index.html
+pub mod macros {
+ // @!has - 'pub use foo as bar;'
+ // @has macro_by_example/macros/macro.bar.html
+ // @has - '//*[@class="docblock"]' 'docs for foo'
+ // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text'
+ // @has - '//a/@href' 'macro_by_example.rs.html#4-6'
+ #[doc(inline)]
+ pub use foo as bar;
+}
diff --git a/src/test/rustdoc/inline_local/please_inline.rs b/src/test/rustdoc/inline_local/please_inline.rs
new file mode 100644
index 000000000..48539361f
--- /dev/null
+++ b/src/test/rustdoc/inline_local/please_inline.rs
@@ -0,0 +1,19 @@
+pub mod foo {
+ pub struct Foo;
+}
+
+// @has please_inline/a/index.html
+pub mod a {
+ // @!has - 'pub use foo::'
+ // @has please_inline/a/struct.Foo.html
+ #[doc(inline)]
+ pub use foo::Foo;
+}
+
+// @has please_inline/b/index.html
+pub mod b {
+ // @has - 'pub use foo::'
+ // @!has please_inline/b/struct.Foo.html
+ #[feature(inline)]
+ pub use foo::Foo;
+}
diff --git a/src/test/rustdoc/inline_local/trait-vis.rs b/src/test/rustdoc/inline_local/trait-vis.rs
new file mode 100644
index 000000000..e7b08088f
--- /dev/null
+++ b/src/test/rustdoc/inline_local/trait-vis.rs
@@ -0,0 +1,18 @@
+pub trait ThisTrait {}
+
+mod asdf {
+ use ThisTrait;
+
+ pub struct SomeStruct;
+
+ impl ThisTrait for SomeStruct {}
+
+ trait PrivateTrait {}
+
+ impl PrivateTrait for SomeStruct {}
+}
+
+// @has trait_vis/struct.SomeStruct.html
+// @has - '//h3[@class="code-header in-band"]' 'impl ThisTrait for SomeStruct'
+// @!has - '//h3[@class="code-header in-band"]' 'impl PrivateTrait for SomeStruct'
+pub use asdf::SomeStruct;
diff --git a/src/test/rustdoc/internal.rs b/src/test/rustdoc/internal.rs
new file mode 100644
index 000000000..f316eb24a
--- /dev/null
+++ b/src/test/rustdoc/internal.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Z force-unstable-if-unmarked
+
+// Check that the unstable marker is not added for "rustc_private".
+
+// @!matches internal/index.html \
+// '//*[@class="item-right docblock-short"]/span[@class="stab unstable"]'
+// @!matches internal/index.html \
+// '//*[@class="item-right docblock-short"]/span[@class="stab internal"]'
+// @matches - '//*[@class="item-right docblock-short"]' 'Docs'
+
+// @!has internal/struct.S.html '//*[@class="stab unstable"]'
+// @!has internal/struct.S.html '//*[@class="stab internal"]'
+/// Docs
+pub struct S;
+
+fn main() {}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs
new file mode 100644
index 000000000..54902f12e
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs
@@ -0,0 +1,10 @@
+#![crate_name = "cross_crate_self"]
+
+/// Link to [Self]
+/// Link to [crate]
+pub struct S;
+
+impl S {
+ /// Link to [Self::f]
+ pub fn f() {}
+}
diff --git a/src/test/rustdoc/intra-doc-crate/self.rs b/src/test/rustdoc/intra-doc-crate/self.rs
new file mode 100644
index 000000000..8c36a7fa0
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/self.rs
@@ -0,0 +1,9 @@
+// aux-build:self.rs
+// build-aux-docs
+
+extern crate cross_crate_self;
+
+// @has self/struct.S.html '//a[@href="struct.S.html#method.f"]' "Self::f"
+// @has self/struct.S.html '//a[@href="struct.S.html"]' "Self"
+// @has self/struct.S.html '//a[@href="../cross_crate_self/index.html"]' "crate"
+pub use cross_crate_self::S;
diff --git a/src/test/rustdoc/intra-doc/anchors.rs b/src/test/rustdoc/intra-doc/anchors.rs
new file mode 100644
index 000000000..3d4c46496
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/anchors.rs
@@ -0,0 +1,24 @@
+/// I want...
+///
+/// # Anchor!
+pub struct Something;
+
+// @has anchors/struct.SomeOtherType.html
+// @has - '//a/@href' 'struct.Something.html#Anchor!'
+
+/// I want...
+///
+/// To link to [Something#Anchor!]
+pub struct SomeOtherType;
+
+/// Primitives?
+///
+/// [u32#hello]
+// @has anchors/fn.x.html
+// @has - '//a/@href' '{{channel}}/std/primitive.u32.html#hello'
+pub fn x() {}
+
+/// [prim@usize#x]
+// @has anchors/usize/index.html
+// @has - '//a/@href' '{{channel}}/std/primitive.usize.html#x'
+pub mod usize {}
diff --git a/src/test/rustdoc/intra-doc/associated-defaults.rs b/src/test/rustdoc/intra-doc/associated-defaults.rs
new file mode 100644
index 000000000..c7e66c826
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-defaults.rs
@@ -0,0 +1,26 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(associated_type_defaults)]
+
+pub trait TraitWithDefault {
+ type T = usize;
+ fn f() -> Self::T {
+ 0
+ }
+}
+
+/// Link to [UsesDefaults::T] and [UsesDefaults::f]
+// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T'
+// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f'
+pub struct UsesDefaults;
+impl TraitWithDefault for UsesDefaults {}
+
+/// Link to [OverridesDefaults::T] and [OverridesDefaults::f]
+// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T'
+// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f'
+pub struct OverridesDefaults;
+impl TraitWithDefault for OverridesDefaults {
+ type T = bool;
+ fn f() -> bool {
+ true
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs
new file mode 100644
index 000000000..0b958eb8e
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-items.rs
@@ -0,0 +1,68 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// [`std::collections::BTreeMap::into_iter`]
+/// [`String::from`] is ambiguous as to which `From` impl
+/// [Vec::into_iter()] uses a disambiguator
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+pub fn foo() {}
+
+/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html"]' 'MyStruct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input'
+pub struct MyStruct { foo: () }
+
+impl Clone for MyStruct {
+ fn clone(&self) -> Self {
+ MyStruct
+ }
+}
+
+pub trait T {
+ type Input;
+ fn method(i: Self::Input);
+}
+
+impl T for MyStruct {
+ type Input = usize;
+
+ /// [link from method][MyStruct::method] on method
+ // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method'
+ fn method(i: usize) {
+ }
+}
+
+/// Ambiguity between which trait to use
+pub trait T1 {
+ fn ambiguous_method();
+}
+
+pub trait T2 {
+ fn ambiguous_method();
+}
+
+/// Link to [S::ambiguous_method]
+// FIXME: there is no way to disambiguate these.
+// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other.
+pub struct S;
+
+impl T1 for S {
+ fn ambiguous_method() {}
+}
+
+impl T2 for S {
+ fn ambiguous_method() {}
+}
+
+// @has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant'
+/// Link to [MyEnumAlias::MyVariant]
+pub enum MyEnum {
+ MyVariant,
+}
+
+pub type MyEnumAlias = MyEnum;
+
+fn main() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty.rs b/src/test/rustdoc/intra-doc/auxiliary/empty.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/empty.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty2.rs b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs
new file mode 100644
index 000000000..d9a08cb41
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs
@@ -0,0 +1,28 @@
+// no-prefer-dynamic
+
+#![feature(lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_std]
+
+pub struct DerefsToF64(f64);
+
+impl core::ops::Deref for DerefsToF64 {
+ type Target = f64;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+mod inner {
+ impl f64 {
+ /// [f64::clone]
+ #[rustc_allow_incoherent_impl]
+ pub fn method() {}
+ }
+}
+
+#[lang = "eh_personality"]
+fn foo() {}
+
+#[panic_handler]
+fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
new file mode 100644
index 000000000..ee4138b68
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
@@ -0,0 +1,11 @@
+#[derive(Clone)]
+pub struct PublicStruct;
+
+mod inner {
+ use super::PublicStruct;
+
+ impl PublicStruct {
+ /// [PublicStruct::clone]
+ pub fn method() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
new file mode 100644
index 000000000..db3bb38ad
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
@@ -0,0 +1,3 @@
+#![crate_name="inner"]
+
+//! ooh, i'm a rebel just for [kicks]
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
new file mode 100644
index 000000000..a4db2ffc4
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
@@ -0,0 +1,4 @@
+#![crate_name = "inner"]
+
+/// Documentation, including a link to [std::ptr]
+pub fn f() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
new file mode 100644
index 000000000..fc51995a9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,6 @@
+#![crate_name = "inner"]
+
+/// Links to [f()]
+pub struct Inner;
+
+pub fn f() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
new file mode 100644
index 000000000..6142dcda9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
@@ -0,0 +1,6 @@
+pub trait ThisTrait {
+ fn asdf(&self);
+
+ /// let's link to [`asdf`](ThisTrait::asdf)
+ fn qwop(&self);
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs
new file mode 100644
index 000000000..2f3d069bd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs
@@ -0,0 +1,2 @@
+/// This will be referred to by the test docstring
+pub struct Something;
diff --git a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
new file mode 100644
index 000000000..e22feb03a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -0,0 +1,23 @@
+#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs)]
+#![no_core]
+#![rustc_coherence_is_core]
+#![crate_type="rlib"]
+
+#[doc(primitive = "char")]
+/// Some char docs
+mod char {}
+
+impl char {
+ pub fn len_utf8(self) -> usize {
+ 42
+ }
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {}
+
+#[lang = "copy"]
+pub trait Copy: Clone {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
new file mode 100644
index 000000000..5ba132f25
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
@@ -0,0 +1,34 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+
+#![crate_type="proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(DeriveB)]
+pub fn b_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(DeriveTrait)]
+pub fn trait_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn attr_b(input: TokenStream, _args: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
new file mode 100644
index 000000000..75d428932
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
@@ -0,0 +1 @@
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/basic.rs b/src/test/rustdoc/intra-doc/basic.rs
new file mode 100644
index 000000000..39f5c298b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/basic.rs
@@ -0,0 +1,84 @@
+// @has basic/index.html
+// @has - '//a/@href' 'struct.ThisType.html'
+// @has - '//a/@href' 'struct.ThisType.html#method.this_method'
+// @has - '//a/@href' 'enum.ThisEnum.html'
+// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
+// @has - '//a/@href' 'trait.ThisTrait.html'
+// @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method'
+// @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType'
+// @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
+// @has - '//a/@href' 'trait.ThisTrait.html'
+// @has - '//a/@href' 'type.ThisAlias.html'
+// @has - '//a/@href' 'union.ThisUnion.html'
+// @has - '//a/@href' 'fn.this_function.html'
+// @has - '//a/@href' 'constant.THIS_CONST.html'
+// @has - '//a/@href' 'static.THIS_STATIC.html'
+// @has - '//a/@href' 'macro.this_macro.html'
+// @has - '//a/@href' 'trait.SoAmbiguous.html'
+// @has - '//a/@href' 'fn.SoAmbiguous.html'
+//! In this crate we would like to link to:
+//!
+//! * [`ThisType`](ThisType)
+//! * [`ThisType::this_method`](ThisType::this_method)
+//! * [`ThisEnum`](ThisEnum)
+//! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant)
+//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor)
+//! * [`ThisTrait`](ThisTrait)
+//! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method)
+//! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType)
+//! * [`ThisTrait::THIS_ASSOCIATED_CONST`](ThisTrait::THIS_ASSOCIATED_CONST)
+//! * [`ThisAlias`](ThisAlias)
+//! * [`ThisUnion`](ThisUnion)
+//! * [`this_function`](this_function())
+//! * [`THIS_CONST`](const@THIS_CONST)
+//! * [`THIS_STATIC`](static@THIS_STATIC)
+//! * [`this_macro`](this_macro!)
+//!
+//! In addition, there's some specifics we want to look at. There's [a trait called
+//! SoAmbiguous][ambig-trait], but there's also [a function called SoAmbiguous][ambig-fn] too!
+//! Whatever shall we do?
+//!
+//! [ambig-trait]: trait@SoAmbiguous
+//! [ambig-fn]: SoAmbiguous()
+
+#[macro_export]
+macro_rules! this_macro {
+ () => {};
+}
+
+// @has basic/struct.ThisType.html '//a/@href' 'macro.this_macro.html'
+/// another link to [`this_macro!()`]
+pub struct ThisType;
+
+impl ThisType {
+ pub fn this_method() {}
+}
+pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), }
+pub trait ThisTrait {
+ type ThisAssociatedType;
+ const THIS_ASSOCIATED_CONST: u8;
+ fn this_associated_method();
+}
+pub type ThisAlias = Result<(), ()>;
+pub union ThisUnion { this_field: usize, }
+
+pub fn this_function() {}
+pub const THIS_CONST: usize = 5usize;
+pub static THIS_STATIC: usize = 5usize;
+
+pub trait SoAmbiguous {}
+
+#[allow(nonstandard_style)]
+pub fn SoAmbiguous() {}
+
+
+// @has basic/struct.SomeOtherType.html '//a/@href' 'struct.ThisType.html'
+// @has - '//a/@href' 'struct.ThisType.html#method.this_method'
+// @has - '//a/@href' 'enum.ThisEnum.html'
+// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
+/// Shortcut links for:
+/// * [`ThisType`]
+/// * [`ThisType::this_method`]
+/// * [ThisEnum]
+/// * [ThisEnum::ThisVariant]
+pub struct SomeOtherType;
diff --git a/src/test/rustdoc/intra-doc/builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs
new file mode 100644
index 000000000..bbdbe246b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/builtin-macros.rs
@@ -0,0 +1,3 @@
+// @has builtin_macros/index.html
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
+//! [cfg]
diff --git a/src/test/rustdoc/intra-doc/crate-relative-assoc.rs b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs
new file mode 100644
index 000000000..d4a0ecc35
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs
@@ -0,0 +1,17 @@
+pub mod io {
+ pub trait Read {
+ fn read(&mut self);
+ }
+}
+
+pub mod bufreader {
+ // @has crate_relative_assoc/bufreader/index.html '//a/@href' 'struct.TcpStream.html#method.read'
+ //! [`crate::TcpStream::read`]
+ use crate::io::Read;
+}
+
+pub struct TcpStream;
+
+impl crate::io::Read for TcpStream {
+ fn read(&mut self) {}
+}
diff --git a/src/test/rustdoc/intra-doc/crate-relative.rs b/src/test/rustdoc/intra-doc/crate-relative.rs
new file mode 100644
index 000000000..bacbcabfc
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/crate-relative.rs
@@ -0,0 +1,13 @@
+pub struct Test<'a> {
+ data: &'a (),
+}
+
+impl<'a> Test<'a> {
+ pub fn do_test(&self) {}
+}
+
+// @has crate_relative/demo/index.html
+// @has - '//a/@href' '../struct.Test.html#method.do_test'
+pub mod demo {
+ //! [`crate::Test::do_test`]
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
new file mode 100644
index 000000000..e52fb9b1c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
@@ -0,0 +1,10 @@
+// aux-build:additional_doc.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate my_rand;
+
+// @has 'additional_doc/trait.Rng.html' '//a[@href="trait.Rng.html"]' 'Rng'
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore'
+/// This is an [`Rng`].
+pub use my_rand::Rng;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
new file mode 100644
index 000000000..684fdd449
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
@@ -0,0 +1,6 @@
+#![crate_name = "my_rand"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait RngCore {}
+/// Rng extends [`RngCore`].
+pub trait Rng: RngCore {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
new file mode 100644
index 000000000..34f4e9f63
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
@@ -0,0 +1,19 @@
+#![crate_name = "hidden_dep"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+#[doc(hidden)]
+pub mod __reexport {
+ pub use crate::*;
+}
+
+pub mod future {
+ mod ready {
+
+ /// Link to [`ready`](function@ready)
+ pub struct Ready;
+ pub fn ready() {}
+
+ }
+ pub use self::ready::{ready, Ready};
+
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
new file mode 100644
index 000000000..d6a829966
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
@@ -0,0 +1,7 @@
+#![crate_name = "a"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct Foo;
+
+/// Link to [Foo]
+pub struct Bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
new file mode 100644
index 000000000..a37848e23
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
@@ -0,0 +1,5 @@
+#![crate_name = "inner"]
+
+/// Links to [crate::g]
+pub fn f() {}
+pub fn g() {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
new file mode 100644
index 000000000..cb7a8afb6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
@@ -0,0 +1,10 @@
+#![crate_name = "macro_inner"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct Foo;
+
+/// See also [`Foo`]
+#[macro_export]
+macro_rules! my_macro {
+ () => {}
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
new file mode 100644
index 000000000..018fdedd9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
@@ -0,0 +1,7 @@
+#![crate_name = "module_inner"]
+#![deny(rustdoc::broken_intra_doc_links)]
+/// [SomeType] links to [bar]
+pub struct SomeType;
+pub trait SomeTrait {}
+/// [bar] links to [SomeTrait] and also [SomeType]
+pub mod bar {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
new file mode 100644
index 000000000..0d5a95407
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+#![crate_type="proc-macro"]
+#![crate_name="proc_macro_inner"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+/// Links to [`OtherDerive`]
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(OtherDerive)]
+pub fn other_derive(input: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
new file mode 100644
index 000000000..0612f53d6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
@@ -0,0 +1,12 @@
+#![crate_name = "a"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod bar {
+ pub struct Bar;
+}
+
+pub mod foo {
+ use crate::bar;
+ /// link to [bar::Bar]
+ pub struct Foo;
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
new file mode 100644
index 000000000..105eb8e11
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
@@ -0,0 +1,13 @@
+#![crate_name = "bar"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Foo {
+ /// [`Bar`] [`Baz`]
+ fn foo();
+}
+
+pub trait Bar {
+}
+
+pub trait Baz {
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
new file mode 100644
index 000000000..c16e39d56
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
@@ -0,0 +1,16 @@
+#![crate_name = "inner"]
+/// this is a trait
+pub trait SomeTrait {
+ /// this is a method for [a trait][SomeTrait]
+ fn foo();
+}
+
+pub mod bar {
+ use super::SomeTrait;
+
+ pub struct BarStruct;
+
+ impl SomeTrait for BarStruct {
+ fn foo() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
new file mode 100644
index 000000000..ad7454918
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
@@ -0,0 +1,9 @@
+// aux-build:intra-doc-basic.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// from https://github.com/rust-lang/rust/issues/65983
+extern crate a;
+
+// @has 'basic/struct.Bar.html' '//a[@href="../a/struct.Foo.html"]' 'Foo'
+pub use a::Bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/crate.rs b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
new file mode 100644
index 000000000..edf544708
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
@@ -0,0 +1,6 @@
+// aux-build:intra-link-cross-crate-crate.rs
+// build-aux-docs
+#![crate_name = "outer"]
+extern crate inner;
+// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g"
+pub use inner::f;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
new file mode 100644
index 000000000..4f7d075ba
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
@@ -0,0 +1,10 @@
+// aux-build:hidden.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// tests https://github.com/rust-lang/rust/issues/73363
+
+extern crate hidden_dep;
+
+// @has 'hidden/struct.Ready.html' '//a/@href' 'fn.ready.html'
+pub use hidden_dep::future::{ready, Ready};
diff --git a/src/test/rustdoc/intra-doc/cross-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
new file mode 100644
index 000000000..32f0a55d3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
@@ -0,0 +1,11 @@
+// aux-build:macro_inner.rs
+// aux-build:proc_macro.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+extern crate macro_inner;
+extern crate proc_macro_inner;
+
+// @has 'macro/macro.my_macro.html' '//a[@href="../macro_inner/struct.Foo.html"]' 'Foo'
+pub use macro_inner::my_macro;
+// @has 'macro/derive.DeriveA.html' '//a[@href="../proc_macro_inner/derive.OtherDerive.html"]' 'OtherDerive'
+pub use proc_macro_inner::DeriveA;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs
new file mode 100644
index 000000000..fde932265
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/module.rs
@@ -0,0 +1,8 @@
+// outer.rs
+// aux-build: module.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+extern crate module_inner;
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
+pub use module_inner::bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
new file mode 100644
index 000000000..577fe78a5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
@@ -0,0 +1,8 @@
+// aux-build:submodule-inner.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate a;
+
+// @has 'submodule_inner/struct.Foo.html' '//a[@href="../a/bar/struct.Bar.html"]' 'Bar'
+pub use a::foo::Foo;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
new file mode 100644
index 000000000..d0c0b7e85
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
@@ -0,0 +1,16 @@
+// aux-build:submodule-outer.rs
+// edition:2018
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate bar as bar_;
+
+// from https://github.com/rust-lang/rust/issues/60883
+pub mod bar {
+ pub use ::bar_::Bar;
+}
+
+// NOTE: we re-exported both `Foo` and `Bar` here,
+// NOTE: so they are inlined and therefore we link to the current module.
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="bar/trait.Bar.html"]' 'Bar'
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="trait.Baz.html"]' 'Baz'
+pub use ::bar_::{Foo, Baz};
diff --git a/src/test/rustdoc/intra-doc/cross-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
new file mode 100644
index 000000000..7b9554bfd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
@@ -0,0 +1,14 @@
+// aux-build:traits.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate inner;
+use inner::SomeTrait;
+
+pub struct SomeStruct;
+
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'SomeTrait'
+impl SomeTrait for SomeStruct {
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'a trait'
+ fn foo() {}
+}
diff --git a/src/test/rustdoc/intra-doc/disambiguators-removed.rs b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
new file mode 100644
index 000000000..331a31413
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
@@ -0,0 +1,50 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+// first try backticks
+/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
+// @has disambiguators_removed/struct.AtDisambiguator.html
+// @has - '//a[@href="trait.Name.html"][code]' "Name"
+// @has - '//a[@href="fn.Name.html"][code]' "Name"
+// @has - '//a[@href="macro.Name.html"][code]' "Name"
+pub struct AtDisambiguator;
+
+/// fn: [`Name()`], macro: [`Name!`]
+// @has disambiguators_removed/struct.SymbolDisambiguator.html
+// @has - '//a[@href="fn.Name.html"][code]' "Name()"
+// @has - '//a[@href="macro.Name.html"][code]' "Name!"
+pub struct SymbolDisambiguator;
+
+// Now make sure that backticks aren't added if they weren't already there
+/// [fn@Name]
+// @has disambiguators_removed/trait.Name.html
+// @has - '//a[@href="fn.Name.html"]' "Name"
+// @!has - '//a[@href="fn.Name.html"][code]' "Name"
+
+// FIXME: this will turn !() into ! alone
+/// [Name!()]
+// @has - '//a[@href="macro.Name.html"]' "Name!"
+pub trait Name {}
+
+#[allow(non_snake_case)]
+
+// Try collapsed reference links
+/// [macro@Name][]
+// @has disambiguators_removed/fn.Name.html
+// @has - '//a[@href="macro.Name.html"]' "Name"
+
+// Try links that have the same text as a generated URL
+/// Weird URL aligned [macro.Name.html][trait@Name]
+// @has - '//a[@href="trait.Name.html"]' "macro.Name.html"
+pub fn Name() {}
+
+#[macro_export]
+// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks.
+/// [fn@Na`m`e]
+// @has disambiguators_removed/macro.Name.html
+// @has - '//a[@href="fn.Name.html"]' "fn@Name"
+
+// It also doesn't handle any case where the code block isn't the whole link text:
+/// [trait@`Name`]
+// @has - '//a[@href="trait.Name.html"]' "trait@Name"
+macro_rules! Name {
+ () => ()
+}
diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs
new file mode 100644
index 000000000..24161c3bb
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/email-address.rs
@@ -0,0 +1,10 @@
+#![forbid(rustdoc::broken_intra_doc_links)]
+
+//! Email me at <hello@example.com>.
+//! Email me at <hello-world@example.com>.
+//! Email me at <hello@localhost>.
+//! Email me at <prim@i32>.
+// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
+// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32'
diff --git a/src/test/rustdoc/intra-doc/enum-struct-field.rs b/src/test/rustdoc/intra-doc/enum-struct-field.rs
new file mode 100644
index 000000000..2270a1faf
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/enum-struct-field.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+pub enum Foo {
+ X {
+ y: u8,
+ }
+}
+
+/// Hello
+///
+/// I want [Foo::X::y].
+pub fn foo() {}
+
+// @has foo/fn.foo.html '//a/@href' 'enum.Foo.html#variant.X.field.y'
diff --git a/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs
new file mode 100644
index 000000000..7bb1ded3f
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs
@@ -0,0 +1,11 @@
+// Reexport of a structure that derefs to a type with lang item impls having doc links in their
+// comments. The doc link points to an associated item, so we check that traits in scope for that
+// link are populated.
+
+// aux-build:extern-builtin-type-impl-dep.rs
+
+#![no_std]
+
+extern crate extern_builtin_type_impl_dep;
+
+pub use extern_builtin_type_impl_dep::DerefsToF64;
diff --git a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
new file mode 100644
index 000000000..5d8dcf8bc
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
@@ -0,0 +1,19 @@
+// This test is just a little cursed.
+// aux-build:issue-66159-1.rs
+// aux-crate:priv:issue_66159_1=issue-66159-1.rs
+// aux-build:empty.rs
+// aux-crate:priv:empty=empty.rs
+// aux-build:empty2.rs
+// aux-crate:priv:empty2=empty2.rs
+// build-aux-docs
+// compile-flags:-Z unstable-options --edition 2018
+
+// @has extern_crate_only_used_in_link/index.html
+// @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something'
+//! [issue_66159_1::Something]
+
+// @has - '//a[@href="../empty/index.html"]' 'empty'
+//! [`empty`]
+
+// @has - '//a[@href="../empty2/index.html"]' 'empty2'
+//! [empty2<x>]
diff --git a/src/test/rustdoc/intra-doc/extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs
new file mode 100644
index 000000000..4e4438dea
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-crate.rs
@@ -0,0 +1,9 @@
+// aux-build:intra-link-extern-crate.rs
+
+// When loading `extern crate` statements, we would pull in their docs at the same time, even
+// though they would never actually get displayed. This tripped intra-doc-link resolution failures,
+// for items that aren't under our control, and not actually getting documented!
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate inner;
diff --git a/src/test/rustdoc/intra-doc/extern-inherent-impl.rs b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs
new file mode 100644
index 000000000..2e41c2214
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs
@@ -0,0 +1,8 @@
+// Reexport of a structure with public inherent impls having doc links in their comments. The doc
+// link points to an associated item, so we check that traits in scope for that link are populated.
+
+// aux-build:extern-inherent-impl-dep.rs
+
+extern crate extern_inherent_impl_dep;
+
+pub use extern_inherent_impl_dep::PublicStruct;
diff --git a/src/test/rustdoc/intra-doc/extern-reference-link.rs b/src/test/rustdoc/intra-doc/extern-reference-link.rs
new file mode 100644
index 000000000..bad6ec755
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-reference-link.rs
@@ -0,0 +1,7 @@
+// compile-flags: --extern pub_struct
+// aux-build:pub-struct.rs
+
+/// [SomeStruct]
+///
+/// [SomeStruct]: pub_struct::SomeStruct
+pub fn foo() {}
diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs
new file mode 100644
index 000000000..ab088ab78
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-type.rs
@@ -0,0 +1,37 @@
+#![feature(extern_types)]
+
+extern {
+ pub type ExternType;
+}
+
+pub trait T {
+ fn test(&self) {}
+}
+
+pub trait G<N> {
+ fn g(&self, n: N) {}
+}
+
+impl ExternType {
+ pub fn f(&self) {}
+}
+
+impl T for ExternType {
+ fn test(&self) {}
+}
+
+impl G<usize> for ExternType {
+ fn g(&self, n: usize) {}
+}
+
+// @has 'extern_type/foreigntype.ExternType.html'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.f"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.test"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.g"'
+/// See also [ExternType::f]
+/// See also [ExternType::test]
+/// See also [ExternType::g]
+pub fn links_to_extern_type() {}
diff --git a/src/test/rustdoc/intra-doc/external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs
new file mode 100644
index 000000000..a0a66f242
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/external-traits.rs
@@ -0,0 +1,12 @@
+// aux-build:intra-links-external-traits.rs
+// ignore-cross-compile
+
+#![crate_name = "outer"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// using a trait that has intra-doc links on it from another crate (whether re-exporting or just
+// implementing it) used to give spurious resolution failure warnings
+
+extern crate intra_links_external_traits;
+
+pub use intra_links_external_traits::ThisTrait;
diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs
new file mode 100644
index 000000000..001143489
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/field.rs
@@ -0,0 +1,4 @@
+// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
diff --git a/src/test/rustdoc/intra-doc/generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs
new file mode 100644
index 000000000..fbc9fc6a9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/generic-params.rs
@@ -0,0 +1,62 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
+//! Here's a link to [`Iterator<Box<T>>::Item`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+
+//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+
+//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//! And [`Result<T, !>`] and [`Result<!, E>`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
+
+//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
+//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
+//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+
+//! This is also pretty tricky: [`TypeId::of::<String>()`].
+//! And this too: [`Vec::<std::error::Error>::len`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+
+//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
+//! [`Box::<T>new()`]. We may not support them in the future!
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+
+//! These will be resolved as regular links:
+//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
+//! - [`this is <invalid syntax> twice`]
+//! - [`<invalid syntax> thrice`](https://www.rust-lang.org)
+//! - [`<invalid syntax> four times`][rlo]
+//! - [a < b][rlo]
+//! - [c > d]
+//!
+//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org
+//! [rlo]: https://www.rust-lang.org
+//! [c > d]: https://www.rust-lang.org
+//!
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d'
+
+use std::any::TypeId;
diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
new file mode 100644
index 000000000..ba8595abf
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
@@ -0,0 +1,20 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// Test intra-doc links on trait implementations with generics
+// regression test for issue #92662
+
+use std::marker::PhantomData;
+
+pub trait Bar<T> {
+ fn bar(&self);
+}
+
+pub struct Foo<U>(PhantomData<U>);
+
+impl<T, U> Bar<T> for Foo<U> {
+ fn bar(&self) {}
+}
+
+// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar'
+/// link to [`Foo::bar`]
+pub fn main() {}
diff --git a/src/test/rustdoc/intra-doc/in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs
new file mode 100644
index 000000000..55169e5d3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/in-bodies.rs
@@ -0,0 +1,30 @@
+// we need to make sure that intra-doc links on trait impls get resolved in the right scope
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod inner {
+ pub struct SomethingOutOfScope;
+}
+
+pub mod other {
+ use inner::SomethingOutOfScope;
+ use SomeTrait;
+
+ pub struct OtherStruct;
+
+ /// Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for OtherStruct {}
+}
+
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+
+fn __implementation_details() {
+ use inner::SomethingOutOfScope;
+
+ // FIXME: intra-links resolve in their nearest module scope, not their actual scope in cases
+ // like this
+ // Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for SomeStruct {}
+}
diff --git a/src/test/rustdoc/intra-doc/issue-66159.rs b/src/test/rustdoc/intra-doc/issue-66159.rs
new file mode 100644
index 000000000..56742b397
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/issue-66159.rs
@@ -0,0 +1,10 @@
+// aux-crate:priv:pub_struct=pub-struct.rs
+// compile-flags:-Z unstable-options
+
+// The issue was an ICE which meant that we never actually generated the docs
+// so if we have generated the docs, we're okay.
+// Since we don't generate the docs for the auxiliary files, we can't actually
+// verify that the struct is linked correctly.
+
+// @has issue_66159/index.html
+//! [pub_struct::SomeStruct]
diff --git a/src/test/rustdoc/intra-doc/issue-82209.rs b/src/test/rustdoc/intra-doc/issue-82209.rs
new file mode 100644
index 000000000..a5fe855cb
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/issue-82209.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+#![deny(rustdoc::broken_intra_doc_links)]
+pub enum Foo {
+ Bar {
+ abc: i32,
+ /// [Self::Bar::abc]
+ xyz: i32,
+ },
+}
+
+// @has foo/enum.Foo.html '//a/@href' 'enum.Foo.html#variant.Bar.field.abc'
diff --git a/src/test/rustdoc/intra-doc/libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs
new file mode 100644
index 000000000..6c41eb2b5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
+
+pub use std::*;
diff --git a/src/test/rustdoc/intra-doc/macros-disambiguators.rs b/src/test/rustdoc/intra-doc/macros-disambiguators.rs
new file mode 100644
index 000000000..cd4caa6a8
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/macros-disambiguators.rs
@@ -0,0 +1,25 @@
+#![crate_name = "foo"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! [foo!()]
+// @has foo/index.html '//a[@href="macro.foo.html"]' 'foo!()'
+
+//! [foo!{}]
+// @has - '//a[@href="macro.foo.html"]' 'foo!{}'
+
+//! [foo![]](foo![])
+// @has - '//a[@href="macro.foo.html"]' 'foo![]'
+
+//! [foo1](foo!())
+// @has - '//a[@href="macro.foo.html"]' 'foo1'
+
+//! [foo2](foo!{})
+// @has - '//a[@href="macro.foo.html"]' 'foo2'
+
+//! [foo3](foo![])
+// @has - '//a[@href="macro.foo.html"]' 'foo3'
+
+#[macro_export]
+macro_rules! foo {
+ () => {};
+}
diff --git a/src/test/rustdoc/intra-doc/mod-ambiguity.rs b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
new file mode 100644
index 000000000..0c7acbaf0
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
@@ -0,0 +1,16 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+
+pub fn foo() {
+
+}
+
+pub mod foo {}
+// @has mod_ambiguity/struct.A.html '//a/@href' 'foo/index.html'
+/// Module is [`module@foo`]
+pub struct A;
+
+
+// @has mod_ambiguity/struct.B.html '//a/@href' 'fn.foo.html'
+/// Function is [`fn@foo`]
+pub struct B;
diff --git a/src/test/rustdoc/intra-doc/mod-relative.rs b/src/test/rustdoc/intra-doc/mod-relative.rs
new file mode 100644
index 000000000..49d3399b9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-relative.rs
@@ -0,0 +1,17 @@
+pub mod wrapper {
+
+ pub struct Test<'a> {
+ data: &'a (),
+ }
+
+ impl<'a> Test<'a> {
+ pub fn do_test(&self) {}
+ }
+
+ // @has mod_relative/wrapper/demo/index.html
+ // @has - '//a/@href' '../struct.Test.html#method.do_test'
+ /// [`Test::do_test`]
+ pub mod demo {
+ }
+
+}
diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs
new file mode 100644
index 000000000..be4b44b31
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs
@@ -0,0 +1,46 @@
+#![crate_name = "foo"]
+#![feature(intra_doc_pointers)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+//! [slice::rotate_left]
+
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
+//! [array::map]
+
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
+//! [owned str][str]
+//! [str ref][&str]
+//! [str::is_empty]
+//! [&str::len]
+
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+//! [pointer::is_null]
+//! [*const::is_null]
+//! [*mut::is_null]
+
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
+//! [unit]
+
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
+//! [tuple]
+
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
+//! [reference]
+//! [&]
+//! [&mut]
+
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
+//! [fn]
+
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
+//! [never]
+//! [!]
diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs
new file mode 100644
index 000000000..dfa7db8a5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-assoc.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! [i32::MAX]
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
new file mode 100644
index 000000000..8639a24f7
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+use std::str::FromStr;
+
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
+/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
+/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
+/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
+/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
+/// [`str::eq()`] [`never::eq()`]
+pub struct Number {
+ pub f_64: f64,
+ pub f_32: f32,
+ pub i_size: isize,
+ pub i_8: i8,
+ pub i_16: i16,
+ pub i_32: i32,
+ pub i_64: i64,
+ pub i_128: i128,
+ pub u_size: usize,
+ pub u_8: u8,
+ pub u_16: u16,
+ pub u_32: u32,
+ pub u_64: u64,
+ pub u_128: u128,
+ pub ch: char,
+ pub boolean: bool,
+ pub string: str,
+ pub n: !,
+}
diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
new file mode 100644
index 000000000..c3340af33
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
@@ -0,0 +1,17 @@
+// aux-build:my-core.rs
+// build-aux-docs
+// ignore-cross-compile
+// only-linux
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![crate_type = "rlib"]
+
+// @has prim_methods_external_core/index.html
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [`char`] and its [`char::len_utf8`].
+
+extern crate my_core;
diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs
new file mode 100644
index 000000000..79d8df045
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs
@@ -0,0 +1,29 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items, rustc_attrs, rustdoc_internals)]
+#![no_core]
+#![rustc_coherence_is_core]
+#![crate_type = "rlib"]
+
+// @has prim_methods_local/index.html
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [prim@`char`] and its [`char::len_utf8`].
+
+#[doc(primitive = "char")]
+mod char {}
+
+impl char {
+ pub fn len_utf8(self) -> usize {
+ 42
+ }
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {}
+
+#[lang = "copy"]
+pub trait Copy: Clone {}
diff --git a/src/test/rustdoc/intra-doc/prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs
new file mode 100644
index 000000000..a412a23fd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods.rs
@@ -0,0 +1,7 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// @has prim_methods/index.html
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [`char`] and its [`char::len_utf8`].
diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs
new file mode 100644
index 000000000..25625b952
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-precedence.rs
@@ -0,0 +1,16 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod char {
+ /// [char]
+ // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
+ pub struct Inner;
+}
+
+/// See [prim@char]
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
+pub struct MyString;
+
+/// See also [crate::char] and [mod@char]
+// @has prim_precedence/struct.MyString2.html '//*[@href="char/index.html"]' 'crate::char'
+// @has - '//*[@href="char/index.html"]' 'mod@char'
+pub struct MyString2;
diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs
new file mode 100644
index 000000000..c7ce71b15
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-self.rs
@@ -0,0 +1,41 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![rustc_coherence_is_core]
+#![allow(incomplete_features)] // inherent_associated_types
+#![feature(rustc_attrs)]
+#![feature(no_core)]
+#![feature(rustdoc_internals)]
+#![feature(inherent_associated_types)]
+#![feature(lang_items)]
+#![no_core]
+
+/// [Self::f]
+/// [Self::MAX]
+// @has prim_self/primitive.usize.html
+// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+impl usize {
+ /// Some docs
+ pub fn f() {}
+
+ /// 10 and 2^32 are basically the same.
+ pub const MAX: usize = 10;
+
+ // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+ /// [Self::ME]
+ pub type ME = usize;
+}
+
+#[doc(primitive = "usize")]
+/// This has some docs.
+mod usize {}
+
+/// [S::f]
+/// [Self::f]
+pub struct S;
+
+impl S {
+ pub fn f() {}
+}
+
+#[lang = "sized"]
+pub trait Sized {}
diff --git a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
new file mode 100644
index 000000000..adcab767d
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+// @has primitive_disambiguators/index.html
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
+//! [str::trim()]
diff --git a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
new file mode 100644
index 000000000..474bf3477
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
@@ -0,0 +1,31 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+
+// @has primitive_non_default_impl/fn.str_methods.html
+/// [`str::trim`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
+/// [`str::to_lowercase`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+/// [`str::into_boxed_bytes`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+/// [`str::replace`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
+pub fn str_methods() {}
+
+// @has primitive_non_default_impl/fn.f32_methods.html
+/// [f32::powi]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
+/// [f32::sqrt]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+/// [f32::mul_add]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+pub fn f32_methods() {}
+
+// @has primitive_non_default_impl/fn.f64_methods.html
+/// [`f64::powi`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
+/// [`f64::sqrt`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+/// [`f64::mul_add`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+pub fn f64_methods() {}
diff --git a/src/test/rustdoc/intra-doc/private-failures-ignored.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
new file mode 100644
index 000000000..b272bfb5a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
@@ -0,0 +1,8 @@
+// Rustdoc would previously report resolution failures on items that weren't in the public docs.
+// These failures were legitimate, but not truly relevant - the docs in question couldn't be
+// checked for accuracy anyway.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// ooh, i'm a [rebel] just for kicks
+struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/private.rs b/src/test/rustdoc/intra-doc/private.rs
new file mode 100644
index 000000000..349091e93
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/private.rs
@@ -0,0 +1,20 @@
+// compile-flags: --document-private-items
+
+// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
+
+#![allow(rustdoc::private_intra_doc_links)]
+
+#![crate_name = "private"]
+
+/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe'
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x'
+pub struct DocMe;
+struct DontDocMe {
+ x: usize,
+}
+
+impl DontDocMe {
+ fn f() {}
+}
diff --git a/src/test/rustdoc/intra-doc/proc-macro.rs b/src/test/rustdoc/intra-doc/proc-macro.rs
new file mode 100644
index 000000000..78379a902
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/proc-macro.rs
@@ -0,0 +1,27 @@
+// aux-build:proc-macro-macro.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate proc_macro_macro;
+
+
+pub use proc_macro_macro::{DeriveA, attr_a};
+use proc_macro_macro::{DeriveB, attr_b};
+
+// @has proc_macro/struct.Foo.html
+// @has - '//a/@href' 'derive.DeriveA.html'
+// @has - '//a/@href' 'attr.attr_a.html'
+// @has - '//a/@href' 'trait.DeriveTrait.html'
+// @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html'
+// @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html'
+/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
+pub struct Foo;
+
+// @has proc_macro/struct.Bar.html
+// @has - '//a/@href' 'derive.DeriveA.html'
+// @has - '//a/@href' 'attr.attr_a.html'
+/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a)
+pub struct Bar;
+
+// this should not cause ambiguity errors
+pub trait DeriveTrait {}
diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs
new file mode 100644
index 000000000..8a998496c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
@@ -0,0 +1,17 @@
+// aux-build: intra-link-pub-use.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "outer"]
+
+extern crate inner;
+
+/// [mod@std::env] [g]
+// @has outer/index.html
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
+// @has - '//a[@href="fn.f.html"]' "g"
+pub use f as g;
+
+// Make sure the documentation is actually correct by documenting an inlined re-export
+/// [mod@std::env]
+// @has outer/fn.f.html
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
+pub use inner::f;
diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs
new file mode 100644
index 000000000..1ed33db93
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs
@@ -0,0 +1,13 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+pub mod r#impl {
+ pub struct S;
+
+ impl S {
+ /// See [Self::b].
+ // @has raw_ident_self/impl/struct.S.html
+ // @has - '//a[@href="struct.S.html#method.b"]' 'Self::b'
+ pub fn a() {}
+
+ pub fn b() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
new file mode 100644
index 000000000..64683bacd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
@@ -0,0 +1,23 @@
+// aux-build:intra-link-reexport-additional-docs.rs
+// build-aux-docs
+#![crate_name = "foo"]
+extern crate inner;
+
+// @has foo/struct.Inner.html '//a[@href="fn.with_code.html"]' 'crate::with_code'
+/// [crate::with_code]
+// @has - '//a[@href="fn.with_code.html"]' 'different text'
+/// [different text][with_code]
+// @has - '//a[@href="fn.me_too.html"]' 'me_too'
+#[doc = "[me_too]"]
+// @has - '//a[@href="fn.me_three.html"]' 'reference link'
+/// This [reference link]
+#[doc = "has an attr in the way"]
+///
+/// [reference link]: me_three
+// Should still resolve links from the original module in that scope
+// @has - '//a[@href="../inner/fn.f.html"]' 'f()'
+pub use inner::Inner;
+
+pub fn with_code() {}
+pub fn me_too() {}
+pub fn me_three() {}
diff --git a/src/test/rustdoc/intra-doc/self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs
new file mode 100644
index 000000000..63bf7fa57
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/self-cache.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+// @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A'
+
+/// [Self::A::b]
+pub enum E1 {
+ A { b: usize }
+}
+
+// @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A'
+
+/// [Self::A::b]
+pub enum E2 {
+ A { b: usize }
+}
diff --git a/src/test/rustdoc/intra-doc/self.rs b/src/test/rustdoc/intra-doc/self.rs
new file mode 100644
index 000000000..0ba7df8a7
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/self.rs
@@ -0,0 +1,116 @@
+#![crate_name = "foo"]
+
+
+// @has foo/index.html '//a/@href' 'struct.Foo.html#method.new'
+// @has foo/struct.Foo.html '//a/@href' 'struct.Foo.html#method.new'
+
+/// Use [`new`] to create a new instance.
+///
+/// [`new`]: Self::new
+pub struct Foo;
+
+impl Foo {
+ pub fn new() -> Self {
+ unimplemented!()
+ }
+}
+
+// @has foo/index.html '//a/@href' 'struct.Bar.html#method.new2'
+// @has foo/struct.Bar.html '//a/@href' 'struct.Bar.html#method.new2'
+
+/// Use [`new2`] to create a new instance.
+///
+/// [`new2`]: Self::new2
+pub struct Bar;
+
+impl Bar {
+ pub fn new2() -> Self {
+ unimplemented!()
+ }
+}
+
+pub struct MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#structfield.struct_field'
+
+ /// [`struct_field`]
+ ///
+ /// [`struct_field`]: Self::struct_field
+ pub struct_field: u8,
+}
+
+pub enum MyEnum {
+ // @has foo/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.EnumVariant'
+
+ /// [`EnumVariant`]
+ ///
+ /// [`EnumVariant`]: Self::EnumVariant
+ EnumVariant,
+}
+
+pub union MyUnion {
+ // @has foo/union.MyUnion.html '//a/@href' 'union.MyUnion.html#structfield.union_field'
+
+ /// [`union_field`]
+ ///
+ /// [`union_field`]: Self::union_field
+ pub union_field: f32,
+}
+
+pub trait MyTrait {
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: Self::AssoType
+ type AssoType;
+
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: Self::ASSO_CONST
+ const ASSO_CONST: i32 = 1;
+
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#method.asso_fn'
+
+ /// [`asso_fn`]
+ ///
+ /// [`asso_fn`]: Self::asso_fn
+ fn asso_fn() {}
+}
+
+impl MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.for_impl'
+
+ /// [`for_impl`]
+ ///
+ /// [`for_impl`]: Self::for_impl
+ pub fn for_impl() {
+ unimplemented!()
+ }
+}
+
+impl MyTrait for MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: Self::AssoType
+ type AssoType = u32;
+
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: Self::ASSO_CONST
+ const ASSO_CONST: i32 = 10;
+
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.asso_fn'
+
+ /// [`asso_fn`]
+ ///
+ /// [`asso_fn`]: Self::asso_fn
+ fn asso_fn() {
+ unimplemented!()
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/trait-impl.rs b/src/test/rustdoc/intra-doc/trait-impl.rs
new file mode 100644
index 000000000..cf60dc1db
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-impl.rs
@@ -0,0 +1,34 @@
+#![crate_name = "foo"]
+
+
+pub struct MyStruct;
+
+impl MyTrait for MyStruct {
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: MyStruct::AssoType
+ type AssoType = u32;
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: MyStruct::ASSO_CONST
+ const ASSO_CONST: i32 = 10;
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.trait_fn'
+
+ /// [`trait_fn`]
+ ///
+ /// [`trait_fn`]: MyStruct::trait_fn
+ fn trait_fn() { }
+}
+
+pub trait MyTrait {
+ type AssoType;
+ const ASSO_CONST: i32 = 1;
+ fn trait_fn();
+}
diff --git a/src/test/rustdoc/intra-doc/trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs
new file mode 100644
index 000000000..e95dba33b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-item.rs
@@ -0,0 +1,11 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// Link to [S::assoc_fn()]
+/// Link to [Default::default()]
+// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+pub struct S;
+
+impl S {
+ pub fn assoc_fn() {}
+}
diff --git a/src/test/rustdoc/intra-doc/true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs
new file mode 100644
index 000000000..e02be9cab
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/true-false.rs
@@ -0,0 +1,8 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+// @has foo/index.html
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
+
+//! A `bool` is either [`true`] or [`false`].
diff --git a/src/test/rustdoc/intra-doc/type-alias.rs b/src/test/rustdoc/intra-doc/type-alias.rs
new file mode 100644
index 000000000..6c52082a2
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/type-alias.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #86120.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+/// You should really try [`Self::bar`]!
+pub type Bar = Foo;
+
+impl Bar {
+ pub fn bar() {}
+}
+
+/// The minimum is [`Self::MIN`].
+pub type Int = i32;
+
+// @has foo/type.Bar.html '//a[@href="struct.Foo.html#method.bar"]' 'Self::bar'
+// @has foo/type.Int.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MIN"]' 'Self::MIN'
diff --git a/src/test/rustdoc/invalid.crate.name.rs b/src/test/rustdoc/invalid.crate.name.rs
new file mode 100644
index 000000000..c19713b56
--- /dev/null
+++ b/src/test/rustdoc/invalid.crate.name.rs
@@ -0,0 +1,3 @@
+// compile-flags: --crate-name foo
+
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs
new file mode 100644
index 000000000..3e20c5c07
--- /dev/null
+++ b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs
@@ -0,0 +1,14 @@
+// aux-build:issue-100204-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name="second"]
+
+extern crate first;
+
+pub mod prelude {}
+
+// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+#[doc(inline)]
+pub use first::*;
diff --git a/src/test/rustdoc/issue-12834.rs b/src/test/rustdoc/issue-12834.rs
new file mode 100644
index 000000000..9605a1e78
--- /dev/null
+++ b/src/test/rustdoc/issue-12834.rs
@@ -0,0 +1,12 @@
+// Tests that failing to syntax highlight a rust code-block doesn't cause
+// rustdoc to fail, while still rendering the code-block (without highlighting).
+
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
+// @has issue_12834/fn.foo.html
+// @has - //pre 'a + b '
+
+/// ```
+/// a + b ∈ Self ∀ a, b ∈ Self
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-13698.rs b/src/test/rustdoc/issue-13698.rs
new file mode 100644
index 000000000..3046a8a28
--- /dev/null
+++ b/src/test/rustdoc/issue-13698.rs
@@ -0,0 +1,16 @@
+// aux-build:issue-13698.rs
+// ignore-cross-compile
+
+extern crate issue_13698;
+
+pub struct Foo;
+// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn foo'
+impl issue_13698::Foo for Foo {}
+
+pub trait Bar {
+ #[doc(hidden)]
+ fn bar(&self) {}
+}
+
+// @!has issue_13698/struct.Foo.html '//*[@id="method.bar"]' 'fn bar'
+impl Bar for Foo {}
diff --git a/src/test/rustdoc/issue-15169.rs b/src/test/rustdoc/issue-15169.rs
new file mode 100644
index 000000000..e525d85e2
--- /dev/null
+++ b/src/test/rustdoc/issue-15169.rs
@@ -0,0 +1,3 @@
+// @has issue_15169/struct.Foo.html '//*[@id="method.eq"]' 'fn eq'
+#[derive(PartialEq)]
+pub struct Foo;
diff --git a/src/test/rustdoc/issue-15318-2.rs b/src/test/rustdoc/issue-15318-2.rs
new file mode 100644
index 000000000..f7f5052a3
--- /dev/null
+++ b/src/test/rustdoc/issue-15318-2.rs
@@ -0,0 +1,12 @@
+// aux-build:issue-15318.rs
+// ignore-cross-compile
+#![no_std]
+
+extern crate issue_15318;
+
+pub use issue_15318::ptr;
+
+// @has issue_15318_2/fn.bar.html \
+// '//*[@href="primitive.pointer.html"]' \
+// '*mut T'
+pub fn bar<T>(ptr: *mut T) {}
diff --git a/src/test/rustdoc/issue-15318-3.rs b/src/test/rustdoc/issue-15318-3.rs
new file mode 100644
index 000000000..2fadc26b0
--- /dev/null
+++ b/src/test/rustdoc/issue-15318-3.rs
@@ -0,0 +1,7 @@
+#![feature(rustdoc_internals)]
+
+// @has issue_15318_3/primitive.pointer.html
+
+/// dox
+#[doc(primitive = "pointer")]
+pub mod ptr {}
diff --git a/src/test/rustdoc/issue-15318.rs b/src/test/rustdoc/issue-15318.rs
new file mode 100644
index 000000000..0349fe285
--- /dev/null
+++ b/src/test/rustdoc/issue-15318.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-15318.rs
+// ignore-cross-compile
+
+#![no_std]
+
+extern crate issue_15318;
+
+// @has issue_15318/fn.bar.html \
+// '//*[@href="http://example.com/issue_15318/primitive.pointer.html"]' \
+// '*mut T'
+pub fn bar<T>(ptr: *mut T) {}
diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs
new file mode 100644
index 000000000..e93d74011
--- /dev/null
+++ b/src/test/rustdoc/issue-15347.rs
@@ -0,0 +1,5 @@
+// compile-flags: -Z unstable-options --document-hidden-items
+
+// @has issue_15347/fn.foo.html
+#[doc(hidden)]
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-16019.rs b/src/test/rustdoc/issue-16019.rs
new file mode 100644
index 000000000..239d92378
--- /dev/null
+++ b/src/test/rustdoc/issue-16019.rs
@@ -0,0 +1,9 @@
+macro_rules! define_struct {
+ ($rounds:expr) => (
+ struct Struct {
+ sk: [u32; $rounds + 1]
+ }
+ )
+}
+
+define_struct!(2);
diff --git a/src/test/rustdoc/issue-16265-1.rs b/src/test/rustdoc/issue-16265-1.rs
new file mode 100644
index 000000000..ec007e36b
--- /dev/null
+++ b/src/test/rustdoc/issue-16265-1.rs
@@ -0,0 +1,10 @@
+pub struct Foo;
+
+// @has issue_16265_1/traits/index.html 'source'
+pub mod traits {
+ impl PartialEq for super::Foo {
+ fn eq(&self, _: &super::Foo) -> bool {
+ true
+ }
+ }
+}
diff --git a/src/test/rustdoc/issue-16265-2.rs b/src/test/rustdoc/issue-16265-2.rs
new file mode 100644
index 000000000..d5cd18d9d
--- /dev/null
+++ b/src/test/rustdoc/issue-16265-2.rs
@@ -0,0 +1,4 @@
+// @has issue_16265_2/index.html 'source'
+
+trait Y {}
+impl Y for Option<u32> {}
diff --git a/src/test/rustdoc/issue-17476.rs b/src/test/rustdoc/issue-17476.rs
new file mode 100644
index 000000000..a5b484c98
--- /dev/null
+++ b/src/test/rustdoc/issue-17476.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-17476.rs
+// ignore-cross-compile
+
+extern crate issue_17476;
+
+pub struct Foo;
+
+// @has issue_17476/struct.Foo.html \
+// '//*[@href="http://example.com/issue_17476/trait.Foo.html#method.foo"]' \
+// 'foo'
+impl issue_17476::Foo for Foo {}
diff --git a/src/test/rustdoc/issue-18199.rs b/src/test/rustdoc/issue-18199.rs
new file mode 100644
index 000000000..bc0c4a565
--- /dev/null
+++ b/src/test/rustdoc/issue-18199.rs
@@ -0,0 +1,9 @@
+// compile-flags:--test
+
+#![doc(test(attr(feature(staged_api))))]
+
+/// ```
+/// #![unstable(feature="test", issue="18199")]
+/// fn main() {}
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-19181.rs b/src/test/rustdoc/issue-19181.rs
new file mode 100644
index 000000000..3dea152fc
--- /dev/null
+++ b/src/test/rustdoc/issue-19181.rs
@@ -0,0 +1,5 @@
+// compile-flags:--test
+
+// rustdoc should not panic when target crate has compilation errors
+
+fn main() { 0 }
diff --git a/src/test/rustdoc/issue-19190-2.rs b/src/test/rustdoc/issue-19190-2.rs
new file mode 100644
index 000000000..b6416e2e5
--- /dev/null
+++ b/src/test/rustdoc/issue-19190-2.rs
@@ -0,0 +1,12 @@
+use std::ops::Deref;
+
+pub struct Bar;
+
+impl Deref for Bar {
+ type Target = String;
+ fn deref(&self) -> &String { loop {} }
+}
+
+// @has issue_19190_2/struct.Bar.html
+// @!has - '//*[@id="method.new"]' 'fn new() -> String'
+// @has - '//*[@id="method.as_str"]' 'fn as_str(&self) -> &str'
diff --git a/src/test/rustdoc/issue-19190-3.rs b/src/test/rustdoc/issue-19190-3.rs
new file mode 100644
index 000000000..4d34ce650
--- /dev/null
+++ b/src/test/rustdoc/issue-19190-3.rs
@@ -0,0 +1,27 @@
+// aux-build:issue-19190-3.rs
+// ignore-cross-compile
+
+extern crate issue_19190_3;
+
+use std::ops::Deref;
+use issue_19190_3::Baz;
+
+// @has issue_19190_3/struct.Foo.html
+// @has - '//*[@id="method.as_str"]' 'fn as_str(&self) -> &str'
+// @!has - '//*[@id="method.new"]' 'fn new() -> String'
+pub use issue_19190_3::Foo;
+
+// @has issue_19190_3/struct.Bar.html
+// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
+// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()'
+pub use issue_19190_3::Bar;
+
+// @has issue_19190_3/struct.MyBar.html
+// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
+// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()'
+pub struct MyBar;
+
+impl Deref for MyBar {
+ type Target = Baz;
+ fn deref(&self) -> &Baz { loop {} }
+}
diff --git a/src/test/rustdoc/issue-19190.rs b/src/test/rustdoc/issue-19190.rs
new file mode 100644
index 000000000..2046273e2
--- /dev/null
+++ b/src/test/rustdoc/issue-19190.rs
@@ -0,0 +1,20 @@
+use std::ops::Deref;
+
+pub struct Foo;
+pub struct Bar;
+
+impl Foo {
+ pub fn foo(&self) {}
+ pub fn static_foo() {}
+}
+
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Foo { loop {} }
+}
+
+// @has issue_19190/struct.Bar.html
+// @has - '//*[@id="method.foo"]//h4[@class="code-header"]' 'fn foo(&self)'
+// @has - '//*[@id="method.foo"]' 'fn foo(&self)'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
diff --git a/src/test/rustdoc/issue-20175.rs b/src/test/rustdoc/issue-20175.rs
new file mode 100644
index 000000000..6a42e2afb
--- /dev/null
+++ b/src/test/rustdoc/issue-20175.rs
@@ -0,0 +1,10 @@
+pub trait Foo {
+ fn foo(&self) {}
+}
+
+pub struct Bar;
+
+// @has issue_20175/struct.Bar.html \
+// '//*[@id="method.foo"]' \
+// 'fn foo'
+impl<'a> Foo for &'a Bar {}
diff --git a/src/test/rustdoc/issue-20646.rs b/src/test/rustdoc/issue-20646.rs
new file mode 100644
index 000000000..2589e27f2
--- /dev/null
+++ b/src/test/rustdoc/issue-20646.rs
@@ -0,0 +1,26 @@
+// aux-build:issue-20646.rs
+// ignore-cross-compile
+
+#![feature(associated_types)]
+
+extern crate issue_20646;
+
+// @has issue_20646/trait.Trait.html \
+// '//*[@id="associatedtype.Output"]' \
+// 'type Output'
+pub trait Trait {
+ type Output;
+}
+
+// @has issue_20646/fn.fun.html \
+// '//*[@class="rust fn"]' 'where T: Trait<Output = i32>'
+pub fn fun<T>(_: T) where T: Trait<Output=i32> {}
+
+pub mod reexport {
+ // @has issue_20646/reexport/trait.Trait.html \
+ // '//*[@id="associatedtype.Output"]' \
+ // 'type Output'
+ // @has issue_20646/reexport/fn.fun.html \
+ // '//*[@class="rust fn"]' 'where T: Trait<Output = i32>'
+ pub use issue_20646::{Trait, fun};
+}
diff --git a/src/test/rustdoc/issue-20727-2.rs b/src/test/rustdoc/issue-20727-2.rs
new file mode 100644
index 000000000..022ff290e
--- /dev/null
+++ b/src/test/rustdoc/issue-20727-2.rs
@@ -0,0 +1,22 @@
+// aux-build:issue-20727.rs
+// ignore-cross-compile
+
+extern crate issue_20727;
+
+// @has issue_20727_2/trait.Add.html
+pub trait Add<RHS = Self> {
+ // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {'
+ // @has - '//*[@class="rust trait"]' 'type Output;'
+ type Output;
+
+ // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+// @has issue_20727_2/reexport/trait.Add.html
+pub mod reexport {
+ // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {'
+ // @has - '//*[@class="rust trait"]' 'type Output;'
+ // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+ pub use issue_20727::Add;
+}
diff --git a/src/test/rustdoc/issue-20727-3.rs b/src/test/rustdoc/issue-20727-3.rs
new file mode 100644
index 000000000..52032b75a
--- /dev/null
+++ b/src/test/rustdoc/issue-20727-3.rs
@@ -0,0 +1,24 @@
+// aux-build:issue-20727.rs
+// ignore-cross-compile
+
+extern crate issue_20727;
+
+pub trait Bar {}
+
+// @has issue_20727_3/trait.Deref2.html
+pub trait Deref2 {
+ // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
+ // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
+ type Target: Bar;
+
+ // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+ fn deref(&self) -> Self::Target;
+}
+
+// @has issue_20727_3/reexport/trait.Deref2.html
+pub mod reexport {
+ // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
+ // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
+ // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+ pub use issue_20727::Deref2;
+}
diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs
new file mode 100644
index 000000000..84fc6f94a
--- /dev/null
+++ b/src/test/rustdoc/issue-20727-4.rs
@@ -0,0 +1,40 @@
+// aux-build:issue-20727.rs
+// ignore-cross-compile
+
+extern crate issue_20727;
+
+// @has issue_20727_4/trait.Index.html
+pub trait Index<Idx: ?Sized> {
+ // @has - '//*[@class="rust trait"]' 'trait Index<Idx: ?Sized> {'
+ // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
+ type Output: ?Sized;
+
+ // @has - '//*[@class="rust trait"]' \
+ // 'fn index(&self, index: Idx) -> &Self::Output'
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+// @has issue_20727_4/trait.IndexMut.html
+pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
+ // @has - '//*[@class="rust trait"]' \
+ // 'trait IndexMut<Idx: ?Sized>: Index<Idx> {'
+ // @has - '//*[@class="rust trait"]' \
+ // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
+ fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
+}
+
+pub mod reexport {
+ // @has issue_20727_4/reexport/trait.Index.html
+ // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {'
+ // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
+ // @has - '//*[@class="rust trait"]' \
+ // 'fn index(&self, index: Idx) -> &Self::Output'
+ pub use issue_20727::Index;
+
+ // @has issue_20727_4/reexport/trait.IndexMut.html
+ // @has - '//*[@class="rust trait"]' \
+ // 'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {'
+ // @has - '//*[@class="rust trait"]' \
+ // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
+ pub use issue_20727::IndexMut;
+}
diff --git a/src/test/rustdoc/issue-20727.rs b/src/test/rustdoc/issue-20727.rs
new file mode 100644
index 000000000..f7acffcb4
--- /dev/null
+++ b/src/test/rustdoc/issue-20727.rs
@@ -0,0 +1,24 @@
+// aux-build:issue-20727.rs
+// ignore-cross-compile
+
+extern crate issue_20727;
+
+// @has issue_20727/trait.Deref.html
+pub trait Deref {
+ // @has - '//*[@class="rust trait"]' 'trait Deref {'
+ // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
+ type Target: ?Sized;
+
+ // @has - '//*[@class="rust trait"]' \
+ // "fn deref<'a>(&'a self) -> &'a Self::Target;"
+ fn deref<'a>(&'a self) -> &'a Self::Target;
+}
+
+// @has issue_20727/reexport/trait.Deref.html
+pub mod reexport {
+ // @has - '//*[@class="rust trait"]' 'trait Deref {'
+ // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
+ // @has - '//*[@class="rust trait"]' \
+ // "fn deref(&'a self) -> &'a Self::Target;"
+ pub use issue_20727::Deref;
+}
diff --git a/src/test/rustdoc/issue-21092.rs b/src/test/rustdoc/issue-21092.rs
new file mode 100644
index 000000000..b054145a4
--- /dev/null
+++ b/src/test/rustdoc/issue-21092.rs
@@ -0,0 +1,8 @@
+// aux-build:issue-21092.rs
+// ignore-cross-compile
+
+extern crate issue_21092;
+
+// @has issue_21092/struct.Bar.html
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar = i32'
+pub use issue_21092::{Foo, Bar};
diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs
new file mode 100644
index 000000000..43ce13fd9
--- /dev/null
+++ b/src/test/rustdoc/issue-21474.rs
@@ -0,0 +1,11 @@
+pub use inner::*;
+
+mod inner {
+ impl super::Blah for super::What { }
+}
+
+pub trait Blah { }
+
+// @count issue_21474/struct.What.html \
+// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+pub struct What;
diff --git a/src/test/rustdoc/issue-21801.rs b/src/test/rustdoc/issue-21801.rs
new file mode 100644
index 000000000..2a586b6ff
--- /dev/null
+++ b/src/test/rustdoc/issue-21801.rs
@@ -0,0 +1,9 @@
+// aux-build:issue-21801.rs
+// ignore-cross-compile
+
+extern crate issue_21801;
+
+// @has issue_21801/struct.Foo.html
+// @has - '//*[@id="method.new"]' \
+// 'fn new<F>(f: F) -> Foo where F: FnMut() -> i32'
+pub use issue_21801::Foo;
diff --git a/src/test/rustdoc/issue-22025.rs b/src/test/rustdoc/issue-22025.rs
new file mode 100644
index 000000000..a721a15f4
--- /dev/null
+++ b/src/test/rustdoc/issue-22025.rs
@@ -0,0 +1,6 @@
+// aux-build:issue-22025.rs
+// ignore-cross-compile
+
+extern crate issue_22025;
+
+pub use issue_22025::foo::{Foo, Bar};
diff --git a/src/test/rustdoc/issue-22038.rs b/src/test/rustdoc/issue-22038.rs
new file mode 100644
index 000000000..ff5813dac
--- /dev/null
+++ b/src/test/rustdoc/issue-22038.rs
@@ -0,0 +1,19 @@
+extern "C" {
+ // @has issue_22038/fn.foo1.html \
+ // '//*[@class="rust fn"]' 'pub unsafe extern "C" fn foo1()'
+ pub fn foo1();
+}
+
+extern "system" {
+ // @has issue_22038/fn.foo2.html \
+ // '//*[@class="rust fn"]' 'pub unsafe extern "system" fn foo2()'
+ pub fn foo2();
+}
+
+// @has issue_22038/fn.bar.html \
+// '//*[@class="rust fn"]' 'pub extern "C" fn bar()'
+pub extern "C" fn bar() {}
+
+// @has issue_22038/fn.baz.html \
+// '//*[@class="rust fn"]' 'pub extern "system" fn baz()'
+pub extern "system" fn baz() {}
diff --git a/src/test/rustdoc/issue-23106.rs b/src/test/rustdoc/issue-23106.rs
new file mode 100644
index 000000000..8cda2fc33
--- /dev/null
+++ b/src/test/rustdoc/issue-23106.rs
@@ -0,0 +1,7 @@
+// compile-flags:--test
+
+/// ```
+/// #
+/// ```
+pub fn main() {
+}
diff --git a/src/test/rustdoc/issue-23207.rs b/src/test/rustdoc/issue-23207.rs
new file mode 100644
index 000000000..1a4b849ee
--- /dev/null
+++ b/src/test/rustdoc/issue-23207.rs
@@ -0,0 +1,9 @@
+// aux-build:issue-23207-1.rs
+// aux-build:issue-23207-2.rs
+// ignore-cross-compile
+
+extern crate issue_23207_2;
+
+// @has issue_23207/fmt/index.html
+// @count - '//*[@class="struct"]' 1
+pub use issue_23207_2::fmt;
diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs
new file mode 100644
index 000000000..2d2a7908f
--- /dev/null
+++ b/src/test/rustdoc/issue-23511.rs
@@ -0,0 +1,13 @@
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![no_std]
+
+pub mod str {
+ #![doc(primitive = "str")]
+
+ impl str {
+ // @has search-index.js foo
+ #[rustc_allow_incoherent_impl]
+ pub fn foo(&self) {}
+ }
+}
diff --git a/src/test/rustdoc/issue-23744.rs b/src/test/rustdoc/issue-23744.rs
new file mode 100644
index 000000000..642817396
--- /dev/null
+++ b/src/test/rustdoc/issue-23744.rs
@@ -0,0 +1,12 @@
+// compile-flags:--test
+
+/// Example of rustdoc incorrectly parsing <code>```rust,should_panic</code>.
+///
+/// ```should_panic
+/// fn main() { panic!("fee"); }
+/// ```
+///
+/// ```rust,should_panic
+/// fn main() { panic!("fum"); }
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-23812.rs b/src/test/rustdoc/issue-23812.rs
new file mode 100644
index 000000000..5dac8d87b
--- /dev/null
+++ b/src/test/rustdoc/issue-23812.rs
@@ -0,0 +1,36 @@
+macro_rules! doc {
+ (#[$outer:meta] mod $i:ident { #![$inner:meta] }) =>
+ (
+ #[$outer]
+ pub mod $i {
+ #![$inner]
+ }
+ )
+}
+
+doc! {
+ /// Outer comment
+ mod Foo {
+ //! Inner comment
+ }
+}
+
+// @has issue_23812/Foo/index.html
+// @has - 'Outer comment'
+// @!has - '/// Outer comment'
+// @has - 'Inner comment'
+// @!has - '//! Inner comment'
+
+
+doc! {
+ /** Outer block comment */
+ mod Bar {
+ /*! Inner block comment */
+ }
+}
+
+// @has issue_23812/Bar/index.html
+// @has - 'Outer block comment'
+// @!has - '/** Outer block comment */'
+// @has - 'Inner block comment'
+// @!has - '/*! Inner block comment */'
diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs
new file mode 100644
index 000000000..c97b35ada
--- /dev/null
+++ b/src/test/rustdoc/issue-25001.rs
@@ -0,0 +1,43 @@
+// @has issue_25001/struct.Foo.html
+pub struct Foo<T>(T);
+
+pub trait Bar {
+ type Item;
+
+ fn quux(self);
+}
+
+impl Foo<u8> {
+ // @has - '//*[@id="method.pass"]//h4[@class="code-header"]' 'fn pass()'
+ pub fn pass() {}
+}
+impl Foo<u16> {
+ // @has - '//*[@id="method.pass-1"]//h4[@class="code-header"]' 'fn pass() -> usize'
+ pub fn pass() -> usize { 42 }
+}
+impl Foo<u32> {
+ // @has - '//*[@id="method.pass-2"]//h4[@class="code-header"]' 'fn pass() -> isize'
+ pub fn pass() -> isize { 42 }
+}
+
+impl<T> Bar for Foo<T> {
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T'
+ type Item=T;
+
+ // @has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)'
+ fn quux(self) {}
+}
+impl<'a, T> Bar for &'a Foo<T> {
+ // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T"
+ type Item=&'a T;
+
+ // @has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)'
+ fn quux(self) {}
+}
+impl<'a, T> Bar for &'a mut Foo<T> {
+ // @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item = &'a mut T"
+ type Item=&'a mut T;
+
+ // @has - '//*[@id="method.quux-2"]//h4[@class="code-header"]' 'fn quux(self)'
+ fn quux(self) {}
+}
diff --git a/src/test/rustdoc/issue-25944.rs b/src/test/rustdoc/issue-25944.rs
new file mode 100644
index 000000000..49625294b
--- /dev/null
+++ b/src/test/rustdoc/issue-25944.rs
@@ -0,0 +1,11 @@
+// compile-flags:--test
+
+/// ```
+/// let a = r#"
+/// foo
+/// bar"#;
+/// let b = "\nfoo\nbar";
+/// assert_eq!(a, b);
+/// ```
+pub fn main() {
+}
diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs
new file mode 100644
index 000000000..d5cb2c710
--- /dev/null
+++ b/src/test/rustdoc/issue-26606.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-26606-macro.rs
+// ignore-cross-compile
+// build-aux-docs
+
+// @has issue_26606_macro/macro.make_item.html
+#[macro_use]
+extern crate issue_26606_macro;
+
+// @has issue_26606/constant.FOO.html
+// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' 'source'
+make_item!(FOO);
diff --git a/src/test/rustdoc/issue-26995.rs b/src/test/rustdoc/issue-26995.rs
new file mode 100644
index 000000000..fedc9f517
--- /dev/null
+++ b/src/test/rustdoc/issue-26995.rs
@@ -0,0 +1,7 @@
+// ignore-windows
+// compile-flags: --no-defaults
+
+// @has src/issue_26995/dev/null.html
+// @has issue_26995/null/index.html '//a/@href' '../../src/issue_26995/dev/null.html'
+#[path="/dev/null"]
+pub mod null;
diff --git a/src/test/rustdoc/issue-27104.rs b/src/test/rustdoc/issue-27104.rs
new file mode 100644
index 000000000..b74c3eb78
--- /dev/null
+++ b/src/test/rustdoc/issue-27104.rs
@@ -0,0 +1,10 @@
+// compile-flags:--no-defaults --passes strip-priv-imports
+// aux-build:empty.rs
+// ignore-cross-compile
+
+// @has issue_27104/index.html
+// @!has - 'extern crate std'
+// @!has - 'use std::prelude::'
+
+// @has - 'pub extern crate empty'
+pub extern crate empty;
diff --git a/src/test/rustdoc/issue-27362.rs b/src/test/rustdoc/issue-27362.rs
new file mode 100644
index 000000000..097e4e3b0
--- /dev/null
+++ b/src/test/rustdoc/issue-27362.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-27362-aux.rs
+// ignore-cross-compile
+
+extern crate issue_27362_aux;
+
+pub use issue_27362_aux::*;
+
+// @matches issue_27362/fn.foo.html '//pre' "pub const fn foo()"
+// @matches issue_27362/fn.bar.html '//pre' "pub const unsafe fn bar()"
+// @matches issue_27362/struct.Foo.html '//h4[@class="code-header"]' "const unsafe fn baz()"
diff --git a/src/test/rustdoc/issue-27759.rs b/src/test/rustdoc/issue-27759.rs
new file mode 100644
index 000000000..f3739dafd
--- /dev/null
+++ b/src/test/rustdoc/issue-27759.rs
@@ -0,0 +1,14 @@
+#![feature(staged_api)]
+#![doc(issue_tracker_base_url = "http://issue_url/")]
+
+#![unstable(feature="test", issue="27759")]
+
+// @has issue_27759/unstable/index.html
+// @has - '<code>test</code>&nbsp;<a href="http://issue_url/27759">#27759</a>'
+#[unstable(feature="test", issue="27759")]
+pub mod unstable {
+ // @has issue_27759/unstable/fn.issue.html
+ // @has - '<code>test_function</code>&nbsp;<a href="http://issue_url/12345">#12345</a>'
+ #[unstable(feature="test_function", issue="12345")]
+ pub fn issue() {}
+}
diff --git a/src/test/rustdoc/issue-27862.rs b/src/test/rustdoc/issue-27862.rs
new file mode 100644
index 000000000..77522f1be
--- /dev/null
+++ b/src/test/rustdoc/issue-27862.rs
@@ -0,0 +1,4 @@
+/// Tests | Table
+/// ------|-------------
+/// t = b | id = \|x\| x
+pub struct Foo; // @has issue_27862/struct.Foo.html //td 'id = |x| x'
diff --git a/src/test/rustdoc/issue-28478.rs b/src/test/rustdoc/issue-28478.rs
new file mode 100644
index 000000000..497276e68
--- /dev/null
+++ b/src/test/rustdoc/issue-28478.rs
@@ -0,0 +1,31 @@
+#![feature(associated_type_defaults)]
+
+// @has issue_28478/trait.Bar.html
+pub trait Bar {
+ // @has - '//*[@id="associatedtype.Bar"]' 'type Bar = ()'
+ // @has - '//*[@href="#associatedtype.Bar"]' 'Bar'
+ type Bar = ();
+ // @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize'
+ // @has - '//*[@href="#associatedconstant.Baz"]' 'Baz'
+ const Baz: usize = 7;
+ // @has - '//*[@id="tymethod.bar"]' 'fn bar'
+ fn bar();
+ // @has - '//*[@id="method.baz"]' 'fn baz'
+ fn baz() { }
+}
+
+// @has issue_28478/struct.Foo.html
+pub struct Foo;
+
+impl Foo {
+ // @has - '//*[@href="#method.foo"]' 'foo'
+ pub fn foo() {}
+}
+
+impl Bar for Foo {
+ // @has - '//*[@href="trait.Bar.html#associatedtype.Bar"]' 'Bar'
+ // @has - '//*[@href="trait.Bar.html#associatedconstant.Baz"]' 'Baz'
+ // @has - '//*[@href="trait.Bar.html#tymethod.bar"]' 'bar'
+ fn bar() {}
+ // @has - '//*[@href="trait.Bar.html#method.baz"]' 'baz'
+}
diff --git a/src/test/rustdoc/issue-28927.rs b/src/test/rustdoc/issue-28927.rs
new file mode 100644
index 000000000..38a520850
--- /dev/null
+++ b/src/test/rustdoc/issue-28927.rs
@@ -0,0 +1,6 @@
+// aux-build:issue-28927-2.rs
+// aux-build:issue-28927-1.rs
+// ignore-cross-compile
+
+pub extern crate issue_28927_1 as inner1;
+pub use inner1 as foo;
diff --git a/src/test/rustdoc/issue-29449.rs b/src/test/rustdoc/issue-29449.rs
new file mode 100644
index 000000000..0d829cf6f
--- /dev/null
+++ b/src/test/rustdoc/issue-29449.rs
@@ -0,0 +1,20 @@
+// @has issue_29449/struct.Foo.html
+pub struct Foo;
+
+impl Foo {
+ // @has - '//*[@id="examples"]//a' 'Examples'
+ // @has - '//*[@id="panics"]//a' 'Panics'
+ /// # Examples
+ /// # Panics
+ pub fn bar() {}
+
+ // @has - '//*[@id="examples-1"]//a' 'Examples'
+ /// # Examples
+ pub fn bar_1() {}
+
+ // @has - '//*[@id="examples-2"]//a' 'Examples'
+ // @has - '//*[@id="panics-1"]//a' 'Panics'
+ /// # Examples
+ /// # Panics
+ pub fn bar_2() {}
+}
diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs
new file mode 100644
index 000000000..635c3175f
--- /dev/null
+++ b/src/test/rustdoc/issue-29503.rs
@@ -0,0 +1,18 @@
+use std::fmt;
+
+// @has issue_29503/trait.MyTrait.html
+pub trait MyTrait {
+ fn my_string(&self) -> String;
+}
+
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
+impl<T> MyTrait for T
+where
+ T: fmt::Debug,
+{
+ fn my_string(&self) -> String {
+ format!("{:?}", self)
+ }
+}
+
+pub fn main() {}
diff --git a/src/test/rustdoc/issue-29584.rs b/src/test/rustdoc/issue-29584.rs
new file mode 100644
index 000000000..28e1efec6
--- /dev/null
+++ b/src/test/rustdoc/issue-29584.rs
@@ -0,0 +1,8 @@
+// aux-build:issue-29584.rs
+// ignore-cross-compile
+
+extern crate issue_29584;
+
+// @has issue_29584/struct.Foo.html
+// @!has - 'impl Bar for'
+pub use issue_29584::Foo;
diff --git a/src/test/rustdoc/issue-30109.rs b/src/test/rustdoc/issue-30109.rs
new file mode 100644
index 000000000..e9447538a
--- /dev/null
+++ b/src/test/rustdoc/issue-30109.rs
@@ -0,0 +1,14 @@
+// build-aux-docs
+// aux-build:issue-30109-1.rs
+// ignore-cross-compile
+
+pub mod quux {
+ extern crate issue_30109_1 as bar;
+ use self::bar::Bar;
+
+ pub trait Foo {}
+
+ // @has issue_30109/quux/trait.Foo.html \
+ // '//a/@href' '../issue_30109_1/struct.Bar.html'
+ impl Foo for Bar {}
+}
diff --git a/src/test/rustdoc/issue-30252.rs b/src/test/rustdoc/issue-30252.rs
new file mode 100644
index 000000000..c3777362a
--- /dev/null
+++ b/src/test/rustdoc/issue-30252.rs
@@ -0,0 +1,6 @@
+// compile-flags:--test --cfg feature="bar"
+
+/// ```rust
+/// assert_eq!(cfg!(feature = "bar"), true);
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-30366.rs b/src/test/rustdoc/issue-30366.rs
new file mode 100644
index 000000000..c6274a058
--- /dev/null
+++ b/src/test/rustdoc/issue-30366.rs
@@ -0,0 +1,6 @@
+// @has issue_30366/index.html '//a/@href' 'http://www.rust-lang.org/'
+
+/// Describe it. [Link somewhere][1].
+///
+/// [1]: http://www.rust-lang.org/
+pub fn here_is_a_fn() { }
diff --git a/src/test/rustdoc/issue-31808.rs b/src/test/rustdoc/issue-31808.rs
new file mode 100644
index 000000000..e55c5bd4f
--- /dev/null
+++ b/src/test/rustdoc/issue-31808.rs
@@ -0,0 +1,11 @@
+// Test that associated item impls on primitive types don't crash rustdoc
+
+pub trait Foo {
+ const BAR: usize;
+ type BAZ;
+}
+
+impl Foo for () {
+ const BAR: usize = 0;
+ type BAZ = usize;
+}
diff --git a/src/test/rustdoc/issue-31899.rs b/src/test/rustdoc/issue-31899.rs
new file mode 100644
index 000000000..e7a8ee239
--- /dev/null
+++ b/src/test/rustdoc/issue-31899.rs
@@ -0,0 +1,59 @@
+// @has issue_31899/index.html
+// @has - 'Make this line a bit longer.'
+// @!has - 'rust rust-example-rendered'
+// @!has - 'use ndarray::arr2'
+// @!has - 'prohibited'
+
+/// A tuple or fixed size array that can be used to index an array.
+/// Make this line a bit longer.
+///
+/// ```
+/// use ndarray::arr2;
+///
+/// let mut a = arr2(&[[0, 1], [0, 0]]);
+/// a[[1, 1]] = 1;
+/// assert_eq!(a[[0, 1]], 1);
+/// assert_eq!(a[[1, 1]], 1);
+/// ```
+///
+/// **Note** the blanket implementation that's not visible in rustdoc:
+/// `impl<D> NdIndex for D where D: Dimension { ... }`
+pub fn bar() {}
+
+/// Some line
+///
+/// # prohibited
+pub fn foo() {}
+
+/// Some line
+///
+/// 1. prohibited
+/// 2. bar
+pub fn baz() {}
+
+/// Some line
+///
+/// - prohibited
+/// - bar
+pub fn qux() {}
+
+/// Some line
+///
+/// * prohibited
+/// * bar
+pub fn quz() {}
+
+/// Some line
+///
+/// > prohibited
+/// > bar
+pub fn qur() {}
+
+/// Some line
+///
+/// prohibited
+/// =====
+///
+/// Second
+/// ------
+pub fn qut() {}
diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs
new file mode 100644
index 000000000..01f955381
--- /dev/null
+++ b/src/test/rustdoc/issue-32374.rs
@@ -0,0 +1,27 @@
+#![feature(staged_api)]
+#![doc(issue_tracker_base_url = "https://issue_url/")]
+#![unstable(feature = "test", issue = "32374")]
+
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// 'Deprecated'
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// 'Experimental'
+// @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
+
+// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
+// '👎 Deprecated since 1.0.0: text'
+// @has - '<code>test</code>&nbsp;<a href="https://issue_url/32374">#32374</a>'
+// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
+// '🔬 This is a nightly-only experimental API. \(test\s#32374\)$'
+/// Docs
+#[deprecated(since = "1.0.0", note = "text")]
+#[unstable(feature = "test", issue = "32374")]
+pub struct T;
+
+// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
+// '👎 Deprecated since 1.0.0: deprecated'
+// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
+// '🔬 This is a nightly-only experimental API. (test #32374)'
+#[deprecated(since = "1.0.0", note = "deprecated")]
+#[unstable(feature = "test", issue = "32374", reason = "unstable")]
+pub struct U;
diff --git a/src/test/rustdoc/issue-32395.rs b/src/test/rustdoc/issue-32395.rs
new file mode 100644
index 000000000..13468c153
--- /dev/null
+++ b/src/test/rustdoc/issue-32395.rs
@@ -0,0 +1,15 @@
+// aux-build:variant-struct.rs
+// build-aux-docs
+// ignore-cross-compile
+
+// @has variant_struct/enum.Foo.html
+// @!has - 'pub qux'
+// @!has - 'pub(crate) qux'
+// @!has - 'pub Bar'
+extern crate variant_struct;
+
+// @has issue_32395/enum.Foo.html
+// @!has - 'pub qux'
+// @!has - 'pub(crate) qux'
+// @!has - 'pub Bar'
+pub use variant_struct::Foo;
diff --git a/src/test/rustdoc/issue-32556.rs b/src/test/rustdoc/issue-32556.rs
new file mode 100644
index 000000000..e1cf11509
--- /dev/null
+++ b/src/test/rustdoc/issue-32556.rs
@@ -0,0 +1,5 @@
+/// Blah blah blah
+/// ```ignore (testing rustdoc's handling of ignore)
+/// bad_assert!();
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-32890.rs b/src/test/rustdoc/issue-32890.rs
new file mode 100644
index 000000000..970954433
--- /dev/null
+++ b/src/test/rustdoc/issue-32890.rs
@@ -0,0 +1,17 @@
+// @has issue_32890/struct.Foo.html
+pub struct Foo<T>(T);
+
+impl Foo<u8> {
+ // @has - '//a[@href="#method.pass"]' 'pass'
+ pub fn pass() {}
+}
+
+impl Foo<u16> {
+ // @has - '//a[@href="#method.pass-1"]' 'pass'
+ pub fn pass() {}
+}
+
+impl Foo<u32> {
+ // @has - '//a[@href="#method.pass-2"]' 'pass'
+ pub fn pass() {}
+}
diff --git a/src/test/rustdoc/issue-33069.rs b/src/test/rustdoc/issue-33069.rs
new file mode 100644
index 000000000..0213a53ca
--- /dev/null
+++ b/src/test/rustdoc/issue-33069.rs
@@ -0,0 +1,10 @@
+pub trait Bar {}
+
+#[doc(hidden)]
+pub mod hidden {
+ pub struct Foo;
+}
+
+// @has issue_33069/trait.Bar.html
+// @!has - '//code' 'impl Bar for Foo'
+impl Bar for hidden::Foo {}
diff --git a/src/test/rustdoc/issue-33178-1.rs b/src/test/rustdoc/issue-33178-1.rs
new file mode 100644
index 000000000..4dc425346
--- /dev/null
+++ b/src/test/rustdoc/issue-33178-1.rs
@@ -0,0 +1,10 @@
+// aux-build:empty.rs
+// aux-build:variant-struct.rs
+// ignore-cross-compile
+
+// @has issue_33178_1/index.html
+// @!has - //a/@title empty
+pub extern crate empty;
+
+// @!has - //a/@title variant_struct
+pub extern crate variant_struct as foo;
diff --git a/src/test/rustdoc/issue-33178.rs b/src/test/rustdoc/issue-33178.rs
new file mode 100644
index 000000000..1f45fe723
--- /dev/null
+++ b/src/test/rustdoc/issue-33178.rs
@@ -0,0 +1,13 @@
+// aux-build:empty.rs
+// aux-build:variant-struct.rs
+// build-aux-docs
+// ignore-cross-compile
+
+// @has issue_33178/index.html
+// @has - //a/@title empty
+// @has - //a/@href ../empty/index.html
+pub extern crate empty;
+
+// @has - //a/@title variant_struct
+// @has - //a/@href ../variant_struct/index.html
+pub extern crate variant_struct as foo;
diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs
new file mode 100644
index 000000000..1e4791e01
--- /dev/null
+++ b/src/test/rustdoc/issue-33302.rs
@@ -0,0 +1,51 @@
+// Ensure constant and array length values are not taken from source
+// code, which wreaks havoc with macros.
+
+macro_rules! make {
+ ($n:expr) => {
+ pub struct S;
+
+ // @has issue_33302/constant.CST.html \
+ // '//pre[@class="rust const"]' 'pub const CST: i32'
+ pub const CST: i32 = ($n * $n);
+ // @has issue_33302/static.ST.html \
+ // '//pre[@class="rust static"]' 'pub static ST: i32'
+ pub static ST: i32 = ($n * $n);
+
+ pub trait T<X> {
+ fn ignore(_: &X) {}
+ const C: X;
+ // @has issue_33302/trait.T.html \
+ // '//*[@class="rust trait"]' 'const D: i32'
+ // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
+ const D: i32 = ($n * $n);
+ }
+
+ // @has issue_33302/struct.S.html \
+ // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+ // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
+ // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
+ impl T<[i32; ($n * $n)]> for S {
+ const C: [i32; ($n * $n)] = [0; ($n * $n)];
+ }
+
+ // @has issue_33302/struct.S.html \
+ // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+ // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
+ // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
+ impl T<(i32,)> for S {
+ const C: (i32,) = ($n,);
+ }
+
+ // @has issue_33302/struct.S.html \
+ // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
+ // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
+ // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
+ impl T<(i32, i32)> for S {
+ const C: (i32, i32) = ($n, $n);
+ const D: i32 = ($n / $n);
+ }
+ };
+}
+
+make!(4);
diff --git a/src/test/rustdoc/issue-33592.rs b/src/test/rustdoc/issue-33592.rs
new file mode 100644
index 000000000..815439db9
--- /dev/null
+++ b/src/test/rustdoc/issue-33592.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+pub trait Foo<T> {}
+
+pub struct Bar;
+
+pub struct Baz;
+
+// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl Foo<i32> for Bar'
+impl Foo<i32> for Bar {}
+
+// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl<T> Foo<T> for Baz'
+impl<T> Foo<T> for Baz {}
diff --git a/src/test/rustdoc/issue-34025.rs b/src/test/rustdoc/issue-34025.rs
new file mode 100644
index 000000000..9b9f21cb3
--- /dev/null
+++ b/src/test/rustdoc/issue-34025.rs
@@ -0,0 +1,12 @@
+#![crate_name = "foo"]
+
+// @!has 'foo/sys/index.html'
+// @!has 'foo/sys/sidebar-items.js'
+#[doc(hidden)]
+pub mod sys {
+ extern "C" {
+ // @!has 'foo/sys/fn.foo.html'
+ #[doc(hidden)]
+ pub fn foo();
+ }
+}
diff --git a/src/test/rustdoc/issue-34274.rs b/src/test/rustdoc/issue-34274.rs
new file mode 100644
index 000000000..ce5be84a5
--- /dev/null
+++ b/src/test/rustdoc/issue-34274.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-34274.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+extern crate issue_34274;
+
+// @has foo/fn.extern_c_fn.html '//a/@href' '../src/issue_34274/issue-34274.rs.html#2'
+pub use issue_34274::extern_c_fn;
diff --git a/src/test/rustdoc/issue-34423.rs b/src/test/rustdoc/issue-34423.rs
new file mode 100644
index 000000000..b429bf8c9
--- /dev/null
+++ b/src/test/rustdoc/issue-34423.rs
@@ -0,0 +1,10 @@
+pub struct Foo;
+
+pub trait Bar {
+ #[doc(hidden)]
+ fn bar() {}
+}
+
+impl Bar for Foo {
+ fn bar() {}
+}
diff --git a/src/test/rustdoc/issue-34473.rs b/src/test/rustdoc/issue-34473.rs
new file mode 100644
index 000000000..d96301f3a
--- /dev/null
+++ b/src/test/rustdoc/issue-34473.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+
+mod second {
+ pub struct SomeTypeWithLongName;
+}
+
+// @has foo/index.html
+// @!has - SomeTypeWithLongName
+// @has foo/struct.SomeType.html
+// @!has foo/struct.SomeTypeWithLongName.html
+pub use second::{SomeTypeWithLongName as SomeType};
diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs
new file mode 100644
index 000000000..4184086f6
--- /dev/null
+++ b/src/test/rustdoc/issue-34928.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+pub trait Bar {}
+
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+pub struct Foo<T>(pub T) where T: Bar;
diff --git a/src/test/rustdoc/issue-35169-2.rs b/src/test/rustdoc/issue-35169-2.rs
new file mode 100644
index 000000000..f08466baf
--- /dev/null
+++ b/src/test/rustdoc/issue-35169-2.rs
@@ -0,0 +1,40 @@
+use std::ops::Deref;
+use std::ops::DerefMut;
+
+pub struct Foo;
+pub struct Bar;
+
+impl Foo {
+ pub fn by_ref(&self) {}
+ pub fn by_explicit_ref(self: &Foo) {}
+ pub fn by_mut_ref(&mut self) {}
+ pub fn by_explicit_mut_ref(self: &mut Foo) {}
+ pub fn by_explicit_box(self: Box<Foo>) {}
+ pub fn by_explicit_self_box(self: Box<Self>) {}
+ pub fn static_foo() {}
+}
+
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Foo { loop {} }
+}
+
+impl DerefMut for Bar {
+ fn deref_mut(&mut self) -> &mut Foo { loop {} }
+}
+
+// @has issue_35169_2/struct.Bar.html
+// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)'
+// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
+// @has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)'
+// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
+// @has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
diff --git a/src/test/rustdoc/issue-35169.rs b/src/test/rustdoc/issue-35169.rs
new file mode 100644
index 000000000..70a2265c8
--- /dev/null
+++ b/src/test/rustdoc/issue-35169.rs
@@ -0,0 +1,35 @@
+use std::ops::Deref;
+
+pub struct Foo;
+pub struct Bar;
+
+impl Foo {
+ pub fn by_ref(&self) {}
+ pub fn by_explicit_ref(self: &Foo) {}
+ pub fn by_mut_ref(&mut self) {}
+ pub fn by_explicit_mut_ref(self: &mut Foo) {}
+ pub fn by_explicit_box(self: Box<Foo>) {}
+ pub fn by_explicit_self_box(self: Box<Self>) {}
+ pub fn static_foo() {}
+}
+
+impl Deref for Bar {
+ type Target = Foo;
+ fn deref(&self) -> &Foo { loop {} }
+}
+
+// @has issue_35169/struct.Bar.html
+// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
+// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)'
+// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
+// @!has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)'
+// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
+// @!has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
+// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)'
+// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()'
+// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
diff --git a/src/test/rustdoc/issue-35488.rs b/src/test/rustdoc/issue-35488.rs
new file mode 100644
index 000000000..c1bf9ceea
--- /dev/null
+++ b/src/test/rustdoc/issue-35488.rs
@@ -0,0 +1,13 @@
+mod foo {
+ pub enum Foo {
+ Bar,
+ }
+ pub use self::Foo::*;
+}
+
+// @has 'issue_35488/index.html' '//code' 'pub use self::Foo::*;'
+// @has 'issue_35488/enum.Foo.html'
+pub use self::foo::*;
+
+// @has 'issue_35488/index.html' '//code' 'pub use std::option::Option::None;'
+pub use std::option::Option::None;
diff --git a/src/test/rustdoc/issue-36031.rs b/src/test/rustdoc/issue-36031.rs
new file mode 100644
index 000000000..af1b32fd2
--- /dev/null
+++ b/src/test/rustdoc/issue-36031.rs
@@ -0,0 +1,9 @@
+// aux-build:issue-36031.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+extern crate issue_36031;
+
+pub use issue_36031::Foo;
diff --git a/src/test/rustdoc/issue-38129.rs b/src/test/rustdoc/issue-38129.rs
new file mode 100644
index 000000000..156d50fa5
--- /dev/null
+++ b/src/test/rustdoc/issue-38129.rs
@@ -0,0 +1,99 @@
+// compile-flags:--test
+
+// This file tests the source-partitioning behavior of rustdoc.
+// Each test contains some code that should be put into the generated
+// `fn main` and some attributes should be left outside (except the first
+// one, which has no attributes).
+// If the #![recursion_limit] attribute is incorrectly left inside,
+// then the tests will fail because the macro recurses 128 times.
+
+/// ```
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn simple() {}
+
+/// ```
+/// #![recursion_limit = "1024"]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn non_feature_attr() {}
+
+/// ```
+/// #![feature(core_intrinsics)]
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn feature_attr() {}
+
+/// ```
+/// #![feature(core_intrinsics)]
+/// #![recursion_limit = "1024"]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn both_attrs() {}
+
+/// ```
+/// #![recursion_limit = "1024"]
+/// #![feature(core_intrinsics)]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn both_attrs_reverse() {}
diff --git a/src/test/rustdoc/issue-38219.rs b/src/test/rustdoc/issue-38219.rs
new file mode 100644
index 000000000..fa57c58c7
--- /dev/null
+++ b/src/test/rustdoc/issue-38219.rs
@@ -0,0 +1,8 @@
+// compile-flags:--test
+// should-fail
+
+/// ```
+/// fail
+/// ```
+#[macro_export]
+macro_rules! foo { () => {} }
diff --git a/src/test/rustdoc/issue-40936.rs b/src/test/rustdoc/issue-40936.rs
new file mode 100644
index 000000000..4d2e4c17b
--- /dev/null
+++ b/src/test/rustdoc/issue-40936.rs
@@ -0,0 +1,6 @@
+// aux-build:issue-40936.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate issue_40936;
diff --git a/src/test/rustdoc/issue-41783.rs b/src/test/rustdoc/issue-41783.rs
new file mode 100644
index 000000000..cb9b9b153
--- /dev/null
+++ b/src/test/rustdoc/issue-41783.rs
@@ -0,0 +1,19 @@
+// @has issue_41783/struct.Foo.html
+// @!has - 'space'
+// @!has - 'comment'
+// @has - '# <span class="ident">single'
+// @has - '## <span class="ident">double</span>'
+// @has - '### <span class="ident">triple</span>'
+// @has - '<span class="attribute">#[<span class="ident">outer</span>]</span>'
+// @has - '<span class="attribute">#![<span class="ident">inner</span>]</span>'
+
+/// ```no_run
+/// # # space
+/// # comment
+/// ## single
+/// ### double
+/// #### triple
+/// ##[outer]
+/// ##![inner]
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs
new file mode 100644
index 000000000..a5394c7d9
--- /dev/null
+++ b/src/test/rustdoc/issue-42760.rs
@@ -0,0 +1,15 @@
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
+// @has issue_42760/struct.NonGen.html
+// @has - '//h2' 'Example'
+
+/// Item docs.
+///
+#[doc="Hello there!"]
+///
+/// # Example
+///
+/// ```rust
+/// // some code here
+/// ```
+pub struct NonGen;
diff --git a/src/test/rustdoc/issue-43153.rs b/src/test/rustdoc/issue-43153.rs
new file mode 100644
index 000000000..0fe680f10
--- /dev/null
+++ b/src/test/rustdoc/issue-43153.rs
@@ -0,0 +1,10 @@
+// Test that `include!` in a doc test searches relative to the directory in
+// which the test is declared.
+
+// compile-flags:--test
+
+/// ```rust
+/// include!("auxiliary/empty.rs");
+/// fn main() {}
+/// ```
+pub struct Foo;
diff --git a/src/test/rustdoc/issue-43701.rs b/src/test/rustdoc/issue-43701.rs
new file mode 100644
index 000000000..44335e961
--- /dev/null
+++ b/src/test/rustdoc/issue-43701.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+pub use std::vec::Vec;
+
+// @!has implementors/core/clone/trait.Clone.js
diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs
new file mode 100644
index 000000000..767d09d85
--- /dev/null
+++ b/src/test/rustdoc/issue-43869.rs
@@ -0,0 +1,72 @@
+pub fn g() -> impl Iterator<Item=u8> {
+ Some(1u8).into_iter()
+}
+
+#[allow(unused_parens)]
+pub fn h() -> (impl Iterator<Item=u8>) {
+ Some(1u8).into_iter()
+}
+
+pub fn i() -> impl Iterator<Item=u8> + 'static {
+ Some(1u8).into_iter()
+}
+
+pub fn j() -> impl Iterator<Item=u8> + Clone {
+ Some(1u8).into_iter()
+}
+
+pub fn k() -> [impl Clone; 2] {
+ [123u32, 456u32]
+}
+
+pub fn l() -> (impl Clone, impl Default) {
+ (789u32, -123i32)
+}
+
+pub fn m() -> &'static impl Clone {
+ &1u8
+}
+
+pub fn n() -> *const impl Clone {
+ &1u8
+}
+
+pub fn o() -> &'static [impl Clone] {
+ b":)"
+}
+
+// issue #44731
+pub fn test_44731_0() -> Box<impl Iterator<Item=u8>> {
+ Box::new(g())
+}
+
+pub fn test_44731_1() -> Result<Box<impl Clone>, ()> {
+ Ok(Box::new(j()))
+}
+
+// NOTE these involve Fn sugar, where impl Trait is disallowed for now, see issue #45994
+//
+//pub fn test_44731_2() -> Box<Fn(impl Clone)> {
+// Box::new(|_: u32| {})
+//}
+//
+//pub fn test_44731_3() -> Box<Fn() -> impl Clone> {
+// Box::new(|| 0u32)
+//}
+
+pub fn test_44731_4() -> Box<Iterator<Item=impl Clone>> {
+ Box::new(g())
+}
+
+// @has issue_43869/fn.g.html
+// @has issue_43869/fn.h.html
+// @has issue_43869/fn.i.html
+// @has issue_43869/fn.j.html
+// @has issue_43869/fn.k.html
+// @has issue_43869/fn.l.html
+// @has issue_43869/fn.m.html
+// @has issue_43869/fn.n.html
+// @has issue_43869/fn.o.html
+// @has issue_43869/fn.test_44731_0.html
+// @has issue_43869/fn.test_44731_1.html
+// @has issue_43869/fn.test_44731_4.html
diff --git a/src/test/rustdoc/issue-43893.rs b/src/test/rustdoc/issue-43893.rs
new file mode 100644
index 000000000..95d551934
--- /dev/null
+++ b/src/test/rustdoc/issue-43893.rs
@@ -0,0 +1,19 @@
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+pub trait SomeTrait {}
+pub struct SomeStruct;
+
+// @has foo/trait.SomeTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#9'
+impl SomeTrait for usize {}
+
+// @has foo/trait.SomeTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#12-14'
+impl SomeTrait for SomeStruct {
+ // deliberately multi-line impl
+}
+
+pub trait AnotherTrait {}
+
+// @has foo/trait.AnotherTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#19'
+impl<T> AnotherTrait for T {}
diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs
new file mode 100644
index 000000000..86479e6fb
--- /dev/null
+++ b/src/test/rustdoc/issue-45584.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+
+pub trait Bar<T, U> {}
+
+// @has 'foo/struct.Foo1.html'
+pub struct Foo1;
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+impl Bar<Foo1, &'static Foo1> for Foo1 {}
+
+// @has 'foo/struct.Foo2.html'
+pub struct Foo2;
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
+impl Bar<&'static Foo2, Foo2> for u8 {}
diff --git a/src/test/rustdoc/issue-46271.rs b/src/test/rustdoc/issue-46271.rs
new file mode 100644
index 000000000..b38ef20c5
--- /dev/null
+++ b/src/test/rustdoc/issue-46271.rs
@@ -0,0 +1,5 @@
+// hopefully this doesn't cause an ICE
+
+pub fn foo() {
+ extern crate std;
+}
diff --git a/src/test/rustdoc/issue-46377.rs b/src/test/rustdoc/issue-46377.rs
new file mode 100644
index 000000000..4489f038c
--- /dev/null
+++ b/src/test/rustdoc/issue-46377.rs
@@ -0,0 +1,3 @@
+// @has 'issue_46377/index.html' '//*[@class="item-right docblock-short"]' 'Check out this struct!'
+/// # Check out this struct!
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/issue-46380-2.rs b/src/test/rustdoc/issue-46380-2.rs
new file mode 100644
index 000000000..7004d18dc
--- /dev/null
+++ b/src/test/rustdoc/issue-46380-2.rs
@@ -0,0 +1,9 @@
+pub trait PublicTrait<T> {}
+
+// @has issue_46380_2/struct.PublicStruct.html
+pub struct PublicStruct;
+
+// @!has - '//*[@class="impl"]' 'impl PublicTrait<PrivateStruct> for PublicStruct'
+impl PublicTrait<PrivateStruct> for PublicStruct {}
+
+struct PrivateStruct;
diff --git a/src/test/rustdoc/issue-46727.rs b/src/test/rustdoc/issue-46727.rs
new file mode 100644
index 000000000..00e9127a3
--- /dev/null
+++ b/src/test/rustdoc/issue-46727.rs
@@ -0,0 +1,7 @@
+// aux-build:issue-46727.rs
+
+extern crate issue_46727;
+
+// @has issue_46727/trait.Foo.html
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Foo for Bar<[T; 3]>'
+pub use issue_46727::{Foo, Bar};
diff --git a/src/test/rustdoc/issue-46766.rs b/src/test/rustdoc/issue-46766.rs
new file mode 100644
index 000000000..36ab73956
--- /dev/null
+++ b/src/test/rustdoc/issue-46766.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+pub enum Enum{Variant}
+pub use self::Enum::Variant;
+
+// @!has foo/index.html '//a/@href' './Enum/index.html'
diff --git a/src/test/rustdoc/issue-46767.rs b/src/test/rustdoc/issue-46767.rs
new file mode 100644
index 000000000..ef6ed104b
--- /dev/null
+++ b/src/test/rustdoc/issue-46767.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+mod private {
+ pub enum Enum{Variant}
+}
+pub use self::private::Enum::*;
+
+// @!has-dir foo/private
+// @!has foo/index.html '//a/@href' 'private/index.html'
diff --git a/src/test/rustdoc/issue-46976.rs b/src/test/rustdoc/issue-46976.rs
new file mode 100644
index 000000000..c59f8c72e
--- /dev/null
+++ b/src/test/rustdoc/issue-46976.rs
@@ -0,0 +1 @@
+pub fn ice(f: impl Fn()) {}
diff --git a/src/test/rustdoc/issue-47038.rs b/src/test/rustdoc/issue-47038.rs
new file mode 100644
index 000000000..810ddca3e
--- /dev/null
+++ b/src/test/rustdoc/issue-47038.rs
@@ -0,0 +1,10 @@
+#![feature(decl_macro)]
+
+#![crate_name = "foo"]
+
+use std::vec;
+
+// @has 'foo/index.html'
+// @!has - '//*[@id="macros"]' 'Macros'
+// @!has - '//a/@href' 'macro.vec.html'
+// @!has 'foo/macro.vec.html'
diff --git a/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs b/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs
new file mode 100644
index 000000000..19994475d
--- /dev/null
+++ b/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs
@@ -0,0 +1,8 @@
+// @has issue_47197_blank_line_in_doc_block/fn.whose_woods_these_are_i_think_i_know.html
+
+/**
+* snow
+
+* ice
+*/
+pub fn whose_woods_these_are_i_think_i_know() {}
diff --git a/src/test/rustdoc/issue-47639.rs b/src/test/rustdoc/issue-47639.rs
new file mode 100644
index 000000000..4b3456b86
--- /dev/null
+++ b/src/test/rustdoc/issue-47639.rs
@@ -0,0 +1,6 @@
+// This should not ICE
+pub fn test() {
+ macro_rules! foo {
+ () => ()
+ }
+}
diff --git a/src/test/rustdoc/issue-48377.rs b/src/test/rustdoc/issue-48377.rs
new file mode 100644
index 000000000..c32bcf380
--- /dev/null
+++ b/src/test/rustdoc/issue-48377.rs
@@ -0,0 +1,13 @@
+// compile-flags:--test
+
+//! This is a doc comment
+//!
+//! ```rust
+//! fn main() {}
+//! ```
+//!
+//! With a trailing code fence
+//! ```
+
+/// Some foo function
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-48414.rs b/src/test/rustdoc/issue-48414.rs
new file mode 100644
index 000000000..b35743d88
--- /dev/null
+++ b/src/test/rustdoc/issue-48414.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-48414.rs
+
+// ICE when resolving paths for a trait that linked to another trait, when both were in an external
+// crate
+
+#![crate_name = "base"]
+
+extern crate issue_48414;
+
+#[doc(inline)]
+pub use issue_48414::{SomeTrait, OtherTrait};
diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs
new file mode 100644
index 000000000..d88c29217
--- /dev/null
+++ b/src/test/rustdoc/issue-50159.rs
@@ -0,0 +1,20 @@
+pub trait Signal {
+ type Item;
+}
+
+pub trait Signal2 {
+ type Item2;
+}
+
+impl<B, C> Signal2 for B where B: Signal<Item = C> {
+ type Item2 = C;
+}
+
+// @has issue_50159/struct.Switch.html
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+pub struct Switch<B: Signal> {
+ pub inner: <B as Signal2>::Item2,
+}
diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs
new file mode 100644
index 000000000..ee11ccc68
--- /dev/null
+++ b/src/test/rustdoc/issue-51236.rs
@@ -0,0 +1,14 @@
+use std::marker::PhantomData;
+
+pub mod traits {
+ pub trait Owned<'a> {
+ type Reader;
+ }
+}
+
+// @has issue_51236/struct.Owned.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
+pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
+ marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
+}
diff --git a/src/test/rustdoc/issue-52873.rs b/src/test/rustdoc/issue-52873.rs
new file mode 100644
index 000000000..8000ce73b
--- /dev/null
+++ b/src/test/rustdoc/issue-52873.rs
@@ -0,0 +1,171 @@
+// Regression test for #52873. We used to ICE due to unexpected
+// overflows when checking for "blanket impl inclusion".
+
+use std::marker::PhantomData;
+use std::cmp::Ordering;
+use std::ops::{Add, Mul};
+
+pub type True = B1;
+pub type False = B0;
+pub type U0 = UTerm;
+pub type U1 = UInt<UTerm, B1>;
+
+pub trait NonZero {}
+
+pub trait Bit {
+}
+
+pub trait Unsigned {
+}
+
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]
+pub struct B0;
+
+impl B0 {
+ #[inline]
+ pub fn new() -> B0 {
+ B0
+ }
+}
+
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]
+pub struct B1;
+
+impl B1 {
+ #[inline]
+ pub fn new() -> B1 {
+ B1
+ }
+}
+
+impl Bit for B0 {
+}
+
+impl Bit for B1 {
+}
+
+impl NonZero for B1 {}
+
+pub trait PrivatePow<Y, N> {
+ type Output;
+}
+pub type PrivatePowOut<A, Y, N> = <A as PrivatePow<Y, N>>::Output;
+
+pub type Add1<A> = <A as Add<::B1>>::Output;
+pub type Prod<A, B> = <A as Mul<B>>::Output;
+pub type Square<A> = <A as Mul>::Output;
+pub type Sum<A, B> = <A as Add<B>>::Output;
+
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]
+pub struct UTerm;
+
+impl UTerm {
+ #[inline]
+ pub fn new() -> UTerm {
+ UTerm
+ }
+}
+
+impl Unsigned for UTerm {
+}
+
+#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]
+pub struct UInt<U, B> {
+ _marker: PhantomData<(U, B)>,
+}
+
+impl<U: Unsigned, B: Bit> UInt<U, B> {
+ #[inline]
+ pub fn new() -> UInt<U, B> {
+ UInt {
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<U: Unsigned, B: Bit> Unsigned for UInt<U, B> {
+}
+
+impl<U: Unsigned, B: Bit> NonZero for UInt<U, B> {}
+
+impl Add<B0> for UTerm {
+ type Output = UTerm;
+ fn add(self, _: B0) -> Self::Output {
+ UTerm
+ }
+}
+
+impl<U: Unsigned, B: Bit> Add<B0> for UInt<U, B> {
+ type Output = UInt<U, B>;
+ fn add(self, _: B0) -> Self::Output {
+ UInt::new()
+ }
+}
+
+impl<U: Unsigned> Add<U> for UTerm {
+ type Output = U;
+ fn add(self, _: U) -> Self::Output {
+ unimplemented!()
+ }
+}
+
+impl<U: Unsigned, B: Bit> Mul<B0> for UInt<U, B> {
+ type Output = UTerm;
+ fn mul(self, _: B0) -> Self::Output {
+ UTerm
+ }
+}
+
+impl<U: Unsigned, B: Bit> Mul<B1> for UInt<U, B> {
+ type Output = UInt<U, B>;
+ fn mul(self, _: B1) -> Self::Output {
+ UInt::new()
+ }
+}
+
+impl<U: Unsigned> Mul<U> for UTerm {
+ type Output = UTerm;
+ fn mul(self, _: U) -> Self::Output {
+ UTerm
+ }
+}
+
+impl<Ul: Unsigned, B: Bit, Ur: Unsigned> Mul<UInt<Ur, B>> for UInt<Ul, B0>
+where
+ Ul: Mul<UInt<Ur, B>>,
+{
+ type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>;
+ fn mul(self, _: UInt<Ur, B>) -> Self::Output {
+ unimplemented!()
+ }
+}
+
+pub trait Pow<Exp> {
+ type Output;
+}
+
+impl<X: Unsigned, N: Unsigned> Pow<N> for X
+where
+ X: PrivatePow<U1, N>,
+{
+ type Output = PrivatePowOut<X, U1, N>;
+}
+
+impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U0> for X {
+ type Output = Y;
+}
+
+impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U1> for X
+where
+ X: Mul<Y>,
+{
+ type Output = Prod<X, Y>;
+}
+
+impl<Y: Unsigned, U: Unsigned, B: Bit, X: Unsigned> PrivatePow<Y, UInt<UInt<U, B>, B0>> for X
+where
+ X: Mul,
+ Square<X>: PrivatePow<Y, UInt<U, B>>,
+{
+ type Output = PrivatePowOut<Square<X>, Y, UInt<U, B>>;
+}
diff --git a/src/test/rustdoc/issue-53689.rs b/src/test/rustdoc/issue-53689.rs
new file mode 100644
index 000000000..52ce4159d
--- /dev/null
+++ b/src/test/rustdoc/issue-53689.rs
@@ -0,0 +1,16 @@
+// aux-build:issue-53689.rs
+
+#![crate_name = "foo"]
+
+extern crate issue_53689;
+
+// @has foo/trait.MyTrait.html
+// @!has - 'MyStruct'
+// @count - '//*[h3="impl<T> MyTrait for T"]' 1
+pub trait MyTrait {}
+
+impl<T> MyTrait for T {}
+
+mod a {
+ pub use issue_53689::MyStruct;
+}
diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs
new file mode 100644
index 000000000..c68ffd521
--- /dev/null
+++ b/src/test/rustdoc/issue-53812.rs
@@ -0,0 +1,20 @@
+pub trait MyIterator {}
+
+pub struct MyStruct<T>(T);
+
+macro_rules! array_impls {
+ ($($N:expr)+) => {
+ $(
+ impl<'a, T> MyIterator for &'a MyStruct<[T; $N]> {
+ }
+ )+
+ }
+}
+
+// @has issue_53812/trait.MyIterator.html
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
+array_impls! { 10 3 2 1 0 }
diff --git a/src/test/rustdoc/issue-54478-demo-allocator.rs b/src/test/rustdoc/issue-54478-demo-allocator.rs
new file mode 100644
index 000000000..4811f363b
--- /dev/null
+++ b/src/test/rustdoc/issue-54478-demo-allocator.rs
@@ -0,0 +1,42 @@
+// Issue #54478: regression test showing that we can demonstrate
+// `#[global_allocator]` in code blocks built by `rustdoc`.
+//
+// ## Background
+//
+// Changes in lang-item visibility injected failures that were only
+// exposed when compiling with `-C prefer-dynamic`. But `rustdoc` used
+// `-C prefer-dynamic` (and had done so for years, for reasons we did
+// not document at that time).
+//
+// Rather than try to revise the visbility semanics, we instead
+// decided to change `rustdoc` to behave more like the compiler's
+// default setting, by leaving off `-C prefer-dynamic`.
+
+// compile-flags:--test
+
+//! This is a doc comment
+//!
+//! ```rust
+//! use std::alloc::*;
+//!
+//! #[global_allocator]
+//! static ALLOC: A = A;
+//!
+//! static mut HIT: bool = false;
+//!
+//! struct A;
+//!
+//! unsafe impl GlobalAlloc for A {
+//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+//! HIT = true;
+//! System.alloc(layout)
+//! }
+//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+//! System.dealloc(ptr, layout);
+//! }
+//! }
+//!
+//! fn main() {
+//! assert!(unsafe { HIT });
+//! }
+//! ```
diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs
new file mode 100644
index 000000000..bedaf5c4d
--- /dev/null
+++ b/src/test/rustdoc/issue-54705.rs
@@ -0,0 +1,29 @@
+pub trait ScopeHandle<'scope> {}
+
+
+
+// @has issue_54705/struct.ScopeFutureContents.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
+//
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
+pub struct ScopeFutureContents<'scope, S>
+ where S: ScopeHandle<'scope>,
+{
+ dummy: &'scope S,
+ this: Box<ScopeFuture<'scope, S>>,
+}
+
+struct ScopeFuture<'scope, S>
+ where S: ScopeHandle<'scope>,
+{
+ contents: ScopeFutureContents<'scope, S>,
+}
+
+unsafe impl<'scope, S> Send for ScopeFuture<'scope, S>
+ where S: ScopeHandle<'scope>,
+{}
+unsafe impl<'scope, S> Sync for ScopeFuture<'scope, S>
+ where S: ScopeHandle<'scope>,
+{}
diff --git a/src/test/rustdoc/issue-55001.rs b/src/test/rustdoc/issue-55001.rs
new file mode 100644
index 000000000..f6c7f9a3d
--- /dev/null
+++ b/src/test/rustdoc/issue-55001.rs
@@ -0,0 +1,31 @@
+// Regression test for issue #55001. Previously, we would incorrectly
+// cache certain trait selection results when checking for blanket impls,
+// resulting in an ICE when we tried to confirm the cached ParamCandidate
+// against an obligation.
+
+pub struct DefaultAllocator;
+pub struct Standard;
+pub struct Inner;
+
+pub trait Rand {}
+
+pub trait Distribution<T> {}
+pub trait Allocator<N> {}
+
+impl<T> Rand for T where Standard: Distribution<T> {}
+
+impl<A> Distribution<Point<A>> for Standard
+where
+DefaultAllocator: Allocator<A>,
+Standard: Distribution<A> {}
+
+impl Distribution<Inner> for Standard {}
+
+
+pub struct Point<N>
+where DefaultAllocator: Allocator<N>
+{
+ field: N
+}
+
+fn main() {}
diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs
new file mode 100644
index 000000000..ee2420d86
--- /dev/null
+++ b/src/test/rustdoc/issue-55321.rs
@@ -0,0 +1,18 @@
+#![feature(negative_impls)]
+
+// @has issue_55321/struct.A.html
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl !Sync for A"
+pub struct A();
+
+impl !Send for A {}
+impl !Sync for A {}
+
+// @has issue_55321/struct.B.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Send for B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Sync for B<T>"
+pub struct B<T: ?Sized>(A, Box<T>);
diff --git a/src/test/rustdoc/issue-55364.rs b/src/test/rustdoc/issue-55364.rs
new file mode 100644
index 000000000..14a6f5041
--- /dev/null
+++ b/src/test/rustdoc/issue-55364.rs
@@ -0,0 +1,86 @@
+// First a module with inner documentation
+
+// @has issue_55364/subone/index.html
+// These foo/bar links in the module's documentation should refer inside `subone`
+// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+pub mod subone {
+ //! See either [foo] or [bar].
+
+ // This should refer to subone's `bar`
+ // @has issue_55364/subone/fn.foo.html
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+ /// See [bar]
+ pub fn foo() {}
+ // This should refer to subone's `foo`
+ // @has issue_55364/subone/fn.bar.html
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+ /// See [foo]
+ pub fn bar() {}
+}
+
+// A module with outer documentation
+
+// @has issue_55364/subtwo/index.html
+// These foo/bar links in the module's documentation should not reference inside `subtwo`
+// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+// Instead it should be referencing the top level functions
+// @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"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+/// See either [foo] or [bar].
+pub mod subtwo {
+
+ // Despite the module's docs referring to the top level foo/bar,
+ // this should refer to subtwo's `bar`
+ // @has issue_55364/subtwo/fn.foo.html
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+ /// See [bar]
+ pub fn foo() {}
+ // Despite the module's docs referring to the top level foo/bar,
+ // this should refer to subtwo's `foo`
+ // @has issue_55364/subtwo/fn.bar.html
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+ /// See [foo]
+ pub fn bar() {}
+}
+
+// These are the function referred to by the module above with outer docs
+
+/// See [bar]
+pub fn foo() {}
+/// See [foo]
+pub fn bar() {}
+
+// This module refers to the outer foo/bar by means of `super::`
+
+// @has issue_55364/subthree/index.html
+// This module should also refer to the top level foo/bar
+// @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'
+pub mod subthree {
+ //! See either [foo][super::foo] or [bar][super::bar]
+}
+
+// Next we go *deeper* - In order to ensure it's not just "this or parent"
+// we test `crate::` and a `super::super::...` chain
+// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
+pub mod subfour {
+ pub mod subfive {
+ pub mod subsix {
+ pub mod subseven {
+ pub mod subeight {
+ /// See [other foo][crate::subone::foo]
+ pub fn foo() {}
+ /// See [other bar][super::super::super::super::super::subtwo::bar]
+ pub fn bar() {}
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/rustdoc/issue-56701.rs b/src/test/rustdoc/issue-56701.rs
new file mode 100644
index 000000000..ba00743fc
--- /dev/null
+++ b/src/test/rustdoc/issue-56701.rs
@@ -0,0 +1,33 @@
+// This shouldn't cause a stack overflow when rustdoc is run
+
+use std::ops::Deref;
+use std::ops::DerefMut;
+
+pub trait SimpleTrait {
+ type SimpleT;
+}
+
+impl<Inner: SimpleTrait, Outer: Deref<Target = Inner>> SimpleTrait for Outer {
+ type SimpleT = Inner::SimpleT;
+}
+
+pub trait AnotherTrait {
+ type AnotherT;
+}
+
+impl<T, Simple: SimpleTrait<SimpleT = Vec<T>>> AnotherTrait for Simple {
+ type AnotherT = T;
+}
+
+pub struct Unrelated<Inner, UnrelatedT: DerefMut<Target = Vec<Inner>>>(UnrelatedT);
+
+impl<Inner, UnrelatedT: DerefMut<Target = Vec<Inner>>> Deref for Unrelated<Inner, UnrelatedT> {
+ type Target = Vec<Inner>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+
+pub fn main() { }
diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs
new file mode 100644
index 000000000..aef6ddd8d
--- /dev/null
+++ b/src/test/rustdoc/issue-56822.rs
@@ -0,0 +1,24 @@
+struct Wrapper<T>(T);
+
+trait MyTrait {
+ type Output;
+}
+
+impl<'a, I, T: 'a> MyTrait for Wrapper<I>
+ where I: MyTrait<Output=&'a T>
+{
+ type Output = T;
+}
+
+struct Inner<'a, T>(&'a T);
+
+impl<'a, T> MyTrait for Inner<'a, T> {
+ type Output = &'a T;
+}
+
+// @has issue_56822/struct.Parser.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'a> Send for Parser<'a>"
+pub struct Parser<'a> {
+ field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
+}
diff --git a/src/test/rustdoc/issue-57180.rs b/src/test/rustdoc/issue-57180.rs
new file mode 100644
index 000000000..14bd2b0fe
--- /dev/null
+++ b/src/test/rustdoc/issue-57180.rs
@@ -0,0 +1,7 @@
+// aux-build:issue-57180.rs
+
+extern crate issue_57180;
+use issue_57180::Trait;
+
+fn main() {
+}
diff --git a/src/test/rustdoc/issue-60482.rs b/src/test/rustdoc/issue-60482.rs
new file mode 100644
index 000000000..0fd1daa74
--- /dev/null
+++ b/src/test/rustdoc/issue-60482.rs
@@ -0,0 +1,9 @@
+// This code caused a panic in `pulldown-cmark` 0.4.1.
+
+pub const BASIC_UNICODE: bool = true;
+
+
+/// # `BASIC_UNICODE`: `A` `|`
+/// ```text
+/// ```
+pub const BASIC_FONTS: bool = true;
diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs
new file mode 100644
index 000000000..167f0f039
--- /dev/null
+++ b/src/test/rustdoc/issue-60726.rs
@@ -0,0 +1,35 @@
+use std::marker::PhantomData;
+
+pub struct True;
+pub struct False;
+
+pub trait InterfaceType{
+ type Send;
+}
+
+
+pub struct FooInterface<T>(PhantomData<fn()->T>);
+
+impl<T> InterfaceType for FooInterface<T> {
+ type Send=False;
+}
+
+
+pub struct DynTrait<I>{
+ _interface:PhantomData<fn()->I>,
+ _unsync_unsend:PhantomData<::std::rc::Rc<()>>,
+}
+
+unsafe impl<I> Send for DynTrait<I>
+where
+ I:InterfaceType<Send=True>
+{}
+
+// @has issue_60726/struct.IntoIter.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Send for IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Sync for IntoIter<T>"
+pub struct IntoIter<T>{
+ hello:DynTrait<FooInterface<T>>,
+}
diff --git a/src/test/rustdoc/issue-61592.rs b/src/test/rustdoc/issue-61592.rs
new file mode 100644
index 000000000..aef038c07
--- /dev/null
+++ b/src/test/rustdoc/issue-61592.rs
@@ -0,0 +1,15 @@
+// aux-build:issue-61592.rs
+
+extern crate foo;
+
+// @has issue_61592/index.html
+// @has - '//a[@href="#reexports"]' 'Re-exports'
+// @has - '//code' 'pub use foo::FooTrait as _;'
+// @!has - '//a[@href="trait._.html"]'
+pub use foo::FooTrait as _;
+
+// @has issue_61592/index.html
+// @has - '//a[@href="#reexports"]' 'Re-exports'
+// @has - '//code' 'pub use foo::FooStruct as _;'
+// @!has - '//a[@href="struct._.html"]'
+pub use foo::FooStruct as _;
diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs
new file mode 100644
index 000000000..d69b94317
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-both.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-private-items --document-hidden-items
+
+// @has issue_67851_both/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_both/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs
new file mode 100644
index 000000000..8a3cafe4c
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-hidden.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-hidden-items
+
+// @has issue_67851_hidden/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_hidden/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs
new file mode 100644
index 000000000..4e3cd8328
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-neither.rs
@@ -0,0 +1,6 @@
+// @!has issue_67851_neither/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_neither/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs
new file mode 100644
index 000000000..8addc7f3e
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-private.rs
@@ -0,0 +1,8 @@
+// compile-flags: --document-private-items
+
+// @!has issue_67851_private/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_private/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs
new file mode 100644
index 000000000..64044cfe9
--- /dev/null
+++ b/src/test/rustdoc/issue-72340.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+pub struct Body;
+
+impl Body {
+ pub fn empty() -> Self {
+ Body
+ }
+
+}
+
+impl Default for Body {
+ // @has foo/struct.Body.html '//a/@href' 'struct.Body.html#method.empty'
+
+ /// Returns [`Body::empty()`](Body::empty).
+ fn default() -> Body {
+ Body::empty()
+ }
+}
diff --git a/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs
new file mode 100644
index 000000000..2700f2370
--- /dev/null
+++ b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs
@@ -0,0 +1,14 @@
+// Regression test for ICE #73061
+
+// aux-build:issue-73061.rs
+
+extern crate issue_73061;
+
+pub struct Z;
+
+impl issue_73061::Foo for Z {
+ type X = <issue_73061::F as issue_73061::Foo>::X;
+ fn x(&self) -> Self::X {
+ issue_73061::F.x()
+ }
+}
diff --git a/src/test/rustdoc/issue-74083.rs b/src/test/rustdoc/issue-74083.rs
new file mode 100644
index 000000000..c7f5d7eaa
--- /dev/null
+++ b/src/test/rustdoc/issue-74083.rs
@@ -0,0 +1,21 @@
+use std::ops::Deref;
+
+pub struct Foo;
+
+impl Foo {
+ pub fn foo(&mut self) {}
+}
+
+// @has issue_74083/struct.Bar.html
+// @!has - '//div[@class="sidebar-links"]/a[@href="#method.foo"]' 'foo'
+pub struct Bar {
+ foo: Foo,
+}
+
+impl Deref for Bar {
+ type Target = Foo;
+
+ fn deref(&self) -> &Foo {
+ &self.foo
+ }
+}
diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs
new file mode 100644
index 000000000..ac97b94fb
--- /dev/null
+++ b/src/test/rustdoc/issue-75588.rs
@@ -0,0 +1,17 @@
+// aux-build:realcore.rs
+// aux-build:real_gimli.rs
+
+// Ensure unstably exported traits have their Implementors sections.
+
+#![crate_name = "foo"]
+#![feature(extremely_unstable_foo)]
+
+extern crate realcore;
+extern crate real_gimli;
+
+// issue #74672
+// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
+pub use realcore::Deref;
+
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
+pub use realcore::Join;
diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs
new file mode 100644
index 000000000..a90e0fea0
--- /dev/null
+++ b/src/test/rustdoc/issue-76501.rs
@@ -0,0 +1,17 @@
+// @has 'issue_76501/fn.bloop.html' '//pre' 'pub const fn bloop() -> i32'
+/// A useless function that always returns 1.
+pub const fn bloop() -> i32 {
+ 1
+}
+
+/// A struct.
+pub struct Struct {}
+
+impl Struct {
+ // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+ // 'pub const fn blurp() -> i32'
+ /// A useless function that always returns 1.
+ pub const fn blurp() -> i32 {
+ 1
+ }
+}
diff --git a/src/test/rustdoc/issue-78673.rs b/src/test/rustdoc/issue-78673.rs
new file mode 100644
index 000000000..2e4bec254
--- /dev/null
+++ b/src/test/rustdoc/issue-78673.rs
@@ -0,0 +1,24 @@
+#![crate_name = "issue_78673"]
+
+pub trait Something {}
+
+pub trait AnAmazingTrait {}
+
+impl<T: Something> AnAmazingTrait for T {}
+
+// @has 'issue_78673/struct.MyStruct.html'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+pub struct MyStruct;
+
+impl AnAmazingTrait for MyStruct {}
+
+// generic structs may have _both_ specific and blanket impls that apply
+
+// @has 'issue_78673/struct.AnotherStruct.html'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+pub struct AnotherStruct<T>(T);
+
+impl<T: Something> Something for AnotherStruct<T> {}
+impl AnAmazingTrait for AnotherStruct<()> {}
diff --git a/src/test/rustdoc/issue-78701.rs b/src/test/rustdoc/issue-78701.rs
new file mode 100644
index 000000000..e3e46468f
--- /dev/null
+++ b/src/test/rustdoc/issue-78701.rs
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+// This test ensures that if a blanket impl has the same ID as another impl, it'll
+// link to the blanket impl and not the other impl. Basically, we're checking if
+// the ID is correctly derived.
+
+// @has 'foo/struct.AnotherStruct.html'
+// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1
+// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1
+
+pub trait Something {}
+
+pub trait AnAmazingTrait {}
+
+impl<T: Something> AnAmazingTrait for T {}
+
+pub struct AnotherStruct<T>(T);
+
+impl<T: Something> Something for AnotherStruct<T> {}
+impl AnAmazingTrait for AnotherStruct<()> {}
diff --git a/src/test/rustdoc/issue-79201.rs b/src/test/rustdoc/issue-79201.rs
new file mode 100644
index 000000000..f95d79cd4
--- /dev/null
+++ b/src/test/rustdoc/issue-79201.rs
@@ -0,0 +1,41 @@
+#![feature(doc_cfg)]
+
+// @has 'issue_79201/trait.Foo.html'
+// @count - '//*[@class="stab portability"]' 6
+// @matches - '//*[@class="stab portability"]' 'crate feature foo-root'
+// @matches - '//*[@class="stab portability"]' 'crate feature foo-public-mod'
+// @matches - '//*[@class="stab portability"]' 'crate feature foo-private-mod'
+// @matches - '//*[@class="stab portability"]' 'crate feature foo-fn'
+// @matches - '//*[@class="stab portability"]' 'crate feature foo-method'
+
+pub trait Foo {}
+
+#[doc(cfg(feature = "foo-root"))]
+impl crate::Foo for usize {}
+
+#[doc(cfg(feature = "foo-public-mod"))]
+pub mod public {
+ impl crate::Foo for u8 {}
+}
+
+#[doc(cfg(feature = "foo-private-mod"))]
+mod private {
+ impl crate::Foo for u16 {}
+}
+
+#[doc(cfg(feature = "foo-const"))]
+const _: () = {
+ impl crate::Foo for u32 {}
+};
+
+#[doc(cfg(feature = "foo-fn"))]
+fn __() {
+ impl crate::Foo for u64 {}
+}
+
+#[doc(cfg(feature = "foo-method"))]
+impl dyn Foo {
+ fn __() {
+ impl crate::Foo for u128 {}
+ }
+}
diff --git a/src/test/rustdoc/issue-80233-normalize-auto-trait.rs b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs
new file mode 100644
index 000000000..515e617b4
--- /dev/null
+++ b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs
@@ -0,0 +1,37 @@
+// Regression test for issue #80233
+// Tests that we don't ICE when processing auto traits
+
+#![crate_type = "lib"]
+pub trait Trait1 {}
+
+pub trait Trait2 {
+ type Type2;
+}
+
+pub trait Trait3 {
+ type Type3;
+}
+
+impl Trait2 for Struct1 {
+ type Type2 = Struct1;
+}
+
+impl<I: Trait2> Trait2 for Vec<I> {
+ type Type2 = Vec<I::Type2>;
+}
+
+impl<T: Trait1> Trait3 for T {
+ type Type3 = Struct1;
+}
+
+impl<T: Trait3> Trait3 for Vec<T> {
+ type Type3 = Vec<T::Type3>;
+}
+
+pub struct Struct1 {}
+
+// @has issue_80233_normalize_auto_trait/struct.Question.html
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Question<T>'
+pub struct Question<T: Trait1> {
+ pub ins: <<Vec<T> as Trait3>::Type3 as Trait2>::Type2,
+}
diff --git a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
new file mode 100644
index 000000000..8999e6a88
--- /dev/null
+++ b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
@@ -0,0 +1,16 @@
+use std::convert::AsRef;
+pub struct Local;
+
+// @has issue_82465_asref_for_and_of_local/struct.Local.html '//h3[@class="code-header in-band"]' 'impl AsRef<str> for Local'
+impl AsRef<str> for Local {
+ fn as_ref(&self) -> &str {
+ todo!()
+ }
+}
+
+// @has - '//h3[@class="code-header in-band"]' 'impl AsRef<Local> for str'
+impl AsRef<Local> for str {
+ fn as_ref(&self) -> &Local {
+ todo!()
+ }
+}
diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs
new file mode 100644
index 000000000..3351b5c83
--- /dev/null
+++ b/src/test/rustdoc/issue-85454.rs
@@ -0,0 +1,29 @@
+// aux-build:issue-85454.rs
+// build-aux-docs
+#![crate_name = "foo"]
+
+extern crate issue_85454;
+
+// @has foo/trait.FromResidual.html
+// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+pub trait FromResidual<R = <Self as Try>::Residual> {
+ fn from_residual(residual: R) -> Self;
+}
+
+pub trait Try: FromResidual {
+ type Output;
+ type Residual;
+ fn from_output(output: Self::Output) -> Self;
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+pub enum ControlFlow<B, C = ()> {
+ Continue(C),
+ Break(B),
+}
+
+pub mod reexport {
+ // @has foo/reexport/trait.FromResidual.html
+ // @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+ pub use issue_85454::*;
+}
diff --git a/src/test/rustdoc/issue-86620.rs b/src/test/rustdoc/issue-86620.rs
new file mode 100644
index 000000000..ef15946ec
--- /dev/null
+++ b/src/test/rustdoc/issue-86620.rs
@@ -0,0 +1,9 @@
+// aux-build:issue-86620-1.rs
+
+extern crate issue_86620_1;
+
+use issue_86620_1::*;
+
+// @!has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip
+// @has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="anchor"]/@href' #method.vzip
+pub struct S;
diff --git a/src/test/rustdoc/issue-88600.rs b/src/test/rustdoc/issue-88600.rs
new file mode 100644
index 000000000..fc63ed343
--- /dev/null
+++ b/src/test/rustdoc/issue-88600.rs
@@ -0,0 +1,35 @@
+// This test ensure that #[doc(hidden)] is applied correctly in enum variant fields.
+
+// Denotes a field which should be hidden.
+pub struct H;
+
+// Denotes a field which should not be hidden (shown).
+pub struct S;
+
+// @has issue_88600/enum.FooEnum.html
+pub enum FooEnum {
+ // @has - '//*[@id="variant.HiddenTupleItem"]//code' 'HiddenTupleItem(_)'
+ // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0
+ HiddenTupleItem(#[doc(hidden)] H),
+ // @has - '//*[@id="variant.MultipleHidden"]//code' 'MultipleHidden(_, _)'
+ // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0
+ // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0
+ MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H),
+ // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)'
+ // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0
+ // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S'
+ MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S),
+ // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)'
+ // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S'
+ // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0
+ MixedHiddenLast(/** dox */ S, #[doc(hidden)] H),
+ // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct'
+ // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0
+ // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S'
+ HiddenStruct {
+ #[doc(hidden)]
+ h: H,
+ /// dox
+ s: S,
+ },
+}
diff --git a/src/test/rustdoc/issue-89309-heading-levels.rs b/src/test/rustdoc/issue-89309-heading-levels.rs
new file mode 100644
index 000000000..bb706c28f
--- /dev/null
+++ b/src/test/rustdoc/issue-89309-heading-levels.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+// @has foo/trait.Read.html
+// @has - '//h2' 'Trait examples'
+/// # Trait examples
+pub trait Read {
+ // @has - '//h5' 'Function examples'
+ /// # Function examples
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()>;
+}
+
+pub struct Foo;
+
+// @has foo/struct.Foo.html
+impl Foo {
+ // @has - '//h5' 'Implementation header'
+ /// # Implementation header
+ pub fn bar(&self) -> usize {
+ 1
+ }
+}
+
+impl Read for Foo {
+ // @has - '//h5' 'Trait implementation header'
+ /// # Trait implementation header
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
+ Ok(1)
+ }
+}
diff --git a/src/test/rustdoc/issue-89852.rs b/src/test/rustdoc/issue-89852.rs
new file mode 100644
index 000000000..45544dbee
--- /dev/null
+++ b/src/test/rustdoc/issue-89852.rs
@@ -0,0 +1,14 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @matches 'issue_89852/sidebar-items.js' '"repro"'
+// @!matches 'issue_89852/sidebar-items.js' '"repro".*"repro"'
+
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+pub use crate::repro as repro2;
diff --git a/src/test/rustdoc/issue-95633.rs b/src/test/rustdoc/issue-95633.rs
new file mode 100644
index 000000000..a71d0a037
--- /dev/null
+++ b/src/test/rustdoc/issue-95633.rs
@@ -0,0 +1,7 @@
+// compile-flags: --document-private-items
+
+// This ensures that no ICE is triggered when rustdoc is run on this code.
+
+mod stdlib {
+ pub (crate) use std::i8;
+}
diff --git a/src/test/rustdoc/issue-95873.rs b/src/test/rustdoc/issue-95873.rs
new file mode 100644
index 000000000..ff33fb63a
--- /dev/null
+++ b/src/test/rustdoc/issue-95873.rs
@@ -0,0 +1,2 @@
+// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
+pub use ::std as x;
diff --git a/src/test/rustdoc/issue-96381.rs b/src/test/rustdoc/issue-96381.rs
new file mode 100644
index 000000000..f0f123f85
--- /dev/null
+++ b/src/test/rustdoc/issue-96381.rs
@@ -0,0 +1,16 @@
+// should-fail
+
+#![allow(unused)]
+
+trait Foo<T>: Sized {
+ fn bar(i: i32, t: T, s: &Self) -> (T, i32);
+}
+
+impl Foo<usize> for () {
+ fn bar(i: _, t: _, s: _) -> _ {
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ (1, 2)
+ }
+}
+
+fn main() {}
diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs
new file mode 100644
index 000000000..83e08094c
--- /dev/null
+++ b/src/test/rustdoc/issue-98697.rs
@@ -0,0 +1,17 @@
+// aux-build:issue-98697-reexport-with-anonymous-lifetime.rs
+// ignore-cross-compile
+
+// When reexporting a function with a HRTB with anonymous lifetimes,
+// make sure the anonymous lifetimes are not rendered.
+//
+// https://github.com/rust-lang/rust/issues/98697
+
+extern crate issue_98697_reexport_with_anonymous_lifetime;
+
+// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)'
+// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
+pub use issue_98697_reexport_with_anonymous_lifetime::repro;
+
+// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl MyTrait<&Extra> for Extra'
+// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl<'
+pub use issue_98697_reexport_with_anonymous_lifetime::Extra;
diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs
new file mode 100644
index 000000000..e74881d38
--- /dev/null
+++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs
@@ -0,0 +1,19 @@
+// aux-build:issue-99221-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99221_aux;
+
+pub use issue_99221_aux::*;
+
+// @count foo/index.html '//a[@class="macro"]' 1
+
+mod inner {
+ #[macro_export]
+ macro_rules! print {
+ () => ()
+ }
+}
diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs
new file mode 100644
index 000000000..46d59654b
--- /dev/null
+++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs
@@ -0,0 +1,17 @@
+// aux-build:issue-99221-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99221_aux;
+
+pub use issue_99221_aux::*;
+
+// @count foo/index.html '//a[@class="macro"]' 1
+
+#[macro_export]
+macro_rules! print {
+ () => ()
+}
diff --git a/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs
new file mode 100644
index 000000000..41e64726a
--- /dev/null
+++ b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs
@@ -0,0 +1,14 @@
+// aux-build:issue-99221-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99221_aux;
+
+pub use issue_99221_aux::*;
+
+// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1
+
+pub struct Print;
diff --git a/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
new file mode 100644
index 000000000..3208fea05
--- /dev/null
+++ b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
@@ -0,0 +1,16 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+
+extern "C" {
+ pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs
new file mode 100644
index 000000000..b2f9b8b46
--- /dev/null
+++ b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs
@@ -0,0 +1,14 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+
+pub mod task {}
diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs
new file mode 100644
index 000000000..1cebe4c67
--- /dev/null
+++ b/src/test/rustdoc/keyword.rs
@@ -0,0 +1,23 @@
+#![crate_name = "foo"]
+
+#![feature(rustdoc_internals)]
+
+// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
+// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
+// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
+// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
+// @has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has foo/index.html '//a/@href' '../foo/index.html'
+// @!has foo/foo/index.html
+// @!has-dir foo/foo
+// @!has foo/index.html '//span' '🔒'
+#[doc(keyword = "match")]
+/// this is a test!
+mod foo{}
+
+// @has foo/keyword.foo.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
+#[doc(keyword = "foo")]
+/// hello
+mod bar {}
diff --git a/src/test/rustdoc/legacy-const-generic.rs b/src/test/rustdoc/legacy-const-generic.rs
new file mode 100644
index 000000000..46a50e2fc
--- /dev/null
+++ b/src/test/rustdoc/legacy-const-generic.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+#![feature(rustc_attrs)]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+
+// @has 'foo/fn.bar.html'
+// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1, 2)]
+pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
+ [x, Y, z]
+}
diff --git a/src/test/rustdoc/lifetime-name.rs b/src/test/rustdoc/lifetime-name.rs
new file mode 100644
index 000000000..5d30a745a
--- /dev/null
+++ b/src/test/rustdoc/lifetime-name.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has 'foo/type.Resolutions.html'
+// @has - '//*[@class="rust typedef"]' "pub type Resolutions<'tcx> = &'tcx u8;"
+pub type Resolutions<'tcx> = &'tcx u8;
diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs
new file mode 100644
index 000000000..29c16fcd4
--- /dev/null
+++ b/src/test/rustdoc/line-breaks.rs
@@ -0,0 +1,30 @@
+#![crate_name = "foo"]
+
+use std::ops::Add;
+use std::fmt::Display;
+
+//@count foo/fn.function_with_a_really_long_name.html //pre/br 2
+pub fn function_with_a_really_long_name(parameter_one: i32,
+ parameter_two: i32)
+ -> Option<i32> {
+ Some(parameter_one + parameter_two)
+}
+
+//@count foo/fn.short_name.html //pre/br 0
+pub fn short_name(param: i32) -> i32 { param + 1 }
+
+//@count foo/fn.where_clause.html //pre/br 4
+pub fn where_clause<T, U>(param_one: T,
+ param_two: U)
+ where T: Add<U> + Display + Copy,
+ U: Add<T> + Display + Copy,
+ T::Output: Display + Add<U::Output> + Copy,
+ <T::Output as Add<U::Output>>::Output: Display,
+ U::Output: Display + Copy
+{
+ let x = param_one + param_two;
+ println!("{} + {} = {}", param_one, param_two, x);
+ let y = param_two + param_one;
+ println!("{} + {} = {}", param_two, param_one, y);
+ println!("{} + {} = {}", x, y, x + y);
+}
diff --git a/src/test/rustdoc/link-assoc-const.rs b/src/test/rustdoc/link-assoc-const.rs
new file mode 100644
index 000000000..75a2531a3
--- /dev/null
+++ b/src/test/rustdoc/link-assoc-const.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+// @has foo/index.html '//a[@href="foo/constant.FIRSTCONST.html"]' 'foo::FIRSTCONST'
+// @has foo/index.html '//a[@href="struct.Bar.html#associatedconstant.CONST"]' 'Bar::CONST'
+
+//! We have here [`foo::FIRSTCONST`] and [`Bar::CONST`].
+
+pub mod foo {
+ pub const FIRSTCONST: u32 = 42;
+}
+
+pub struct Bar;
+
+impl Bar {
+ pub const CONST: u32 = 42;
+}
diff --git a/src/test/rustdoc/link-title-escape.rs b/src/test/rustdoc/link-title-escape.rs
new file mode 100644
index 000000000..01aa8d00b
--- /dev/null
+++ b/src/test/rustdoc/link-title-escape.rs
@@ -0,0 +1,9 @@
+#![allow(rustdoc::broken_intra_doc_links)]
+
+#![crate_name = "foo"]
+
+//! hello [foo]
+//!
+//! [foo]: url 'title & <stuff> & "things"'
+
+// @has 'foo/index.html' 'title &amp; &lt;stuff&gt; &amp; &quot;things&quot;'
diff --git a/src/test/rustdoc/logo-class-default.rs b/src/test/rustdoc/logo-class-default.rs
new file mode 100644
index 000000000..a7016d227
--- /dev/null
+++ b/src/test/rustdoc/logo-class-default.rs
@@ -0,0 +1,4 @@
+// Note: this test is paired with logo-class.rs.
+// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+// @has logo_class_default/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/logo-class.rs b/src/test/rustdoc/logo-class.rs
new file mode 100644
index 000000000..f071f356a
--- /dev/null
+++ b/src/test/rustdoc/logo-class.rs
@@ -0,0 +1,10 @@
+#![doc(html_logo_url =
+ "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")]
+// Note: this test is paired with logo-class-default.rs.
+
+// @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
+// @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+//
+// @has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
+// @!has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs
new file mode 100644
index 000000000..7576c1326
--- /dev/null
+++ b/src/test/rustdoc/macro-document-private-duplicate.rs
@@ -0,0 +1,25 @@
+// ignore-test (fails spuriously, see issue #89228)
+
+// FIXME: If two macros in the same module have the same name
+// (yes, that's a thing), rustdoc lists both of them on the index page,
+// but only documents the first one on the page for the macro.
+// Fortunately, this can only happen in document private items mode,
+// but it still isn't ideal beahvior.
+//
+// See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453
+//
+// compile-flags: --document-private-items
+
+// @has macro_document_private_duplicate/index.html 'Doc 1.'
+// @has macro_document_private_duplicate/macro.a_macro.html 'Doc 1.'
+/// Doc 1.
+macro_rules! a_macro {
+ () => ()
+}
+
+// @has macro_document_private_duplicate/index.html 'Doc 2.'
+// @!has macro_document_private_duplicate/macro.a_macro.html 'Doc 2.'
+/// Doc 2.
+macro_rules! a_macro {
+ () => ()
+}
diff --git a/src/test/rustdoc/macro-document-private.rs b/src/test/rustdoc/macro-document-private.rs
new file mode 100644
index 000000000..d2496913f
--- /dev/null
+++ b/src/test/rustdoc/macro-document-private.rs
@@ -0,0 +1,19 @@
+// Checks that private macros are documented when `--document-private-items`
+// is present.
+//
+// This is a regression test for issue #73754.
+//
+// compile-flags: --document-private-items
+
+#![feature(decl_macro)]
+
+
+// @has macro_document_private/macro.some_macro.html
+macro some_macro {
+ (a: tt) => {}
+}
+
+// @has macro_document_private/macro.another_macro.html
+macro_rules! another_macro {
+ (a: tt) => {}
+}
diff --git a/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html
new file mode 100644
index 000000000..ce5d3a846
--- /dev/null
+++ b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html
@@ -0,0 +1,6 @@
+macro_rules! linebreak {
+ (
+ <= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
+ 26 27 28 =>
+ ) => { ... };
+} \ No newline at end of file
diff --git a/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html
new file mode 100644
index 000000000..28f15522a
--- /dev/null
+++ b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html
@@ -0,0 +1,15 @@
+macro_rules! morestuff {
+ (
+ <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static
+ "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
+ "space inside curly brace" : { 2 a }
+ "no space inside empty delimiters" : () [] {}
+ "no space before comma or semicolon" : a, (a), { a }, a; [T; 0];
+ "the three repetition specifiers" : $(@)*, $(@)+, $(@)?
+ "repetition separators" : $(@)|*, $(@)|+, $(@)==*, $(@)static*
+ "plus or star cannot be a repetition separator" : $(@)+ * $(@)* +
+ "no space between ident and paren" : let _ = f(0) + f[0] + Struct {};
+ "space between keyword and paren" : return (a,) & for x in (..)
+ "some special case keywords" : pub(crate), fn() -> u8, Self(0, 0) =>
+ ) => { ... };
+} \ No newline at end of file
diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs
new file mode 100644
index 000000000..1a423cac1
--- /dev/null
+++ b/src/test/rustdoc/macro-generated-macro.rs
@@ -0,0 +1,39 @@
+macro_rules! make_macro {
+ ($macro_name:ident $($matcher:tt)*) => {
+ #[macro_export]
+ macro_rules! $macro_name {
+ (<= $($matcher)* =>) => {};
+ }
+ }
+}
+
+// @has macro_generated_macro/macro.interpolations.html //pre 'macro_rules! interpolations {'
+// @has - //pre '(<= type $($i:ident)::* + $e:expr =>) => { ... };'
+make_macro!(interpolations type $($i:ident)::* + $e:expr);
+interpolations!(<= type foo::bar + x.sort() =>);
+
+// @has macro_generated_macro/macro.attributes.html //pre 'macro_rules! attributes {'
+// @has - //pre '(<= #![no_std] #[cfg(feature = "alloc")] =>) => { ... };'
+make_macro!(attributes #![no_std] #[cfg(feature = "alloc")]);
+
+// @has macro_generated_macro/macro.groups.html //pre 'macro_rules! groups {'
+// @has - //pre '(<= fn {} () { foo[0] } =>) => { ... };'
+make_macro!(groups fn {}() {foo[0]});
+
+// @snapshot macro_linebreak_pre macro_generated_macro/macro.linebreak.html //pre/text()
+make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28);
+
+// @snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text()
+make_macro!(morestuff
+ "space between most kinds of tokens": 1 $x + @ :: >>= 'static
+ "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)*
+ "space inside curly brace": { 2 a }
+ "no space inside empty delimiters": () [] {}
+ "no space before comma or semicolon": a, (a), { a }, a; [T; 0];
+ "the three repetition specifiers": $(@)*, $(@)+, $(@)?
+ "repetition separators": $(@)|*, $(@)|+, $(@)==*, $(@)static*
+ "plus or star cannot be a repetition separator": $(@)+ * $(@)* +
+ "no space between ident and paren": let _ = f(0) + f[0] + Struct {};
+ "space between keyword and paren": return (a,) & for x in (..)
+ "some special case keywords": pub(crate), fn() -> u8, Self(0, 0)
+);
diff --git a/src/test/rustdoc/macro-higher-kinded-function.rs b/src/test/rustdoc/macro-higher-kinded-function.rs
new file mode 100644
index 000000000..02a430564
--- /dev/null
+++ b/src/test/rustdoc/macro-higher-kinded-function.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+
+pub struct TyCtxt<'tcx>(&'tcx u8);
+
+macro_rules! gen {
+ ($(($name:ident, $tcx:lifetime, [$k:ty], [$r:ty]))*) => {
+ pub struct Providers {
+ $(pub $name: for<$tcx> fn(TyCtxt<$tcx>, $k) -> $r,)*
+ }
+ }
+}
+
+// @has 'foo/struct.Providers.html'
+// @has - '//*[@class="docblock item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8,"
+// @has - '//*[@class="docblock item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16,"
+// @has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8"
+// @has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16"
+gen! {
+ (a, 'tcx, [u8], [i8])
+ (b, 'tcx, [u16], [i16])
+}
diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs
new file mode 100644
index 000000000..b4aaacf7b
--- /dev/null
+++ b/src/test/rustdoc/macro-in-async-block.rs
@@ -0,0 +1,9 @@
+// Regression issue for rustdoc ICE encountered in PR #72088.
+// edition:2018
+#![feature(decl_macro)]
+
+fn main() {
+ async {
+ macro m() {}
+ };
+}
diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs
new file mode 100644
index 000000000..b4411d927
--- /dev/null
+++ b/src/test/rustdoc/macro-in-closure.rs
@@ -0,0 +1,16 @@
+// Regression issue for rustdoc ICE encountered in PR #65252.
+
+#![feature(decl_macro)]
+
+fn main() {
+ || {
+ macro m() {}
+ };
+
+ let _ = || {
+ macro n() {}
+ };
+
+ let cond = true;
+ let _ = || if cond { macro n() {} } else { panic!() };
+}
diff --git a/src/test/rustdoc/macro-indirect-use.rs b/src/test/rustdoc/macro-indirect-use.rs
new file mode 100644
index 000000000..b2d9336cf
--- /dev/null
+++ b/src/test/rustdoc/macro-indirect-use.rs
@@ -0,0 +1,16 @@
+// Checks that it is possible to make a macro public through a `pub use` of its
+// parent module.
+//
+// This is a regression test for issue #87257.
+
+#![feature(decl_macro)]
+
+mod outer {
+ pub mod inner {
+ pub macro some_macro() {}
+ }
+}
+
+// @has macro_indirect_use/inner/index.html
+// @has macro_indirect_use/inner/macro.some_macro.html
+pub use outer::inner;
diff --git a/src/test/rustdoc/macro-private-not-documented.rs b/src/test/rustdoc/macro-private-not-documented.rs
new file mode 100644
index 000000000..ae8b0e722
--- /dev/null
+++ b/src/test/rustdoc/macro-private-not-documented.rs
@@ -0,0 +1,19 @@
+// Checks that private macros aren't documented by default. They
+// should be still be documented in `--document-private-items` mode,
+// but that's tested in `macro-document-private.rs`.
+//
+//
+// This is a regression text for issue #88453.
+#![feature(decl_macro)]
+
+// @!has macro_private_not_documented/index.html 'a_macro'
+// @!has macro_private_not_documented/macro.a_macro.html
+macro_rules! a_macro {
+ () => ()
+}
+
+// @!has macro_private_not_documented/index.html 'another_macro'
+// @!has macro_private_not_documented/macro.another_macro.html
+macro another_macro {
+ () => ()
+}
diff --git a/src/test/rustdoc/macro_pub_in_module.rs b/src/test/rustdoc/macro_pub_in_module.rs
new file mode 100644
index 000000000..4fd85d689
--- /dev/null
+++ b/src/test/rustdoc/macro_pub_in_module.rs
@@ -0,0 +1,82 @@
+// aux-build:macro_pub_in_module.rs
+// edition:2018
+// build-aux-docs
+
+//! See issue #74355
+#![feature(decl_macro, no_core, rustc_attrs)]
+#![crate_name = "krate"]
+#![no_core]
+
+ // @has external_crate/some_module/macro.external_macro.html
+ // @!has external_crate/macro.external_macro.html
+extern crate external_crate;
+
+pub mod inner {
+ // @has krate/inner/macro.raw_const.html
+ // @!has krate/macro.raw_const.html
+ pub macro raw_const() {}
+
+ // @has krate/inner/macro.test.html
+ // @!has krate/macro.test.html
+ #[rustc_builtin_macro]
+ pub macro test($item:item) {}
+
+ // @has krate/inner/macro.Clone.html
+ // @!has krate/macro.Clone.html
+ #[rustc_builtin_macro]
+ pub macro Clone($item:item) {}
+
+ // Make sure the logic is not affected by re-exports.
+ mod unrenamed {
+ // @!has krate/macro.unrenamed.html
+ #[rustc_macro_transparency = "semitransparent"]
+ pub macro unrenamed() {}
+ }
+ // @has krate/inner/macro.unrenamed.html
+ pub use unrenamed::unrenamed;
+
+ mod private {
+ // @!has krate/macro.m.html
+ pub macro m() {}
+ }
+ // @has krate/inner/macro.renamed.html
+ // @!has krate/macro.renamed.html
+ pub use private::m as renamed;
+
+ mod private2 {
+ // @!has krate/macro.m2.html
+ pub macro m2() {}
+ }
+ use private2 as renamed_mod;
+ // @has krate/inner/macro.m2.html
+ pub use renamed_mod::m2;
+
+ // @has krate/inner/macro.external_macro.html
+ // @!has krate/macro.external_macro.html
+ pub use ::external_crate::some_module::external_macro;
+}
+
+// Namespaces: Make sure the logic does not mix up a function name with a module name…
+fn both_fn_and_mod() {
+ // @!has krate/macro.in_both_fn_and_mod.html
+ pub macro in_both_fn_and_mod() {}
+}
+pub mod both_fn_and_mod {
+ // @!has krate/both_fn_and_mod/macro.in_both_fn_and_mod.html
+}
+
+const __: () = {
+ // @!has krate/macro.in_both_const_and_mod.html
+ pub macro in_both_const_and_mod() {}
+};
+pub mod __ {
+ // @!has krate/__/macro.in_both_const_and_mod.html
+}
+
+enum Enum {
+ Crazy = {
+ // @!has krate/macro.this_is_getting_weird.html;
+ pub macro this_is_getting_weird() {}
+ 42
+ },
+}
diff --git a/src/test/rustdoc/macro_rules-matchers.rs b/src/test/rustdoc/macro_rules-matchers.rs
new file mode 100644
index 000000000..efc3b21e6
--- /dev/null
+++ b/src/test/rustdoc/macro_rules-matchers.rs
@@ -0,0 +1,39 @@
+// This is a regression test for issue #86208.
+// It is also a general test of macro_rules! display.
+
+#![crate_name = "foo"]
+
+// @has 'foo/macro.todo.html'
+// @has - '//span[@class="macro"]' 'macro_rules!'
+// @has - '//span[@class="ident"]' 'todo'
+// Note: the only op is the `+`
+// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1
+
+// @has - '{ () =&gt; { ... }; ($('
+// @has - '//span[@class="macro-nonterminal"]' '$'
+// @has - '//span[@class="macro-nonterminal"]' 'arg'
+// @has - ':'
+// @has - '//span[@class="ident"]' 'tt'
+// @has - '),'
+// @has - '//span[@class="op"]' '+'
+// @has - ') =&gt; { ... }; }'
+pub use std::todo;
+
+mod mod1 {
+ // @has 'foo/macro.macro1.html'
+ // @has - 'macro_rules!'
+ // @has - 'macro1'
+ // @has - '{ () =&gt; { ... }; ($('
+ // @has - '//span[@class="macro-nonterminal"]' '$'
+ // @has - '//span[@class="macro-nonterminal"]' 'arg'
+ // @has - ':'
+ // @has - 'expr'
+ // @has - '),'
+ // @has - '+'
+ // @has - ') =&gt; { ... }; }'
+ #[macro_export]
+ macro_rules! macro1 {
+ () => {};
+ ($($arg:expr),+) => { stringify!($($arg),+) };
+ }
+}
diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs
new file mode 100644
index 000000000..ae0cf7a14
--- /dev/null
+++ b/src/test/rustdoc/macros.rs
@@ -0,0 +1,24 @@
+// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
+// @has - //pre '() => { ... };'
+// @has - //pre '($a:tt) => { ... };'
+// @has - //pre '($e:expr) => { ... };'
+#[macro_export]
+macro_rules! my_macro {
+ () => [];
+ ($a:tt) => ();
+ ($e:expr) => {};
+}
+
+// Check that exported macro defined in a module are shown at crate root.
+// @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {'
+// @has - //pre '() => { ... };'
+// @has - //pre '($a:tt) => { ... };'
+// @has - //pre '($e:expr) => { ... };'
+mod sub {
+ #[macro_export]
+ macro_rules! my_sub_macro {
+ () => {};
+ ($a:tt) => {};
+ ($e:expr) => {};
+ }
+}
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
new file mode 100644
index 000000000..b2ee077bc
--- /dev/null
+++ b/src/test/rustdoc/manual_impl.rs
@@ -0,0 +1,77 @@
+// @has manual_impl/trait.T.html
+// @has - '//*[@class="docblock"]' 'Docs associated with the trait definition.'
+// @has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+/// Docs associated with the trait definition.
+pub trait T {
+ /// Docs associated with the trait a_method definition.
+ fn a_method(&self) -> usize;
+
+ /// Docs associated with the trait b_method definition.
+ fn b_method(&self) -> usize {
+ self.a_method()
+ }
+
+ /// Docs associated with the trait c_method definition.
+ ///
+ /// There is another line
+ fn c_method(&self) -> usize {
+ self.a_method()
+ }
+}
+
+// @has manual_impl/struct.S1.html '//*[@class="trait"]' 'T'
+// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
+// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
+// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @!has - '//*[@class="docblock"]' 'There is another line'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more'
+pub struct S1(usize);
+
+/// Docs associated with the S1 trait implementation.
+impl T for S1 {
+ /// Docs associated with the S1 trait a_method implementation.
+ fn a_method(&self) -> usize {
+ self.0
+ }
+}
+
+// @has manual_impl/struct.S2.html '//*[@class="trait"]' 'T'
+// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
+// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
+// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+pub struct S2(usize);
+
+/// Docs associated with the S2 trait implementation.
+impl T for S2 {
+ /// Docs associated with the S2 trait a_method implementation.
+ fn a_method(&self) -> usize {
+ self.0
+ }
+
+ /// Docs associated with the S2 trait c_method implementation.
+ fn c_method(&self) -> usize {
+ 5
+ }
+}
+
+// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+pub struct S3(usize);
+
+/// Docs associated with the S3 trait implementation.
+impl T for S3 {
+ fn a_method(&self) -> usize {
+ self.0
+ }
+
+ /// Docs associated with the S3 trait b_method implementation.
+ fn b_method(&self) -> usize {
+ 5
+ }
+}
diff --git a/src/test/rustdoc/markdown-summaries.rs b/src/test/rustdoc/markdown-summaries.rs
new file mode 100644
index 000000000..b843e28e7
--- /dev/null
+++ b/src/test/rustdoc/markdown-summaries.rs
@@ -0,0 +1,27 @@
+#![crate_type = "lib"]
+#![crate_name = "summaries"]
+
+//! This *summary* has a [link] and `code`.
+//!
+//! This is the second paragraph.
+//!
+//! [link]: https://example.com
+
+// @has search-index.js 'This <em>summary</em> has a link and <code>code</code>.'
+// @!has - 'second paragraph'
+
+/// This `code` will be rendered in a code tag.
+///
+/// This text should not be rendered.
+pub struct Sidebar;
+
+// @has search-index.js 'This <code>code</code> will be rendered in a code tag.'
+// @has summaries/sidebar-items.js 'This `code` will be rendered in a code tag.'
+// @!has - 'text should not be rendered'
+
+/// ```text
+/// this block should not be rendered
+/// ```
+pub struct Sidebar2;
+
+// @!has summaries/sidebar-items.js 'block should not be rendered'
diff --git a/src/test/rustdoc/masked.rs b/src/test/rustdoc/masked.rs
new file mode 100644
index 000000000..c7ad690d6
--- /dev/null
+++ b/src/test/rustdoc/masked.rs
@@ -0,0 +1,30 @@
+// aux-build:masked.rs
+
+#![feature(doc_masked)]
+
+#![crate_name = "foo"]
+
+#[doc(masked)]
+extern crate masked;
+
+// @!has 'search-index.js' 'masked_method'
+
+// @!has 'foo/struct.String.html' 'MaskedTrait'
+// @!has 'foo/struct.String.html' 'masked_method'
+pub use std::string::String;
+
+// @!has 'foo/trait.Clone.html' 'MaskedStruct'
+pub use std::clone::Clone;
+
+// @!has 'foo/struct.MyStruct.html' 'MaskedTrait'
+// @!has 'foo/struct.MyStruct.html' 'masked_method'
+pub struct MyStruct;
+
+impl masked::MaskedTrait for MyStruct {
+ fn masked_method() {}
+}
+
+// @!has 'foo/trait.MyTrait.html' 'MaskedStruct'
+pub trait MyTrait {}
+
+impl MyTrait for masked::MaskedStruct {}
diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs
new file mode 100644
index 000000000..50f4af3aa
--- /dev/null
+++ b/src/test/rustdoc/method-list.rs
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="sidebar-elems"]//section//a' 'super_long_name'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Disp'
+pub struct Foo(usize);
+
+impl Foo {
+ pub fn super_long_name() {}
+}
+
+pub trait Disp {
+ fn disp_trait_method();
+}
+
+impl Disp for Foo {
+ fn disp_trait_method() {}
+}
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
new file mode 100644
index 000000000..8ff114b99
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
+Hello again!</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
new file mode 100644
index 000000000..8ff114b99
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
+Hello again!</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html
new file mode 100644
index 000000000..a4ee4b141
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html
@@ -0,0 +1,3 @@
+<div class="docblock"><p>Par 1</p>
+<p>Par 2</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.rs b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
new file mode 100644
index 000000000..a27c5ae6d
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
@@ -0,0 +1,25 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.S1.html'
+// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+
+#[doc = "Hello world!\n\n"]
+/// Goodbye!
+#[doc = " Hello again!\n"]
+pub struct S1;
+
+// @has 'foo/struct.S2.html'
+// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+
+/// Hello world!
+///
+#[doc = "Goodbye!"]
+/// Hello again!
+pub struct S2;
+
+// @has 'foo/struct.S3.html'
+// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+/** Par 1
+*/ ///
+/// Par 2
+pub struct S3;
diff --git a/src/test/rustdoc/mod-stackoverflow.rs b/src/test/rustdoc/mod-stackoverflow.rs
new file mode 100644
index 000000000..45b1de216
--- /dev/null
+++ b/src/test/rustdoc/mod-stackoverflow.rs
@@ -0,0 +1,6 @@
+// aux-build:mod-stackoverflow.rs
+// ignore-cross-compile
+
+extern crate mod_stackoverflow;
+pub use mod_stackoverflow::tree;
+pub use mod_stackoverflow::tree2;
diff --git a/src/test/rustdoc/module-impls.rs b/src/test/rustdoc/module-impls.rs
new file mode 100644
index 000000000..198b3446c
--- /dev/null
+++ b/src/test/rustdoc/module-impls.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+pub use std::marker::Send;
+
+// @!has foo/index.html 'Implementations'
diff --git a/src/test/rustdoc/must_implement_one_of.rs b/src/test/rustdoc/must_implement_one_of.rs
new file mode 100644
index 000000000..1f1dd5d57
--- /dev/null
+++ b/src/test/rustdoc/must_implement_one_of.rs
@@ -0,0 +1,10 @@
+#![crate_name = "c"]
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, b)]
+// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \
+// 'At least one of the `a`, `b` methods is required.$'
+pub trait Trait {
+ fn a() {}
+ fn b() {}
+}
diff --git a/src/test/rustdoc/mut-params.rs b/src/test/rustdoc/mut-params.rs
new file mode 100644
index 000000000..f3ea69958
--- /dev/null
+++ b/src/test/rustdoc/mut-params.rs
@@ -0,0 +1,18 @@
+// Rustdoc shouldn't display `mut` in function arguments, which are
+// implementation details. Regression test for #81289.
+
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
+// @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
+impl Foo {
+ pub fn foo(mut self) {}
+
+ pub fn bar(mut bar: ()) {}
+}
+
+// @count foo/fn.baz.html '//*[@class="rust fn"]' 1
+// @!has - '//*[@class="rust fn"]' 'mut'
+pub fn baz(mut foo: Foo) {}
diff --git a/src/test/rustdoc/namespaces.rs b/src/test/rustdoc/namespaces.rs
new file mode 100644
index 000000000..ad828e5ee
--- /dev/null
+++ b/src/test/rustdoc/namespaces.rs
@@ -0,0 +1,16 @@
+// issue #34843: rustdoc prioritises documenting reexports from the type namespace
+
+mod inner {
+ pub mod sync {
+ pub struct SomeStruct;
+ }
+
+ pub fn sync() {}
+}
+
+// @has namespaces/sync/index.html
+// @has namespaces/fn.sync.html
+// @has namespaces/index.html '//a/@href' 'sync/index.html'
+// @has - '//a/@href' 'fn.sync.html'
+#[doc(inline)]
+pub use inner::sync;
diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs
new file mode 100644
index 000000000..b995fff1f
--- /dev/null
+++ b/src/test/rustdoc/negative-impl-sidebar.rs
@@ -0,0 +1,9 @@
+#![feature(negative_impls)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations'
+// @has - '//*[@class="sidebar-elems"]//section//a' '!Sync'
+impl !Sync for Foo {}
diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs
new file mode 100644
index 000000000..61a239868
--- /dev/null
+++ b/src/test/rustdoc/negative-impl.rs
@@ -0,0 +1,14 @@
+#![feature(negative_impls)]
+
+// @matches negative_impl/struct.Alpha.html '//pre' "pub struct Alpha"
+pub struct Alpha;
+// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
+pub struct Bravo<B>(B);
+
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl !Send for Alpha"
+impl !Send for Alpha {}
+
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' "\
+// impl<B> !Send for Bravo<B>"
+impl<B> !Send for Bravo<B> {}
diff --git a/src/test/rustdoc/nested-modules.rs b/src/test/rustdoc/nested-modules.rs
new file mode 100644
index 000000000..1596f4674
--- /dev/null
+++ b/src/test/rustdoc/nested-modules.rs
@@ -0,0 +1,42 @@
+#![crate_name = "aCrate"]
+
+mod a_module {
+ pub fn private_function() {}
+
+ pub use a_module::private_function as other_private_function;
+
+ pub mod a_nested_module {
+ // @has aCrate/a_nested_module/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+ // @has aCrate/a_nested_module/fn.a_nested_public_function.html 'pub fn a_nested_public_function()'
+ pub fn a_nested_public_function() {}
+
+ // @has aCrate/a_nested_module/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+ // @has aCrate/a_nested_module/fn.another_nested_public_function.html 'pub fn another_nested_public_function()'
+ pub use a_nested_module::a_nested_public_function as another_nested_public_function;
+ }
+
+ // @!has aCrate/a_nested_module/index.html 'yet_another_nested_public_function'
+ pub use a_nested_module::a_nested_public_function as yet_another_nested_public_function;
+
+ // @!has aCrate/a_nested_module/index.html 'one_last_nested_public_function'
+ pub use a_nested_module::another_nested_public_function as one_last_nested_public_function;
+}
+
+// @!has aCrate/index.html 'a_module'
+// @has aCrate/index.html '//a[@href="a_nested_module/index.html"]' 'a_nested_module'
+pub use a_module::a_nested_module;
+
+// @has aCrate/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.yet_another_nested_public_function.html"]' 'yet_another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.one_last_nested_public_function.html"]' 'one_last_nested_public_function'
+pub use a_module::{
+ a_nested_module::{a_nested_public_function, another_nested_public_function},
+ one_last_nested_public_function, yet_another_nested_public_function,
+};
+
+// @has aCrate/index.html '//a[@href="fn.private_function.html"]' 'private_function'
+// @!has aCrate/fn.private_function.html 'a_module'
+// @has aCrate/index.html '//a[@href="fn.other_private_function.html"]' 'other_private_function'
+// @!has aCrate/fn.other_private_function.html 'a_module'
+pub use a_module::{other_private_function, private_function};
diff --git a/src/test/rustdoc/no-compiler-reexport.rs b/src/test/rustdoc/no-compiler-reexport.rs
new file mode 100644
index 000000000..d28fdf87b
--- /dev/null
+++ b/src/test/rustdoc/no-compiler-reexport.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Z unstable-options --document-hidden-items --document-private-items
+
+#![crate_name = "foo"]
+
+// @!has 'foo/index.html' '//code' 'extern crate std;'
+// @!has 'foo/index.html' '//code' 'use std::prelude'
+pub struct Foo;
diff --git a/src/test/rustdoc/no-crate-filter.rs b/src/test/rustdoc/no-crate-filter.rs
new file mode 100644
index 000000000..c694d1456
--- /dev/null
+++ b/src/test/rustdoc/no-crate-filter.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// compile-flags: -Z unstable-options --disable-per-crate-search
+
+// @!has 'foo/struct.Foo.html' '//*[id="crate-search"]'
+pub struct Foo;
diff --git a/src/test/rustdoc/no-run-still-checks-lints.rs b/src/test/rustdoc/no-run-still-checks-lints.rs
new file mode 100644
index 000000000..9f7d1c884
--- /dev/null
+++ b/src/test/rustdoc/no-run-still-checks-lints.rs
@@ -0,0 +1,9 @@
+// compile-flags:--test
+// should-fail
+
+#![doc(test(attr(deny(warnings))))]
+
+/// ```no_run
+/// let a = 3;
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc/no-stack-overflow-25295.rs b/src/test/rustdoc/no-stack-overflow-25295.rs
new file mode 100644
index 000000000..dd79f1e4b
--- /dev/null
+++ b/src/test/rustdoc/no-stack-overflow-25295.rs
@@ -0,0 +1,35 @@
+// Ensure this code doesn't stack overflow.
+// aux-build:enum-primitive.rs
+
+#[macro_use] extern crate enum_primitive;
+
+enum_from_primitive! {
+ pub enum Test {
+ A1,A2,A3,A4,A5,A6,
+ B1,B2,B3,B4,B5,B6,
+ C1,C2,C3,C4,C5,C6,
+ D1,D2,D3,D4,D5,D6,
+ E1,E2,E3,E4,E5,E6,
+ F1,F2,F3,F4,F5,F6,
+ G1,G2,G3,G4,G5,G6,
+ H1,H2,H3,H4,H5,H6,
+ I1,I2,I3,I4,I5,I6,
+ J1,J2,J3,J4,J5,J6,
+ K1,K2,K3,K4,K5,K6,
+ L1,L2,L3,L4,L5,L6,
+ M1,M2,M3,M4,M5,M6,
+ N1,N2,N3,N4,N5,N6,
+ O1,O2,O3,O4,O5,O6,
+ P1,P2,P3,P4,P5,P6,
+ Q1,Q2,Q3,Q4,Q5,Q6,
+ R1,R2,R3,R4,R5,R6,
+ S1,S2,S3,S4,S5,S6,
+ T1,T2,T3,T4,T5,T6,
+ U1,U2,U3,U4,U5,U6,
+ V1,V2,V3,V4,V5,V6,
+ W1,W2,W3,W4,W5,W6,
+ X1,X2,X3,X4,X5,X6,
+ Y1,Y2,Y3,Y4,Y5,Y6,
+ Z1,Z2,Z3,Z4,Z5,Z6,
+ }
+}
diff --git a/src/test/rustdoc/no_std-primitive.rs b/src/test/rustdoc/no_std-primitive.rs
new file mode 100644
index 000000000..22fd392dd
--- /dev/null
+++ b/src/test/rustdoc/no_std-primitive.rs
@@ -0,0 +1,6 @@
+#![no_std]
+
+/// Link to [intra-doc link][u8]
+// @has 'no_std_primitive/fn.foo.html' '//a[@href="{{channel}}/core/primitive.u8.html"]' 'intra-doc link'
+// @has - '//a[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
+pub fn foo() -> u8 {}
diff --git a/src/test/rustdoc/normalize-assoc-item.rs b/src/test/rustdoc/normalize-assoc-item.rs
new file mode 100644
index 000000000..ad1a868ee
--- /dev/null
+++ b/src/test/rustdoc/normalize-assoc-item.rs
@@ -0,0 +1,69 @@
+// ignore-tidy-linelength
+// aux-build:normalize-assoc-item.rs
+// build-aux-docs
+// compile-flags:-Znormalize-docs
+
+pub trait Trait {
+ type X;
+}
+
+impl Trait for usize {
+ type X = isize;
+}
+
+// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust fn"]' 'pub fn f() -> isize'
+pub fn f() -> <usize as Trait>::X {
+ 0
+}
+
+pub struct S {
+ // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.box_me_up"]' 'box_me_up: Box<S, Global>'
+ pub box_me_up: <S as Trait>::X,
+ // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.generic"]' 'generic: (usize, isize)'
+ pub generic: <Generic<usize> as Trait>::X,
+}
+
+impl Trait for S {
+ type X = Box<S>;
+}
+
+pub struct Generic<Inner>(Inner);
+
+impl<Inner: Trait> Trait for Generic<Inner> {
+ type X = (Inner, Inner::X);
+}
+
+// These can't be normalized because they depend on a generic parameter.
+// However the user can choose whether the text should be displayed as `Inner::X` or `<Inner as Trait>::X`.
+
+// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust struct"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
+pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);
+
+// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust struct"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
+pub struct Unknown2<Inner: Trait>(pub Inner::X);
+
+trait Lifetimes<'a> {
+ type Y;
+}
+
+impl<'a> Lifetimes<'a> for usize {
+ type Y = &'a isize;
+}
+
+// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust fn"]' "pub fn g() -> &isize"
+pub fn g() -> <usize as Lifetimes<'static>>::Y {
+ &0
+}
+
+// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust const"]' "pub const A: &isize"
+pub const A: <usize as Lifetimes<'static>>::Y = &0;
+
+// test cross-crate re-exports
+extern crate inner;
+// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust fn"]' "pub fn foo() -> i32"
+pub use inner::foo;
+
+// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust fn"]' "pub fn h<T>() -> IntoIter<T, Global>"
+pub fn h<T>() -> <Vec<T> as IntoIterator>::IntoIter {
+ vec![].into_iter()
+}
diff --git a/src/test/rustdoc/nul-error.rs b/src/test/rustdoc/nul-error.rs
new file mode 100644
index 000000000..3d30f5f6b
--- /dev/null
+++ b/src/test/rustdoc/nul-error.rs
@@ -0,0 +1,8 @@
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html '//code' ''
+#[doc = "Attempted to pass a string containing `\0`"]
+pub fn foo() {}
diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs
new file mode 100644
index 000000000..69c896265
--- /dev/null
+++ b/src/test/rustdoc/playground-arg.rs
@@ -0,0 +1,13 @@
+// compile-flags: --playground-url=https://example.com/ -Z unstable-options
+
+#![crate_name = "foo"]
+
+//! ```
+//! use foo::dummy;
+//! dummy();
+//! ```
+
+pub fn dummy() {}
+
+// ensure that `extern crate foo;` was inserted into code snips automatically:
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
diff --git a/src/test/rustdoc/playground-empty.rs b/src/test/rustdoc/playground-empty.rs
new file mode 100644
index 000000000..7d8bd3ffe
--- /dev/null
+++ b/src/test/rustdoc/playground-empty.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+#![doc(html_playground_url = "")]
+
+// compile-flags:-Z unstable-options --playground-url https://play.rust-lang.org/
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/rustdoc/playground-none.rs b/src/test/rustdoc/playground-none.rs
new file mode 100644
index 000000000..ff51c68d8
--- /dev/null
+++ b/src/test/rustdoc/playground-none.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/rustdoc/playground-syntax-error.rs b/src/test/rustdoc/playground-syntax-error.rs
new file mode 100644
index 000000000..8918ae874
--- /dev/null
+++ b/src/test/rustdoc/playground-syntax-error.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+#![doc(html_playground_url = "https://play.rust-lang.org/")]
+
+/// bar docs
+///
+/// ```edition2015
+/// use std::future::Future;
+/// use std::pin::Pin;
+/// fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
+/// Box::pin(async move {
+/// if n > 0 {
+/// foo_recursive(n - 1).await;
+/// }
+/// })
+/// }
+/// ```
+pub fn bar() {}
+
+// @has foo/fn.bar.html
+// @has - '//a[@class="test-arrow"]' "Run"
+// @has - '//*[@class="docblock"]' 'foo_recursive'
diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs
new file mode 100644
index 000000000..877ea1cfb
--- /dev/null
+++ b/src/test/rustdoc/playground.rs
@@ -0,0 +1,27 @@
+#![crate_name = "foo"]
+
+#![doc(html_playground_url = "https://www.example.com/")]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+//!
+//! ```
+//! fn main() {
+//! println!("Hello, world!");
+//! }
+//! ```
+//!
+//! ```
+//! #![feature(something)]
+//!
+//! fn main() {
+//! println!("Hello, world!");
+//! }
+//! ```
+
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run"
diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs
new file mode 100644
index 000000000..125e0c849
--- /dev/null
+++ b/src/test/rustdoc/primitive-link.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str'
+
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+
+/// It contains [`u32`] and [i64].
+/// It also links to [std::primitive::i32], [std::primitive::str],
+/// and [`std::primitive::i32::MAX`].
+pub struct Foo;
diff --git a/src/test/rustdoc/primitive-reexport.rs b/src/test/rustdoc/primitive-reexport.rs
new file mode 100644
index 000000000..10a8a47db
--- /dev/null
+++ b/src/test/rustdoc/primitive-reexport.rs
@@ -0,0 +1,28 @@
+// aux-build: primitive-reexport.rs
+// compile-flags:--extern foo --edition 2018
+
+#![crate_name = "bar"]
+
+// @has bar/p/index.html
+// @has - '//code' 'pub use bool;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
+// @has - '//code' 'pub use char as my_char;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub mod p {
+ pub use foo::bar::*;
+}
+
+// @has bar/baz/index.html
+// @has - '//code' 'pub use bool;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
+// @has - '//code' 'pub use char as my_char;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub use foo::bar as baz;
+
+// @has bar/index.html
+// @has - '//code' 'pub use str;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str'
+// @has - '//code' 'pub use i32 as my_i32;'
+// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32'
+pub use str;
+pub use i32 as my_i32;
diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs
new file mode 100644
index 000000000..b3f511bc1
--- /dev/null
+++ b/src/test/rustdoc/primitive-slice-auto-trait.rs
@@ -0,0 +1,14 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
+// @has - '//span[@class="in-band"]' 'Primitive Type slice'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+#[doc(primitive = "slice")]
+/// this is a test!
+mod slice_prim {}
diff --git a/src/test/rustdoc/primitive-tuple-auto-trait.rs b/src/test/rustdoc/primitive-tuple-auto-trait.rs
new file mode 100644
index 000000000..a2fbbf078
--- /dev/null
+++ b/src/test/rustdoc/primitive-tuple-auto-trait.rs
@@ -0,0 +1,22 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
+// @has - '//span[@class="in-band"]' 'Primitive Type tuple'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Sync'
+#[doc(primitive = "tuple")]
+/// this is a test!
+///
+// Hardcoded anchor to header written in library/core/src/primitive_docs.rs
+// @has - '//h2[@id="trait-implementations-1"]' 'Trait implementations'
+/// # Trait implementations
+///
+/// This header is hard-coded in the HTML format linking for `#[doc(fake_variadics)]`.
+/// To make sure it gets linked correctly, we need to make sure the hardcoded anchor
+/// in the code matches what rustdoc generates for the header.
+mod tuple_prim {}
diff --git a/src/test/rustdoc/primitive-tuple-variadic.rs b/src/test/rustdoc/primitive-tuple-variadic.rs
new file mode 100644
index 000000000..db7cfd60c
--- /dev/null
+++ b/src/test/rustdoc/primitive-tuple-variadic.rs
@@ -0,0 +1,18 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+pub trait Foo {}
+
+// @has foo/trait.Foo.html
+// @has - '//section[@id="impl-Foo-for-(T%2C)"]/h3' 'impl<T> Foo for (T₁, T₂, …, Tₙ)'
+#[doc(fake_variadic)]
+impl<T> Foo for (T,) {}
+
+pub trait Bar {}
+
+// @has foo/trait.Bar.html
+// @has - '//section[@id="impl-Bar-for-(U%2C)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
+#[doc(fake_variadic)]
+impl<U: Foo> Bar for (U,) {}
diff --git a/src/test/rustdoc/primitive-unit-auto-trait.rs b/src/test/rustdoc/primitive-unit-auto-trait.rs
new file mode 100644
index 000000000..76182622e
--- /dev/null
+++ b/src/test/rustdoc/primitive-unit-auto-trait.rs
@@ -0,0 +1,14 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
+// @has - '//span[@class="in-band"]' 'Primitive Type unit'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()'
+#[doc(primitive = "unit")]
+/// this is a test!
+mod unit_prim {}
diff --git a/src/test/rustdoc/primitive.rs b/src/test/rustdoc/primitive.rs
new file mode 100644
index 000000000..605ca4d17
--- /dev/null
+++ b/src/test/rustdoc/primitive.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+
+#![feature(rustdoc_internals)]
+
+// @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types'
+// @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
+// @has foo/primitive.i32.html '//a[@class="primitive"]' 'i32'
+// @has foo/primitive.i32.html '//span[@class="in-band"]' 'Primitive Type i32'
+// @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has foo/index.html '//a/@href' '../foo/index.html'
+// @!has foo/index.html '//span' '🔒'
+#[doc(primitive = "i32")]
+/// this is a test!
+mod i32{}
+
+// @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
+#[doc(primitive = "bool")]
+/// hello
+mod bool {}
diff --git a/src/test/rustdoc/primitive/no_std.rs b/src/test/rustdoc/primitive/no_std.rs
new file mode 100644
index 000000000..f0f70cb6c
--- /dev/null
+++ b/src/test/rustdoc/primitive/no_std.rs
@@ -0,0 +1,16 @@
+#![no_std]
+#![deny(warnings)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
+// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link'
+/// Link to [primitive link][u8]
+pub fn foo() -> u8 {}
+
+// Test that all primitives can be linked to.
+/// [isize] [i8] [i16] [i32] [i64] [i128]
+/// [usize] [u8] [u16] [u32] [u64] [u128]
+/// [f32] [f64]
+/// [char] [bool] [str] [slice] [array] [tuple] [unit]
+/// [pointer] [reference] [fn] [never]
+pub fn bar() {}
diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs
new file mode 100644
index 000000000..eebb2cf5a
--- /dev/null
+++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs
@@ -0,0 +1,8 @@
+#![feature(rustdoc_internals)]
+#![crate_name = "foo"]
+
+// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+
+#[doc(primitive = "i32")]
+/// Some useless docs, wouhou!
+mod i32 {}
diff --git a/src/test/rustdoc/private-type-alias.rs b/src/test/rustdoc/private-type-alias.rs
new file mode 100644
index 000000000..ec7385404
--- /dev/null
+++ b/src/test/rustdoc/private-type-alias.rs
@@ -0,0 +1,31 @@
+type MyResultPriv<T> = Result<T, u16>;
+pub type MyResultPub<T> = Result<T, u64>;
+
+// @has private_type_alias/fn.get_result_priv.html '//pre' 'Result<u8, u16>'
+pub fn get_result_priv() -> MyResultPriv<u8> {
+ panic!();
+}
+
+// @has private_type_alias/fn.get_result_pub.html '//pre' 'MyResultPub<u32>'
+pub fn get_result_pub() -> MyResultPub<u32> {
+ panic!();
+}
+
+pub type PubRecursive = u16;
+type PrivRecursive3 = u8;
+type PrivRecursive2 = PubRecursive;
+type PrivRecursive1 = PrivRecursive3;
+
+// PrivRecursive1 is expanded twice and stops at u8
+// PrivRecursive2 is expanded once and stops at public type alias PubRecursive
+// @has private_type_alias/fn.get_result_recursive.html '//pre' '(u8, PubRecursive)'
+pub fn get_result_recursive() -> (PrivRecursive1, PrivRecursive2) {
+ panic!();
+}
+
+type MyLifetimePriv<'a> = &'a isize;
+
+// @has private_type_alias/fn.get_lifetime_priv.html '//pre' "&'static isize"
+pub fn get_lifetime_priv() -> MyLifetimePriv<'static> {
+ panic!();
+}
diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs
new file mode 100644
index 000000000..10acb7ac4
--- /dev/null
+++ b/src/test/rustdoc/proc-macro.rs
@@ -0,0 +1,72 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro --document-private-items
+
+#![crate_type="proc-macro"]
+#![crate_name="some_macros"]
+
+// @has some_macros/index.html
+// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
+
+//! include a link to [some_proc_macro!] to make sure it works.
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+// @has some_macros/index.html
+// @has - '//h2' 'Macros'
+// @has - '//h2' 'Attribute Macros'
+// @has - '//h2' 'Derive Macros'
+// @!has - '//h2' 'Functions'
+
+// @has some_macros/all.html
+// @has - '//a[@href="macro.some_proc_macro.html"]' 'some_proc_macro'
+// @has - '//a[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
+// @has - '//a[@href="derive.SomeDerive.html"]' 'SomeDerive'
+// @!has - '//a/@href' 'fn.some_proc_macro.html'
+// @!has - '//a/@href' 'fn.some_proc_attr.html'
+// @!has - '//a/@href' 'fn.some_derive.html'
+
+// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html'
+// @!has - '//a/@href' 'fn.some_proc_macro.html'
+// @has some_macros/macro.some_proc_macro.html
+// @!has some_macros/fn.some_proc_macro.html
+/// a proc-macro that swallows its input and does nothing.
+#[proc_macro]
+pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html'
+// @!has - '//a/@href' 'fn.some_proc_attr.html'
+// @has some_macros/attr.some_proc_attr.html
+// @!has some_macros/fn.some_proc_attr.html
+/// a proc-macro attribute that passes its item through verbatim.
+#[proc_macro_attribute]
+pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ item
+}
+
+// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html'
+// @!has - '//a/@href' 'fn.some_derive.html'
+// @has some_macros/derive.SomeDerive.html
+// @!has some_macros/fn.some_derive.html
+/// a derive attribute that adds nothing to its input.
+#[proc_macro_derive(SomeDerive)]
+pub fn some_derive(_item: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+// @has some_macros/foo/index.html
+mod foo {
+ // @has - '//code' 'pub use some_proc_macro;'
+ // @has - '//a/@href' '../macro.some_proc_macro.html'
+ pub use some_proc_macro;
+ // @has - '//code' 'pub use some_proc_attr;'
+ // @has - '//a/@href' '../attr.some_proc_attr.html'
+ pub use some_proc_attr;
+ // @has - '//code' 'pub use some_derive;'
+ // @has - '//a/@href' '../derive.SomeDerive.html'
+ pub use some_derive;
+}
diff --git a/src/test/rustdoc/process-termination.rs b/src/test/rustdoc/process-termination.rs
new file mode 100644
index 000000000..32258792b
--- /dev/null
+++ b/src/test/rustdoc/process-termination.rs
@@ -0,0 +1,24 @@
+// compile-flags:--test
+
+/// A check of using various process termination strategies
+///
+/// # Examples
+///
+/// ```rust
+/// assert!(true); // this returns `()`, all is well
+/// ```
+///
+/// You can also simply return `Ok(())`, but you'll need to disambiguate the
+/// type using turbofish, because we cannot infer the type:
+///
+/// ```rust
+/// Ok::<(), &'static str>(())
+/// ```
+///
+/// You can err with anything that implements `Debug`:
+///
+/// ```rust,should_panic
+/// Err("This is returned from `main`, leading to panic")?;
+/// Ok::<(), &'static str>(())
+/// ```
+pub fn check_process_termination() {}
diff --git a/src/test/rustdoc/pub-extern-crate.rs b/src/test/rustdoc/pub-extern-crate.rs
new file mode 100644
index 000000000..26747a4d1
--- /dev/null
+++ b/src/test/rustdoc/pub-extern-crate.rs
@@ -0,0 +1,9 @@
+// aux-build:pub-extern-crate.rs
+
+// @has pub_extern_crate/index.html
+// @!has - '//code' 'pub extern crate inner'
+// @has - '//a/@href' 'inner/index.html'
+// @has pub_extern_crate/inner/index.html
+// @has pub_extern_crate/inner/struct.SomeStruct.html
+#[doc(inline)]
+pub extern crate inner;
diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs
new file mode 100644
index 000000000..fa7de0aff
--- /dev/null
+++ b/src/test/rustdoc/pub-method.rs
@@ -0,0 +1,20 @@
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub fn bar() -> '
+/// foo
+pub fn bar() -> usize {
+ 2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
+// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
+pub struct Foo(usize);
+
+impl Foo {
+ pub fn new() -> Foo { Foo(0) }
+ fn not_pub() {}
+}
diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs
new file mode 100644
index 000000000..eefe6b4b0
--- /dev/null
+++ b/src/test/rustdoc/pub-use-extern-macros.rs
@@ -0,0 +1,17 @@
+// aux-build:pub-use-extern-macros.rs
+
+extern crate macros;
+
+// @has pub_use_extern_macros/macro.bar.html
+// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::bar;'
+pub use macros::bar;
+
+// @has pub_use_extern_macros/macro.baz.html
+// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::baz;'
+#[doc(inline)]
+pub use macros::baz;
+
+// @!has pub_use_extern_macros/macro.quux.html
+// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::quux;'
+#[doc(hidden)]
+pub use macros::quux;
diff --git a/src/test/rustdoc/range-arg-pattern.rs b/src/test/rustdoc/range-arg-pattern.rs
new file mode 100644
index 000000000..756939ae3
--- /dev/null
+++ b/src/test/rustdoc/range-arg-pattern.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)'
+pub fn f(0u8..=255: u8) {}
diff --git a/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs
new file mode 100644
index 000000000..7dbe63854
--- /dev/null
+++ b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs
@@ -0,0 +1,21 @@
+#![crate_type="lib"]
+
+pub mod internal {
+ // @has 'raw_ident_eliminate_r_hashtag/internal/struct.mod.html'
+ #[allow(non_camel_case_types)]
+ pub struct r#mod;
+
+ /// See [name], [other name]
+ ///
+ /// [name]: mod
+ /// [other name]: crate::internal::mod
+ // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'name'
+ // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'other name'
+ pub struct B;
+}
+
+/// See [name].
+///
+/// [name]: internal::mod
+// @has 'raw_ident_eliminate_r_hashtag/struct.A.html' '//*a[@href="internal/struct.mod.html"]' 'name'
+pub struct A;
diff --git a/src/test/rustdoc/recursion1.rs b/src/test/rustdoc/recursion1.rs
new file mode 100644
index 000000000..edf7e440f
--- /dev/null
+++ b/src/test/rustdoc/recursion1.rs
@@ -0,0 +1,13 @@
+#![crate_type = "lib"]
+
+mod m {
+ pub use self::a::Foo;
+
+ mod a {
+ pub struct Foo;
+ }
+
+ mod b {
+ pub use super::*;
+ }
+}
diff --git a/src/test/rustdoc/recursion2.rs b/src/test/rustdoc/recursion2.rs
new file mode 100644
index 000000000..edf7e440f
--- /dev/null
+++ b/src/test/rustdoc/recursion2.rs
@@ -0,0 +1,13 @@
+#![crate_type = "lib"]
+
+mod m {
+ pub use self::a::Foo;
+
+ mod a {
+ pub struct Foo;
+ }
+
+ mod b {
+ pub use super::*;
+ }
+}
diff --git a/src/test/rustdoc/recursion3.rs b/src/test/rustdoc/recursion3.rs
new file mode 100644
index 000000000..e69b43016
--- /dev/null
+++ b/src/test/rustdoc/recursion3.rs
@@ -0,0 +1,13 @@
+pub mod longhands {
+ pub use super::*;
+
+ pub use super::common_types::computed::compute_CSSColor as to_computed_value;
+
+ pub fn computed_as_specified() {}
+}
+
+pub mod common_types {
+ pub mod computed {
+ pub use super::super::longhands::computed_as_specified as compute_CSSColor;
+ }
+}
diff --git a/src/test/rustdoc/recursive-deref-sidebar.rs b/src/test/rustdoc/recursive-deref-sidebar.rs
new file mode 100644
index 000000000..619f40eff
--- /dev/null
+++ b/src/test/rustdoc/recursive-deref-sidebar.rs
@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+pub struct A {}
+impl A { pub fn foo_a(&self) {} }
+
+pub struct B {}
+impl B { pub fn foo_b(&self) {} }
+
+pub struct C {}
+impl C { pub fn foo_c(&self) {} }
+
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_b'
+impl Deref for A {
+ type Target = B;
+ fn deref(&self) -> &B { todo!() }
+}
+
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_c'
+impl Deref for B {
+ type Target = C;
+ fn deref(&self) -> &C { todo!() }
+}
diff --git a/src/test/rustdoc/recursive-deref.rs b/src/test/rustdoc/recursive-deref.rs
new file mode 100644
index 000000000..a7504fbcc
--- /dev/null
+++ b/src/test/rustdoc/recursive-deref.rs
@@ -0,0 +1,120 @@
+use std::ops::Deref;
+
+// Cyclic deref with the parent (which is not the top parent).
+pub struct A;
+pub struct B;
+pub struct C;
+
+impl C {
+ pub fn c(&self) {}
+}
+
+// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
+impl Deref for A {
+ type Target = B;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
+impl Deref for B {
+ type Target = C;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
+impl Deref for C {
+ type Target = B;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with the grand-parent (which is not the top parent).
+pub struct D;
+pub struct E;
+pub struct F;
+pub struct G;
+
+impl G {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn g() {}
+}
+
+// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for D {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for E {
+ type Target = F;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for F {
+ type Target = G;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
+impl Deref for G {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with top parent.
+pub struct H;
+pub struct I;
+
+impl I {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn i() {}
+}
+
+// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
+// @!has '-' '//*[@id="deref-methods-I"]'
+impl Deref for H {
+ type Target = I;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
+impl Deref for I {
+ type Target = H;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
diff --git a/src/test/rustdoc/redirect-const.rs b/src/test/rustdoc/redirect-const.rs
new file mode 100644
index 000000000..453da8387
--- /dev/null
+++ b/src/test/rustdoc/redirect-const.rs
@@ -0,0 +1,13 @@
+#![crate_name="foo"]
+
+pub use hidden::STATIC_FOO;
+pub use hidden::CONST_FOO;
+
+mod hidden {
+ // @has foo/hidden/static.STATIC_FOO.html
+ // @has - '//p/a' '../../foo/static.STATIC_FOO.html'
+ pub static STATIC_FOO: u64 = 0;
+ // @has foo/hidden/constant.CONST_FOO.html
+ // @has - '//p/a' '../../foo/constant.CONST_FOO.html'
+ pub const CONST_FOO: u64 = 0;
+}
diff --git a/src/test/rustdoc/redirect-map-empty.rs b/src/test/rustdoc/redirect-map-empty.rs
new file mode 100644
index 000000000..e9d021e0f
--- /dev/null
+++ b/src/test/rustdoc/redirect-map-empty.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Z unstable-options --generate-redirect-map
+
+#![crate_name = "foo"]
+
+// @!has foo/redirect-map.json
+pub struct Foo;
diff --git a/src/test/rustdoc/redirect-map.rs b/src/test/rustdoc/redirect-map.rs
new file mode 100644
index 000000000..b7f16b64e
--- /dev/null
+++ b/src/test/rustdoc/redirect-map.rs
@@ -0,0 +1,23 @@
+// compile-flags: -Z unstable-options --generate-redirect-map
+
+#![crate_name = "foo"]
+
+// @!has foo/private/struct.Quz.html
+// @!has foo/hidden/struct.Bar.html
+// @has foo/redirect-map.json
+pub use private::Quz;
+pub use hidden::Bar;
+
+mod private {
+ pub struct Quz;
+}
+
+#[doc(hidden)]
+pub mod hidden {
+ pub struct Bar;
+}
+
+#[macro_export]
+macro_rules! foo {
+ () => {}
+}
diff --git a/src/test/rustdoc/redirect-rename.rs b/src/test/rustdoc/redirect-rename.rs
new file mode 100644
index 000000000..504c0687c
--- /dev/null
+++ b/src/test/rustdoc/redirect-rename.rs
@@ -0,0 +1,34 @@
+#![crate_name = "foo"]
+
+mod hidden {
+ // @has foo/hidden/struct.Foo.html
+ // @has - '//p/a' '../../foo/struct.FooBar.html'
+ pub struct Foo {}
+ pub union U { a: usize }
+ pub enum Empty {}
+ pub const C: usize = 1;
+ pub static S: usize = 1;
+
+ // @has foo/hidden/bar/index.html
+ // @has - '//p/a' '../../foo/baz/index.html'
+ pub mod bar {
+ // @has foo/hidden/bar/struct.Thing.html
+ // @has - '//p/a' '../../foo/baz/struct.Thing.html'
+ pub struct Thing {}
+ }
+}
+
+// @has foo/struct.FooBar.html
+pub use hidden::Foo as FooBar;
+// @has foo/union.FooU.html
+pub use hidden::U as FooU;
+// @has foo/enum.FooEmpty.html
+pub use hidden::Empty as FooEmpty;
+// @has foo/constant.FooC.html
+pub use hidden::C as FooC;
+// @has foo/static.FooS.html
+pub use hidden::S as FooS;
+
+// @has foo/baz/index.html
+// @has foo/baz/struct.Thing.html
+pub use hidden::bar as baz;
diff --git a/src/test/rustdoc/redirect.rs b/src/test/rustdoc/redirect.rs
new file mode 100644
index 000000000..e3a14c7a7
--- /dev/null
+++ b/src/test/rustdoc/redirect.rs
@@ -0,0 +1,39 @@
+// aux-build:reexp-stripped.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate reexp_stripped;
+
+pub trait Foo {}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use reexp_stripped::Bar'
+// @has - '//code/a' 'Bar'
+// @has reexp_stripped/hidden/struct.Bar.html
+// @has - '//p/a' '../../reexp_stripped/struct.Bar.html'
+// @has 'reexp_stripped/struct.Bar.html'
+#[doc(no_inline)]
+pub use reexp_stripped::Bar;
+impl Foo for Bar {}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use reexp_stripped::Quz'
+// @has - '//code/a' 'Quz'
+// @has reexp_stripped/private/struct.Quz.html
+// @has - '//p/a' '../../reexp_stripped/struct.Quz.html'
+// @has 'reexp_stripped/struct.Quz.html'
+#[doc(no_inline)]
+pub use reexp_stripped::Quz;
+impl Foo for Quz {}
+
+mod private_no_inline {
+ pub struct Qux;
+ impl ::Foo for Qux {}
+}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use private_no_inline::Qux'
+// @!has - '//a' 'Qux'
+// @!has redirect/struct.Qux.html
+#[doc(no_inline)]
+pub use private_no_inline::Qux;
diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs
new file mode 100644
index 000000000..db1f90c69
--- /dev/null
+++ b/src/test/rustdoc/reexport-check.rs
@@ -0,0 +1,18 @@
+// aux-build:reexport-check.rs
+#![crate_name = "foo"]
+
+extern crate reexport_check;
+
+// @!has 'foo/index.html' '//code' 'pub use self::i32;'
+// @has 'foo/index.html' '//div[@class="item-left deprecated module-item"]' 'i32'
+// @has 'foo/i32/index.html'
+#[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-left module-item"]' 'String'
+pub use std::string::String;
+
+// @has 'foo/index.html' '//div[@class="item-right 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/src/test/rustdoc/reexport-dep-foreign-fn.rs b/src/test/rustdoc/reexport-dep-foreign-fn.rs
new file mode 100644
index 000000000..6e1dc4539
--- /dev/null
+++ b/src/test/rustdoc/reexport-dep-foreign-fn.rs
@@ -0,0 +1,12 @@
+// aux-build:all-item-types.rs
+
+// This test is to ensure there is no problem on handling foreign functions
+// coming from a dependency.
+
+#![crate_name = "foo"]
+
+extern crate all_item_types;
+
+// @has 'foo/fn.foo_ffn.html'
+// @has - '//*[@class="docblock item-decl"]//code' 'pub unsafe extern "C" fn foo_ffn()'
+pub use all_item_types::foo_ffn;
diff --git a/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs
new file mode 100644
index 000000000..a79d05904
--- /dev/null
+++ b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs
@@ -0,0 +1,48 @@
+#![crate_name = "foo"]
+#![feature(doc_cfg)]
+
+pub mod tag {
+ #[deprecated(since = "0.1.8", note = "Use bar() instead")]
+ pub trait Deprecated {}
+
+ #[doc(cfg(feature = "sync"))]
+ pub trait Portability {}
+
+ #[deprecated(since = "0.1.8", note = "Use bar() instead")]
+ #[doc(cfg(feature = "sync"))]
+ pub trait Both {}
+
+ pub trait None {}
+}
+
+// @has foo/mod1/index.html
+pub mod mod1 {
+ // @has - '//code' 'pub use tag::Deprecated;'
+ // @has - '//span' 'Deprecated'
+ // @!has - '//span' 'sync'
+ pub use tag::Deprecated;
+}
+
+// @has foo/mod2/index.html
+pub mod mod2 {
+ // @has - '//code' 'pub use tag::Portability;'
+ // @!has - '//span' 'Deprecated'
+ // @has - '//span' 'sync'
+ pub use tag::Portability;
+}
+
+// @has foo/mod3/index.html
+pub mod mod3 {
+ // @has - '//code' 'pub use tag::Both;'
+ // @has - '//span' 'Deprecated'
+ // @has - '//span' 'sync'
+ pub use tag::Both;
+}
+
+// @has foo/mod4/index.html
+pub mod mod4 {
+ // @has - '//code' 'pub use tag::None;'
+ // @!has - '//span' 'Deprecated'
+ // @!has - '//span' 'sync'
+ pub use tag::None;
+}
diff --git a/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs
new file mode 100644
index 000000000..ff8a910f5
--- /dev/null
+++ b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs
@@ -0,0 +1,61 @@
+#![crate_name = "foo"]
+#![feature(doc_cfg)]
+#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod tag {
+ #[unstable(feature = "humans", issue = "none")]
+ pub trait Unstable {}
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[doc(cfg(feature = "sync"))]
+ pub trait Portability {}
+
+ #[unstable(feature = "humans", issue = "none")]
+ #[doc(cfg(feature = "sync"))]
+ pub trait Both {}
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub trait None {}
+}
+
+// @has foo/mod1/index.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod mod1 {
+ // @has - '//code' 'pub use tag::Unstable;'
+ // @has - '//span' 'Experimental'
+ // @!has - '//span' 'sync'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use tag::Unstable;
+}
+
+// @has foo/mod2/index.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod mod2 {
+ // @has - '//code' 'pub use tag::Portability;'
+ // @!has - '//span' 'Experimental'
+ // @has - '//span' 'sync'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use tag::Portability;
+}
+
+// @has foo/mod3/index.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod mod3 {
+ // @has - '//code' 'pub use tag::Both;'
+ // @has - '//span' 'Experimental'
+ // @has - '//span' 'sync'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use tag::Both;
+}
+
+// @has foo/mod4/index.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod mod4 {
+ // @has - '//code' 'pub use tag::None;'
+ // @!has - '//span' 'Experimental'
+ // @!has - '//span' 'sync'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use tag::None;
+}
diff --git a/src/test/rustdoc/reexports-priv.rs b/src/test/rustdoc/reexports-priv.rs
new file mode 100644
index 000000000..aea9b9f2b
--- /dev/null
+++ b/src/test/rustdoc/reexports-priv.rs
@@ -0,0 +1,135 @@
+// aux-build: reexports.rs
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+extern crate reexports;
+
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
+pub use reexports::addr_of;
+// @!has 'foo/macro.addr_of_crate.html'
+pub(crate) use reexports::addr_of_crate;
+// @!has 'foo/macro.addr_of_self.html'
+pub(self) use reexports::addr_of_self;
+// @!has 'foo/macro.addr_of_local.html'
+use reexports::addr_of_local;
+
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+pub use reexports::Foo;
+// @!has 'foo/struct.FooCrate.html'
+pub(crate) use reexports::FooCrate;
+// @!has 'foo/struct.FooSelf.html'
+pub(self) use reexports::FooSelf;
+// @!has 'foo/struct.FooLocal.html'
+use reexports::FooLocal;
+
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+pub use reexports::Bar;
+// @!has 'foo/enum.BarCrate.html'
+pub(crate) use reexports::BarCrate;
+// @!has 'foo/enum.BarSelf.html'
+pub(self) use reexports::BarSelf;
+// @!has 'foo/enum.BarLocal.html'
+use reexports::BarLocal;
+
+// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+pub use reexports::foo;
+// @!has 'foo/fn.foo_crate.html'
+pub(crate) use reexports::foo_crate;
+// @!has 'foo/fn.foo_self.html'
+pub(self) use reexports::foo_self;
+// @!has 'foo/fn.foo_local.html'
+use reexports::foo_local;
+
+// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+pub use reexports::Type;
+// @!has 'foo/type.TypeCrate.html'
+pub(crate) use reexports::TypeCrate;
+// @!has 'foo/type.TypeSelf.html'
+pub(self) use reexports::TypeSelf;
+// @!has 'foo/type.TypeLocal.html'
+use reexports::TypeLocal;
+
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+pub use reexports::Union;
+// @!has 'foo/union.UnionCrate.html'
+pub(crate) use reexports::UnionCrate;
+// @!has 'foo/union.UnionSelf.html'
+pub(self) use reexports::UnionSelf;
+// @!has 'foo/union.UnionLocal.html'
+use reexports::UnionLocal;
+
+pub mod outer {
+ pub mod inner {
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
+ pub use reexports::addr_of;
+ // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
+ pub(crate) use reexports::addr_of_crate;
+ // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
+ pub(super) use reexports::addr_of_super;
+ // @!has 'foo/outer/inner/macro.addr_of_self.html'
+ pub(self) use reexports::addr_of_self;
+ // @!has 'foo/outer/inner/macro.addr_of_local.html'
+ use reexports::addr_of_local;
+
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+ pub use reexports::Foo;
+ // @has 'foo/outer/inner/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;'
+ pub(crate) use reexports::FooCrate;
+ // @has 'foo/outer/inner/struct.FooSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) struct FooSuper;'
+ pub(super) use reexports::FooSuper;
+ // @!has 'foo/outer/inner/struct.FooSelf.html'
+ pub(self) use reexports::FooSelf;
+ // @!has 'foo/outer/inner/struct.FooLocal.html'
+ use reexports::FooLocal;
+
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+ pub use reexports::Bar;
+ // @has 'foo/outer/inner/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {'
+ pub(crate) use reexports::BarCrate;
+ // @has 'foo/outer/inner/enum.BarSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) enum BarSuper {'
+ pub(super) use reexports::BarSuper;
+ // @!has 'foo/outer/inner/enum.BarSelf.html'
+ pub(self) use reexports::BarSelf;
+ // @!has 'foo/outer/inner/enum.BarLocal.html'
+ use reexports::BarLocal;
+
+ // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+ pub use reexports::foo;
+ // @has 'foo/outer/inner/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()'
+ pub(crate) use reexports::foo_crate;
+ // @has 'foo/outer/inner/fn.foo_super.html' '//*[@class="rust fn"]' 'pub(in outer) fn foo_super()'
+ pub(super) use::reexports::foo_super;
+ // @!has 'foo/outer/inner/fn.foo_self.html'
+ pub(self) use reexports::foo_self;
+ // @!has 'foo/outer/inner/fn.foo_local.html'
+ use reexports::foo_local;
+
+ // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+ pub use reexports::Type;
+ // @has 'foo/outer/inner/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate ='
+ pub(crate) use reexports::TypeCrate;
+ // @has 'foo/outer/inner/type.TypeSuper.html' '//*[@class="rust typedef"]' 'pub(in outer) type TypeSuper ='
+ pub(super) use reexports::TypeSuper;
+ // @!has 'foo/outer/inner/type.TypeSelf.html'
+ pub(self) use reexports::TypeSelf;
+ // @!has 'foo/outer/inner/type.TypeLocal.html'
+ use reexports::TypeLocal;
+
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+ pub use reexports::Union;
+ // @has 'foo/outer/inner/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {'
+ pub(crate) use reexports::UnionCrate;
+ // @has 'foo/outer/inner/union.UnionSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) union UnionSuper {'
+ pub(super) use reexports::UnionSuper;
+ // @!has 'foo/outer/inner/union.UnionSelf.html'
+ pub(self) use reexports::UnionSelf;
+ // @!has 'foo/outer/inner/union.UnionLocal.html'
+ use reexports::UnionLocal;
+ }
+}
+
+mod re_re_exports {
+ // @!has 'foo/re_re_exports/union.Union.html'
+ use crate::reexports::Union;
+}
diff --git a/src/test/rustdoc/reexports.rs b/src/test/rustdoc/reexports.rs
new file mode 100644
index 000000000..7abcbfb61
--- /dev/null
+++ b/src/test/rustdoc/reexports.rs
@@ -0,0 +1,129 @@
+// aux-build: reexports.rs
+
+#![crate_name = "foo"]
+
+extern crate reexports;
+
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
+pub use reexports::addr_of;
+// @!has 'foo/macro.addr_of_crate.html'
+pub(crate) use reexports::addr_of_crate;
+// @!has 'foo/macro.addr_of_self.html'
+pub(self) use reexports::addr_of_self;
+// @!has 'foo/macro.addr_of_local.html'
+use reexports::addr_of_local;
+
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+pub use reexports::Foo;
+// @!has 'foo/struct.FooCrate.html'
+pub(crate) use reexports::FooCrate;
+// @!has 'foo/struct.FooSelf.html'
+pub(self) use reexports::FooSelf;
+// @!has 'foo/struct.FooLocal.html'
+use reexports::FooLocal;
+
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+pub use reexports::Bar;
+// @!has 'foo/enum.BarCrate.html'
+pub(crate) use reexports::BarCrate;
+// @!has 'foo/enum.BarSelf.html'
+pub(self) use reexports::BarSelf;
+// @!has 'foo/enum.BarLocal.html'
+use reexports::BarLocal;
+
+// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+pub use reexports::foo;
+// @!has 'foo/fn.foo_crate.html'
+pub(crate) use reexports::foo_crate;
+// @!has 'foo/fn.foo_self.html'
+pub(self) use reexports::foo_self;
+// @!has 'foo/fn.foo_local.html'
+use reexports::foo_local;
+
+// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+pub use reexports::Type;
+// @!has 'foo/type.TypeCrate.html'
+pub(crate) use reexports::TypeCrate;
+// @!has 'foo/type.TypeSelf.html'
+pub(self) use reexports::TypeSelf;
+// @!has 'foo/type.TypeLocal.html'
+use reexports::TypeLocal;
+
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+pub use reexports::Union;
+// @!has 'foo/union.UnionCrate.html'
+pub(crate) use reexports::UnionCrate;
+// @!has 'foo/union.UnionSelf.html'
+pub(self) use reexports::UnionSelf;
+// @!has 'foo/union.UnionLocal.html'
+use reexports::UnionLocal;
+
+pub mod outer {
+ pub mod inner {
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
+ pub use reexports::addr_of;
+ // @!has 'foo/outer/inner/macro.addr_of_crate.html'
+ pub(crate) use reexports::addr_of_crate;
+ // @!has 'foo/outer/inner/macro.addr_of_super.html'
+ pub(super) use reexports::addr_of_super;
+ // @!has 'foo/outer/inner/macro.addr_of_self.html'
+ pub(self) use reexports::addr_of_self;
+ // @!has 'foo/outer/inner/macro.addr_of_local.html'
+ use reexports::addr_of_local;
+
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+ pub use reexports::Foo;
+ // @!has 'foo/outer/inner/struct.FooCrate.html'
+ pub(crate) use reexports::FooCrate;
+ // @!has 'foo/outer/inner/struct.FooSuper.html'
+ pub(super) use reexports::FooSuper;
+ // @!has 'foo/outer/inner/struct.FooSelf.html'
+ pub(self) use reexports::FooSelf;
+ // @!has 'foo/outer/inner/struct.FooLocal.html'
+ use reexports::FooLocal;
+
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+ pub use reexports::Bar;
+ // @!has 'foo/outer/inner/enum.BarCrate.html'
+ pub(crate) use reexports::BarCrate;
+ // @!has 'foo/outer/inner/enum.BarSuper.html'
+ pub(super) use reexports::BarSuper;
+ // @!has 'foo/outer/inner/enum.BarSelf.html'
+ pub(self) use reexports::BarSelf;
+ // @!has 'foo/outer/inner/enum.BarLocal.html'
+ use reexports::BarLocal;
+
+ // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+ pub use reexports::foo;
+ // @!has 'foo/outer/inner/fn.foo_crate.html'
+ pub(crate) use reexports::foo_crate;
+ // @!has 'foo/outer/inner/fn.foo_super.html'
+ pub(super) use::reexports::foo_super;
+ // @!has 'foo/outer/inner/fn.foo_self.html'
+ pub(self) use reexports::foo_self;
+ // @!has 'foo/outer/inner/fn.foo_local.html'
+ use reexports::foo_local;
+
+ // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+ pub use reexports::Type;
+ // @!has 'foo/outer/inner/type.TypeCrate.html'
+ pub(crate) use reexports::TypeCrate;
+ // @!has 'foo/outer/inner/type.TypeSuper.html'
+ pub(super) use reexports::TypeSuper;
+ // @!has 'foo/outer/inner/type.TypeSelf.html'
+ pub(self) use reexports::TypeSelf;
+ // @!has 'foo/outer/inner/type.TypeLocal.html'
+ use reexports::TypeLocal;
+
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+ pub use reexports::Union;
+ // @!has 'foo/outer/inner/union.UnionCrate.html'
+ pub(crate) use reexports::UnionCrate;
+ // @!has 'foo/outer/inner/union.UnionSuper.html'
+ pub(super) use reexports::UnionSuper;
+ // @!has 'foo/outer/inner/union.UnionSelf.html'
+ pub(self) use reexports::UnionSelf;
+ // @!has 'foo/outer/inner/union.UnionLocal.html'
+ use reexports::UnionLocal;
+ }
+}
diff --git a/src/test/rustdoc/remove-duplicates.rs b/src/test/rustdoc/remove-duplicates.rs
new file mode 100644
index 000000000..759bf84db
--- /dev/null
+++ b/src/test/rustdoc/remove-duplicates.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+mod foo {
+ pub use bar::*;
+ pub mod bar {
+ pub trait Foo {
+ fn foo();
+ }
+ }
+}
+
+// @count foo/index.html '//*[@class="trait"]' 1
+pub use foo::bar::*;
+pub use foo::*;
diff --git a/src/test/rustdoc/remove-url-from-headings.rs b/src/test/rustdoc/remove-url-from-headings.rs
new file mode 100644
index 000000000..e2b232a6e
--- /dev/null
+++ b/src/test/rustdoc/remove-url-from-headings.rs
@@ -0,0 +1,17 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @!has - '//a[@href="http://a.a"]'
+// @has - '//a[@href="#implementing-stuff-somewhere"]' 'Implementing stuff somewhere'
+// @has - '//a[@href="#another-one-urg"]' 'Another one urg'
+
+/// fooo
+///
+/// # Implementing [stuff](http://a.a "title") somewhere
+///
+/// hello
+///
+/// # Another [one][two] urg
+///
+/// [two]: http://a.a
+pub fn foo() {}
diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs
new file mode 100644
index 000000000..1ccf5ac46
--- /dev/null
+++ b/src/test/rustdoc/return-impl-trait.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait Backend {}
+
+impl Backend for () {}
+
+pub struct Module<T>(T);
+
+pub type BackendImpl = impl Backend;
+
+// @has return_impl_trait/fn.make_module.html
+/// Documentation
+pub fn make_module() -> Module<BackendImpl> {
+ Module(())
+}
diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
new file mode 100644
index 000000000..f3e211e30
--- /dev/null
+++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
@@ -0,0 +1,70 @@
+// Test that we do not currently display `~const` in rustdoc
+// as that syntax is currently provisional; `~const Destruct` has
+// no effect on stable code so it should be hidden as well.
+//
+// To future blessers: make sure that `const_trait_impl` is
+// stabilized when changing `@!has` to `@has`, and please do
+// not remove this test.
+#![feature(const_trait_impl)]
+#![crate_name = "foo"]
+
+use std::marker::Destruct;
+
+pub struct S<T>(T);
+
+// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
+// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
+// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+#[const_trait]
+pub trait Tr<T> {
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ fn a<A: ~const Clone + ~const Destruct>()
+ where
+ Option<A>: ~const Clone + ~const Destruct,
+ {
+ }
+}
+
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]' ''
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+impl<T: ~const Clone + ~const Destruct> const Tr<T> for T
+where
+ Option<T>: ~const Clone + ~const Destruct,
+{
+ fn a<A: ~const Clone + ~const Destruct>()
+ where
+ Option<A>: ~const Clone + ~const Destruct,
+ {
+ }
+}
+
+// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
+// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
+// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+pub const fn foo<F: ~const Clone + ~const Destruct>()
+where
+ Option<F>: ~const Clone + ~const Destruct,
+{
+ F::a()
+}
+
+impl<T> S<T> {
+ // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ pub const fn foo<B: ~const Clone + ~const Destruct>()
+ where
+ B: ~const Clone + ~const Destruct,
+ {
+ B::a()
+ }
+}
diff --git a/src/test/rustdoc/rustc-macro-crate.rs b/src/test/rustdoc/rustc-macro-crate.rs
new file mode 100644
index 000000000..dd5edc984
--- /dev/null
+++ b/src/test/rustdoc/rustc-macro-crate.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Foo)]
+pub fn foo(input: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/rustdoc/safe-intrinsic.rs b/src/test/rustdoc/safe-intrinsic.rs
new file mode 100644
index 000000000..d3bb8514b
--- /dev/null
+++ b/src/test/rustdoc/safe-intrinsic.rs
@@ -0,0 +1,20 @@
+#![feature(intrinsics)]
+#![feature(no_core)]
+
+#![no_core]
+#![crate_name = "foo"]
+
+extern "rust-intrinsic" {
+ // @has 'foo/fn.abort.html'
+ // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+ pub fn abort() -> !;
+ // @has 'foo/fn.unreachable.html'
+ // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+ pub fn unreachable() -> !;
+}
+
+extern "C" {
+ // @has 'foo/fn.needs_drop.html'
+ // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+ pub fn needs_drop() -> !;
+}
diff --git a/src/test/rustdoc/same-crate-hidden-impl-parameter.rs b/src/test/rustdoc/same-crate-hidden-impl-parameter.rs
new file mode 100644
index 000000000..d55393af8
--- /dev/null
+++ b/src/test/rustdoc/same-crate-hidden-impl-parameter.rs
@@ -0,0 +1,36 @@
+// test for `doc(hidden)` with impl parameters in the same crate.
+#![crate_name = "foo"]
+
+#[doc(hidden)]
+pub enum HiddenType {}
+
+#[doc(hidden)]
+pub trait HiddenTrait {}
+
+pub enum MyLibType {}
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CHiddenType%3E"]' 'impl From<HiddenType> for MyLibType'
+impl From<HiddenType> for MyLibType {
+ fn from(it: HiddenType) -> MyLibType {
+ match it {}
+ }
+}
+
+pub struct T<T>(T);
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CT%3CT%3CT%3CT%3CHiddenType%3E%3E%3E%3E%3E"]' 'impl From<T<T<T<T<HiddenType>>>>> for MyLibType'
+impl From<T<T<T<T<HiddenType>>>>> for MyLibType {
+ fn from(it: T<T<T<T<HiddenType>>>>) -> MyLibType {
+ todo!()
+ }
+}
+
+// @!has foo/enum.MyLibType.html '//*[@id="impl-HiddenTrait"]' 'impl HiddenTrait for MyLibType'
+impl HiddenTrait for MyLibType {}
+
+// @!has foo/struct.T.html '//*[@id="impl-From%3CMyLibType%3E"]' 'impl From<MyLibType> for T<T<T<T<HiddenType>>>>'
+impl From<MyLibType> for T<T<T<T<HiddenType>>>> {
+ fn from(it: MyLibType) -> T<T<T<T<HiddenType>>>> {
+ match it {}
+ }
+}
diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs
new file mode 100644
index 000000000..1abba468f
--- /dev/null
+++ b/src/test/rustdoc/sanitizer-option.rs
@@ -0,0 +1,18 @@
+// needs-sanitizer-support
+// needs-sanitizer-address
+// compile-flags: --test -Z sanitizer=address
+//
+// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
+// function that is provided by the sanitizer runtime, if flag is not passed
+// correctly, then linking will fail.
+
+/// ```
+/// extern "C" {
+/// fn __sanitizer_print_stack_trace();
+/// }
+///
+/// fn main() {
+/// unsafe { __sanitizer_print_stack_trace() };
+/// }
+/// ```
+pub fn z_flag_is_passed_to_rustc() {}
diff --git a/src/test/rustdoc/search-index-summaries.rs b/src/test/rustdoc/search-index-summaries.rs
new file mode 100644
index 000000000..dd9c1a0b4
--- /dev/null
+++ b/src/test/rustdoc/search-index-summaries.rs
@@ -0,0 +1,10 @@
+#![crate_name = "foo"]
+
+// @has 'search-index.js' 'Foo short link.'
+// @!has - 'www.example.com'
+// @!has - 'More Foo.'
+
+/// Foo short [link](https://www.example.com/).
+///
+/// More Foo.
+pub struct Foo;
diff --git a/src/test/rustdoc/search-index.rs b/src/test/rustdoc/search-index.rs
new file mode 100644
index 000000000..f1b78f172
--- /dev/null
+++ b/src/test/rustdoc/search-index.rs
@@ -0,0 +1,26 @@
+#![crate_name = "rustdoc_test"]
+
+use std::ops::Deref;
+
+// @has search-index.js Foo
+pub use private::Foo;
+
+mod private {
+ pub struct Foo;
+ impl Foo {
+ pub fn test_method() {} // @has - test_method
+ fn priv_method() {} // @!has - priv_method
+ }
+
+ pub trait PrivateTrait {
+ fn trait_method(&self) {} // @!has - priv_method
+ }
+}
+
+pub struct Bar;
+
+impl Deref for Bar {
+ // @!has search-index.js Target
+ type Target = Bar;
+ fn deref(&self) -> &Bar { self }
+}
diff --git a/src/test/rustdoc/short-docblock-codeblock.rs b/src/test/rustdoc/short-docblock-codeblock.rs
new file mode 100644
index 000000000..c6b318b06
--- /dev/null
+++ b/src/test/rustdoc/short-docblock-codeblock.rs
@@ -0,0 +1,12 @@
+#![crate_name = "foo"]
+
+// @has foo/index.html '//*[@class="item-right docblock-short"]' ""
+// @!has foo/index.html '//*[@class="item-right docblock-short"]' "Some text."
+// @!has foo/index.html '//*[@class="item-right docblock-short"]' "let x = 12;"
+
+/// ```
+/// let x = 12;
+/// ```
+///
+/// Some text.
+pub fn foo() {}
diff --git a/src/test/rustdoc/short-docblock.rs b/src/test/rustdoc/short-docblock.rs
new file mode 100644
index 000000000..17c44eab0
--- /dev/null
+++ b/src/test/rustdoc/short-docblock.rs
@@ -0,0 +1,25 @@
+#![crate_name = "foo"]
+
+// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo'
+// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo'
+// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo'
+
+/// # fooo
+///
+/// foo
+pub fn foo() {}
+
+// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood'
+// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood'
+// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood'
+
+/// ## mooood
+///
+/// foo mod
+pub mod foo {}
+
+// @has foo/index.html '//*[@class="item-right docblock-short"]/p/a[@href=\
+// "https://nougat.world"]/code' 'nougat'
+
+/// [`nougat`](https://nougat.world)
+pub struct Bar;
diff --git a/src/test/rustdoc/short-line.md b/src/test/rustdoc/short-line.md
new file mode 100644
index 000000000..eff713baa
--- /dev/null
+++ b/src/test/rustdoc/short-line.md
@@ -0,0 +1,2 @@
+inc2
+x
diff --git a/src/test/rustdoc/show-const-contents.rs b/src/test/rustdoc/show-const-contents.rs
new file mode 100644
index 000000000..48b608859
--- /dev/null
+++ b/src/test/rustdoc/show-const-contents.rs
@@ -0,0 +1,68 @@
+// Test that the contents of constants are displayed as part of the
+// documentation.
+
+// @has show_const_contents/constant.CONST_S.html 'show this'
+// @!has show_const_contents/constant.CONST_S.html '; //'
+pub const CONST_S: &'static str = "show this";
+
+// @has show_const_contents/constant.CONST_I32.html '= 42;'
+// @!has show_const_contents/constant.CONST_I32.html '; //'
+pub const CONST_I32: i32 = 42;
+
+// @has show_const_contents/constant.CONST_I32_HEX.html '= 0x42;'
+// @!has show_const_contents/constant.CONST_I32_HEX.html '; //'
+pub const CONST_I32_HEX: i32 = 0x42;
+
+// @has show_const_contents/constant.CONST_NEG_I32.html '= -42;'
+// @!has show_const_contents/constant.CONST_NEG_I32.html '; //'
+pub const CONST_NEG_I32: i32 = -42;
+
+// @has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '= 42i32;'
+// @!has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32'
+pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32;
+
+// @has show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32'
+pub const CONST_CALC_I32: i32 = 42 + 1;
+
+// @!has show_const_contents/constant.CONST_REF_I32.html '= &42;'
+// @!has show_const_contents/constant.CONST_REF_I32.html '; //'
+pub const CONST_REF_I32: &'static i32 = &42;
+
+// @has show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX; // 2_147_483_647i32'
+pub const CONST_I32_MAX: i32 = i32::MAX;
+
+// @!has show_const_contents/constant.UNIT.html '= ();'
+// @!has show_const_contents/constant.UNIT.html '; //'
+pub const UNIT: () = ();
+
+pub struct MyType(i32);
+
+// @!has show_const_contents/constant.MY_TYPE.html '= MyType(42);'
+// @!has show_const_contents/constant.MY_TYPE.html '; //'
+pub const MY_TYPE: MyType = MyType(42);
+
+pub struct MyTypeWithStr(&'static str);
+
+// @!has show_const_contents/constant.MY_TYPE_WITH_STR.html '= MyTypeWithStr("show this");'
+// @!has show_const_contents/constant.MY_TYPE_WITH_STR.html '; //'
+pub const MY_TYPE_WITH_STR: MyTypeWithStr = MyTypeWithStr("show this");
+
+// @has show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288f32;'
+// @has show_const_contents/constant.PI.html '; // 3.14159274f32'
+pub use std::f32::consts::PI;
+
+// @has show_const_contents/constant.MAX.html '= i32::MAX; // 2_147_483_647i32'
+#[allow(deprecated, deprecated_in_future)]
+pub use std::i32::MAX;
+
+macro_rules! int_module {
+ ($T:ident) => (
+ pub const MIN: $T = $T::MIN;
+ )
+}
+
+// @has show_const_contents/constant.MIN.html '= i16::MIN; // -32_768i16'
+int_module!(i16);
+
+// @has show_const_contents/constant.ESCAPE.html //pre '= r#"<script>alert("ESCAPE");</script>"#;'
+pub const ESCAPE: &str = r#"<script>alert("ESCAPE");</script>"#;
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
new file mode 100644
index 000000000..b5b681ab0
--- /dev/null
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -0,0 +1,56 @@
+#![feature(associated_type_defaults)]
+#![crate_name = "foo"]
+
+// @has foo/trait.Foo.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
+// @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
+// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'FOO'
+// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
+// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
+// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Extra'
+pub trait Foo {
+ const FOO: usize;
+ const BAR: u32 = 0;
+ type Extra: Copy = ();
+ type Output: ?Sized;
+
+ fn foo() {}
+ fn bar() -> Self::Output;
+}
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
+pub struct Bar {
+ pub f: u32,
+ pub u: u32,
+ waza: u32,
+}
+
+// @has foo/enum.En.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Bar'
+pub enum En {
+ Foo,
+ Bar,
+}
+
+// @has foo/union.MyUnion.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
+pub union MyUnion {
+ pub f1: u32,
+ pub f2: f32,
+ waza: u32,
+}
diff --git a/src/test/rustdoc/sidebar-link-generation.rs b/src/test/rustdoc/sidebar-link-generation.rs
new file mode 100644
index 000000000..7858f35a2
--- /dev/null
+++ b/src/test/rustdoc/sidebar-link-generation.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \
+// "some_fn"
+pub struct SomeStruct<T> { _inner: T }
+
+impl SomeStruct<()> {
+ pub fn some_fn(&self) {}
+}
+
+impl SomeStruct<usize> {
+ pub fn some_fn(&self) {}
+}
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
new file mode 100644
index 000000000..155150396
--- /dev/null
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -0,0 +1,16 @@
+// issue #56018: "Implementations on Foreign Types" sidebar items should link to specific impls
+
+#![crate_name = "foo"]
+
+// @has foo/trait.Foo.html
+// @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
+// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
+// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
+// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
+pub trait Foo {}
+
+impl Foo for u32 {}
+
+impl<'a> Foo for &'a str {}
diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs
new file mode 100644
index 000000000..9d2c19677
--- /dev/null
+++ b/src/test/rustdoc/sized_trait.rs
@@ -0,0 +1,17 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Bar.html
+// @!has - '//*[@id="impl-Sized"]'
+pub struct Bar {
+ a: u16,
+}
+
+// @has foo/struct.Foo.html
+// @!has - '//*[@id="impl-Sized"]'
+pub struct Foo<T: ?Sized>(T);
+
+// @has foo/struct.Unsized.html
+// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+pub struct Unsized {
+ data: [u8],
+}
diff --git a/src/test/rustdoc/slice-links.link_box_generic.html b/src/test/rustdoc/slice-links.link_box_generic.html
new file mode 100644
index 000000000..38aaf2080
--- /dev/null
+++ b/src/test/rustdoc/slice-links.link_box_generic.html
@@ -0,0 +1 @@
+<code>pub fn delta&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>&gt;</code> \ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_box_u32.html b/src/test/rustdoc/slice-links.link_box_u32.html
new file mode 100644
index 000000000..7bec7582d
--- /dev/null
+++ b/src/test/rustdoc/slice-links.link_box_u32.html
@@ -0,0 +1 @@
+<code>pub fn gamma() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]&gt;</code> \ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_slice_generic.html b/src/test/rustdoc/slice-links.link_slice_generic.html
new file mode 100644
index 000000000..1d0f2bf75
--- /dev/null
+++ b/src/test/rustdoc/slice-links.link_slice_generic.html
@@ -0,0 +1 @@
+<code>pub fn beta&lt;T&gt;() -&gt; &amp;'static <a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a></code> \ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.link_slice_u32.html b/src/test/rustdoc/slice-links.link_slice_u32.html
new file mode 100644
index 000000000..c86d38304
--- /dev/null
+++ b/src/test/rustdoc/slice-links.link_slice_u32.html
@@ -0,0 +1 @@
+<code>pub fn alpha() -&gt; &amp;'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]</code> \ No newline at end of file
diff --git a/src/test/rustdoc/slice-links.rs b/src/test/rustdoc/slice-links.rs
new file mode 100644
index 000000000..9a78e963e
--- /dev/null
+++ b/src/test/rustdoc/slice-links.rs
@@ -0,0 +1,28 @@
+#![crate_name = "foo"]
+#![no_std]
+
+pub struct MyBox<T: ?Sized>(*const T);
+
+// @has 'foo/fn.alpha.html'
+// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+pub fn alpha() -> &'static [u32] {
+ loop {}
+}
+
+// @has 'foo/fn.beta.html'
+// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+pub fn beta<T>() -> &'static [T] {
+ loop {}
+}
+
+// @has 'foo/fn.gamma.html'
+// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+pub fn gamma() -> MyBox<[u32]> {
+ loop {}
+}
+
+// @has 'foo/fn.delta.html'
+// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+pub fn delta<T>() -> MyBox<[T]> {
+ loop {}
+}
diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs
new file mode 100644
index 000000000..7ae5bd699
--- /dev/null
+++ b/src/test/rustdoc/smart-punct.rs
@@ -0,0 +1,28 @@
+#![crate_name = "foo"]
+
+//! This is the "start" of the 'document'! How'd you know that "it's" the start?
+//!
+//! # Header with "smart punct'"
+//!
+//! [link with "smart punct'" -- yessiree!][]
+//!
+//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org
+//!
+//! # Code should not be smart-punct'd
+//!
+//! `this inline code -- it shouldn't have "smart punct"`
+//!
+//! ```
+//! let x = "don't smart-punct me -- please!";
+//! ```
+//!
+//! ```text
+//! I say "don't smart-punct me -- please!"
+//! ```
+
+// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?"
+// @has "foo/index.html" "//h2" "Header with “smart punct’”"
+// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!"
+// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\""
+// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";"
+// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\""
diff --git a/src/test/rustdoc/smoke.rs b/src/test/rustdoc/smoke.rs
new file mode 100644
index 000000000..c1ed3a0c9
--- /dev/null
+++ b/src/test/rustdoc/smoke.rs
@@ -0,0 +1,25 @@
+// @has smoke/index.html
+
+//! Very docs
+
+// @has smoke/bar/index.html
+pub mod bar {
+
+ /// So correct
+ // @has smoke/bar/baz/index.html
+ pub mod baz {
+ /// Much detail
+ // @has smoke/bar/baz/fn.baz.html
+ pub fn baz() { }
+ }
+
+ /// *wow*
+ // @has smoke/bar/trait.Doge.html
+ pub trait Doge { fn dummy(&self) { } }
+
+ // @has smoke/bar/struct.Foo.html
+ pub struct Foo { x: isize, y: usize }
+
+ // @has smoke/bar/fn.prawns.html
+ pub fn prawns((a, b): (isize, usize), Foo { x, y }: Foo) { }
+}
diff --git a/src/test/rustdoc/sort-modules-by-appearance.rs b/src/test/rustdoc/sort-modules-by-appearance.rs
new file mode 100644
index 000000000..5be6b9826
--- /dev/null
+++ b/src/test/rustdoc/sort-modules-by-appearance.rs
@@ -0,0 +1,13 @@
+// Tests the rustdoc --sort-modules-by-appearance option, that allows module declarations to appear
+// in the order they are declared in the source code, rather than only alphabetically.
+
+// compile-flags: -Z unstable-options --sort-modules-by-appearance
+
+pub mod module_b {}
+
+pub mod module_c {}
+
+pub mod module_a {}
+
+// @matches 'sort_modules_by_appearance/index.html' '(?s)module_b.*module_c.*module_a'
+// @matches 'sort_modules_by_appearance/sidebar-items.js' '"module_b".*"module_c".*"module_a"'
diff --git a/src/test/rustdoc/source-file.rs b/src/test/rustdoc/source-file.rs
new file mode 100644
index 000000000..968899dab
--- /dev/null
+++ b/src/test/rustdoc/source-file.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has source-files.js source-file.rs
+
+pub struct Foo;
diff --git a/src/test/rustdoc/source-version-separator.rs b/src/test/rustdoc/source-version-separator.rs
new file mode 100644
index 000000000..14580373b
--- /dev/null
+++ b/src/test/rustdoc/source-version-separator.rs
@@ -0,0 +1,30 @@
+#![stable(feature = "bar", since = "1.0")]
+#![crate_name = "foo"]
+#![feature(staged_api)]
+
+// @has foo/trait.Bar.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub trait Bar {
+ // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
+ #[stable(feature = "foobar", since = "3.0")]
+ fn foo();
+}
+
+// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source'
+
+// @has foo/struct.Foo.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "baz", since = "1.0")]
+pub struct Foo;
+
+impl Foo {
+ // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
+ #[stable(feature = "foobar", since = "3.0")]
+ pub fn foofoo() {}
+}
+
+#[stable(feature = "yolo", since = "4.0")]
+impl Bar for Foo {
+ fn foo() {}
+}
diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs
new file mode 100644
index 000000000..524578921
--- /dev/null
+++ b/src/test/rustdoc/spotlight-from-dependency.rs
@@ -0,0 +1,24 @@
+#![crate_name = "foo"]
+
+use std::iter::Iterator;
+
+// @has foo/struct.Odd.html
+// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+pub struct Odd {
+ current: usize,
+}
+
+impl Odd {
+ pub fn new() -> Odd {
+ Odd { current: 1 }
+ }
+}
+
+impl Iterator for Odd {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.current += 2;
+ Some(self.current - 2)
+ }
+}
diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs
new file mode 100644
index 000000000..69be9aa8d
--- /dev/null
+++ b/src/test/rustdoc/src-links-auto-impls.rs
@@ -0,0 +1,12 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Unsized.html
+// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
+// @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
+// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink"]' 'source'
+pub struct Unsized {
+ data: [u8],
+}
diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs
new file mode 100644
index 000000000..8012e4422
--- /dev/null
+++ b/src/test/rustdoc/src-links-external.rs
@@ -0,0 +1,13 @@
+// aux-build:src-links-external.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+extern crate src_links_external;
+
+// @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#1'
+#[doc(inline)]
+pub use src_links_external as bar;
+
+// @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#1'
diff --git a/src/test/rustdoc/src-links.rs b/src/test/rustdoc/src-links.rs
new file mode 100644
index 000000000..353ce1024
--- /dev/null
+++ b/src/test/rustdoc/src-links.rs
@@ -0,0 +1,46 @@
+#![crate_name = "foo"]
+
+//! Dox
+// @has src/foo/src-links.rs.html
+// @has foo/index.html '//a/@href' '../src/foo/src-links.rs.html'
+
+#[path = "src-links/mod.rs"]
+pub mod qux;
+
+// @has foo/bar/index.html '//a/@href' '../../src/foo/src-links.rs.html'
+pub mod bar {
+
+ /// Dox
+ // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/src-links.rs.html'
+ pub mod baz {
+ /// Dox
+ // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/src-links.rs.html'
+ pub fn baz() { }
+ }
+
+ /// Dox
+ // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/src-links.rs.html'
+ pub trait Foobar { fn dummy(&self) { } }
+
+ // @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/src-links.rs.html'
+ pub struct Foo { x: i32, y: u32 }
+
+ // @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/src-links.rs.html'
+ pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { }
+}
+
+/// Dox
+// @has foo/fn.modfn.html '//a/@href' '../src/foo/src-links.rs.html'
+pub fn modfn() { }
+
+// same hierarchy as above, but just for the submodule
+
+// @has src/foo/src-links/mod.rs.html
+// @has foo/qux/index.html '//a/@href' '../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/src-links/mod.rs.html'
+// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/src-links/mod.rs.html'
diff --git a/src/test/rustdoc/src-links/compiletest-ignore-dir b/src/test/rustdoc/src-links/compiletest-ignore-dir
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/test/rustdoc/src-links/compiletest-ignore-dir
diff --git a/src/test/rustdoc/src-links/mod.rs b/src/test/rustdoc/src-links/mod.rs
new file mode 100644
index 000000000..27b239681
--- /dev/null
+++ b/src/test/rustdoc/src-links/mod.rs
@@ -0,0 +1,19 @@
+//! Dox
+pub mod bar {
+
+ /// Dox
+ pub mod baz {
+ /// Dox
+ pub fn baz() { }
+ }
+
+ /// Dox
+ pub trait Foobar { fn dummy(&self) { } }
+
+ pub struct Foo { x: i32, y: u32 }
+
+ pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { }
+}
+
+/// Dox
+pub fn modfn() { }
diff --git a/src/test/rustdoc/stability.rs b/src/test/rustdoc/stability.rs
new file mode 100644
index 000000000..90be2050d
--- /dev/null
+++ b/src/test/rustdoc/stability.rs
@@ -0,0 +1,12 @@
+#![feature(staged_api)]
+
+#![unstable(feature = "test", issue = "none")]
+
+pub struct Unstable {
+ // @has stability/struct.Unstable.html \
+ // '//span[@class="item-info"]//div[@class="stab unstable"]' \
+ // 'This is a nightly-only experimental API'
+ // @count stability/struct.Unstable.html '//span[@class="stab unstable"]' 0
+ pub foo: u32,
+ pub bar: u32,
+}
diff --git a/src/test/rustdoc/static-root-path.rs b/src/test/rustdoc/static-root-path.rs
new file mode 100644
index 000000000..f1d49b9fc
--- /dev/null
+++ b/src/test/rustdoc/static-root-path.rs
@@ -0,0 +1,18 @@
+// compile-flags:-Z unstable-options --static-root-path /cache/
+
+// @has static_root_path/struct.SomeStruct.html
+// @matches - '"/cache/main\.js"'
+// @!matches - '"\.\./main\.js"'
+// @matches - 'data-root-path="\.\./"'
+// @!matches - '"/cache/search-index\.js"'
+pub struct SomeStruct;
+
+// @has src/static_root_path/static-root-path.rs.html
+// @matches - '"/cache/source-script\.js"'
+// @!matches - '"\.\./\.\./source-script\.js"'
+// @matches - '"\.\./\.\./source-files.js"'
+// @!matches - '"/cache/source-files\.js"'
+
+// @has settings.html
+// @matches - '/cache/settings\.js'
+// @!matches - '\./settings\.js'
diff --git a/src/test/rustdoc/static.rs b/src/test/rustdoc/static.rs
new file mode 100644
index 000000000..90dafd8b3
--- /dev/null
+++ b/src/test/rustdoc/static.rs
@@ -0,0 +1,12 @@
+// compile-flags: --document-private-items
+
+#![crate_type = "lib"]
+
+// @has static/static.FOO.html '//pre' 'static FOO: usize'
+static FOO: usize = 1;
+
+// @has static/static.BAR.html '//pre' 'pub static BAR: usize'
+pub static BAR: usize = 1;
+
+// @has static/static.BAZ.html '//pre' 'pub static mut BAZ: usize'
+pub static mut BAZ: usize = 1;
diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html
new file mode 100644
index 000000000..22b0b5dc4
--- /dev/null
+++ b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html
@@ -0,0 +1,2 @@
+<div class="docblock"><p>a</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.rs b/src/test/rustdoc/strip-block-doc-comments-stars.rs
new file mode 100644
index 000000000..ea28d84f1
--- /dev/null
+++ b/src/test/rustdoc/strip-block-doc-comments-stars.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+
+// The goal of this test is to ensure that it won't be generated as a list because
+// block doc comments can have their lines starting with a star.
+
+// @has foo/fn.foo.html
+// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]'
+/**
+ * a
+ */
+pub fn foo() {}
diff --git a/src/test/rustdoc/strip-enum-variant.no-not-shown.html b/src/test/rustdoc/strip-enum-variant.no-not-shown.html
new file mode 100644
index 000000000..c4ee1a991
--- /dev/null
+++ b/src/test/rustdoc/strip-enum-variant.no-not-shown.html
@@ -0,0 +1 @@
+<ul><li><a href="#variant.Shown">Shown</a></li></ul> \ No newline at end of file
diff --git a/src/test/rustdoc/strip-enum-variant.rs b/src/test/rustdoc/strip-enum-variant.rs
new file mode 100644
index 000000000..f82ffdfed
--- /dev/null
+++ b/src/test/rustdoc/strip-enum-variant.rs
@@ -0,0 +1,11 @@
+// @has strip_enum_variant/enum.MyThing.html
+// @has - '//code' 'Shown'
+// @!has - '//code' 'NotShown'
+// @has - '//code' '// some variants omitted'
+// Also check that `NotShown` isn't displayed in the sidebar.
+// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block"][1]/ul'
+pub enum MyThing {
+ Shown,
+ #[doc(hidden)]
+ NotShown,
+}
diff --git a/src/test/rustdoc/struct-arg-pattern.rs b/src/test/rustdoc/struct-arg-pattern.rs
new file mode 100644
index 000000000..3c0369e3d
--- /dev/null
+++ b/src/test/rustdoc/struct-arg-pattern.rs
@@ -0,0 +1,10 @@
+#![crate_name = "foo"]
+
+struct BodyId {
+ hir_id: usize,
+}
+
+// @has 'foo/fn.body_owner.html' '//*[@class="rust fn"]' 'pub fn body_owner(_: BodyId)'
+pub fn body_owner(BodyId { hir_id }: BodyId) {
+ // ...
+}
diff --git a/src/test/rustdoc/struct-field.rs b/src/test/rustdoc/struct-field.rs
new file mode 100644
index 000000000..998683bdd
--- /dev/null
+++ b/src/test/rustdoc/struct-field.rs
@@ -0,0 +1,22 @@
+#![crate_name = "foo"]
+
+
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="struct.Foo.html#structfield.bar"]' 'Foo::bar'
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="union.Bar.html#structfield.foo"]' 'Bar::foo'
+// @has foo/index.html '//*[@class="docblock"]/p/a[@href="enum.Uniooon.html#variant.X"]' 'Uniooon::X'
+
+//! Test with [Foo::bar], [Bar::foo], [Uniooon::X]
+
+pub struct Foo {
+ pub bar: usize,
+}
+
+pub union Bar {
+ pub foo: u32,
+}
+
+pub enum Uniooon {
+ F,
+ X,
+ Y,
+}
diff --git a/src/test/rustdoc/struct-implementations-title.rs b/src/test/rustdoc/struct-implementations-title.rs
new file mode 100644
index 000000000..5468796f6
--- /dev/null
+++ b/src/test/rustdoc/struct-implementations-title.rs
@@ -0,0 +1,9 @@
+#![crate_name = "foo"]
+
+pub struct Struc;
+
+// @has foo/struct.Struc.html
+// @has - '//*[@id="main-content"]/h2[@id="implementations"]' "Implementations"
+impl Struc {
+ pub const S: u64 = 0;
+}
diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs
new file mode 100644
index 000000000..7e1cada4b
--- /dev/null
+++ b/src/test/rustdoc/structfields.rs
@@ -0,0 +1,44 @@
+// @has structfields/struct.Foo.html
+pub struct Foo {
+ // @has - //pre "pub a: ()"
+ pub a: (),
+ // @has - //pre "/* private fields */"
+ // @!has - //pre "b: ()"
+ b: (),
+ // @!has - //pre "c: usize"
+ #[doc(hidden)]
+ c: usize,
+ // @has - //pre "pub d: usize"
+ pub d: usize,
+}
+
+// @has structfields/struct.Bar.html
+pub struct Bar {
+ // @has - //pre "pub a: ()"
+ pub a: (),
+ // @!has - //pre "/* private fields */"
+}
+
+// @has structfields/enum.Qux.html
+pub enum Qux {
+ Quz {
+ // @has - //pre "a: ()"
+ a: (),
+ // @!has - //pre "b: ()"
+ #[doc(hidden)]
+ b: (),
+ // @has - //pre "c: usize"
+ c: usize,
+ // @has - //pre "/* private fields */"
+ },
+}
+
+// @has structfields/struct.Baz.html //pre "pub struct Baz { /* private fields */ }"
+pub struct Baz {
+ x: u8,
+ #[doc(hidden)]
+ pub y: u8,
+}
+
+// @has structfields/struct.Quux.html //pre "pub struct Quux {}"
+pub struct Quux {}
diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs
new file mode 100644
index 000000000..54c54fdbf
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/basic.rs
@@ -0,0 +1,8 @@
+// @has basic/struct.Foo.html
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T> where T: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T> where T: Sync'
+// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+pub struct Foo<T> {
+ field: T,
+}
diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs
new file mode 100644
index 000000000..f9017b90c
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/complex.rs
@@ -0,0 +1,42 @@
+mod foo {
+ pub trait MyTrait<'a> {
+ type MyItem: ?Sized;
+ }
+
+ pub struct Inner<'a, Q, R: ?Sized> {
+ field: Q,
+ field3: &'a u8,
+ my_foo: Foo<Q>,
+ field2: R,
+ }
+
+ pub struct Outer<'a, T, K: ?Sized> {
+ my_inner: Inner<'a, T, K>,
+ }
+
+ pub struct Foo<T> {
+ myfield: T,
+ }
+}
+
+// @has complex/struct.NotOuter.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
+
+pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
+
+unsafe impl<T> Send for Foo<T>
+where
+ T: NotMyTrait<'static>,
+{
+}
+
+unsafe impl<'a, Q, R: ?Sized> Send for NotInner<'a, Q, R>
+where
+ Q: NotMyTrait<'a>,
+ <Q as NotMyTrait<'a>>::MyItem: Copy,
+ R: for<'b> Fn((&'b bool, &'a u8)) -> &'b i8,
+ Foo<Q>: Send,
+{
+}
diff --git a/src/test/rustdoc/synthetic_auto/crate-local.rs b/src/test/rustdoc/synthetic_auto/crate-local.rs
new file mode 100644
index 000000000..58b787dfa
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/crate-local.rs
@@ -0,0 +1,9 @@
+#![feature(auto_traits)]
+
+pub auto trait Banana {}
+
+// @has crate_local/struct.Peach.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Banana for Peach'
+// @has - '//h3[@class="code-header in-band"]' 'impl Send for Peach'
+// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Peach'
+pub struct Peach;
diff --git a/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs
new file mode 100644
index 000000000..6f66b8e55
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs
@@ -0,0 +1,25 @@
+// Regression test for issue #72213
+// Tests that we don't ICE when we have projection predicates
+// in our initial ParamEnv
+
+pub struct Lines<'a, L>
+where
+ L: Iterator<Item = &'a ()>,
+{
+ words: std::iter::Peekable<Words<'a, L>>,
+}
+
+pub struct Words<'a, L> {
+ _m: std::marker::PhantomData<&'a L>,
+}
+
+impl<'a, L> Iterator for Words<'a, L>
+where
+ L: Iterator<Item = &'a ()>,
+{
+ type Item = ();
+
+ fn next(&mut self) -> Option<Self::Item> {
+ unimplemented!()
+ }
+}
diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs
new file mode 100644
index 000000000..ee1393f97
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs
@@ -0,0 +1,19 @@
+pub struct Inner<'a, T: 'a> {
+ field: &'a T,
+}
+
+unsafe impl<'a, T> Send for Inner<'a, T>
+where
+ 'a: 'static,
+ T: for<'b> Fn(&'b bool) -> &'a u8,
+{}
+
+// @has lifetimes/struct.Foo.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+//
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
+pub struct Foo<'c, K: 'c> {
+ inner_field: Inner<'c, K>,
+}
diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs
new file mode 100644
index 000000000..49bad1622
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/manual.rs
@@ -0,0 +1,14 @@
+// @has manual/struct.Foo.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
+//
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// 'impl<T> Send for Foo<T>'
+//
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
+pub struct Foo<T> {
+ field: T,
+}
+
+unsafe impl<T> Send for Foo<T> {}
diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs
new file mode 100644
index 000000000..66e749ac3
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/negative.rs
@@ -0,0 +1,13 @@
+pub struct Inner<T: Copy> {
+ field: *mut T,
+}
+
+// @has negative/struct.Outer.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Send for Outer<T>"
+//
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> !Sync for Outer<T>"
+pub struct Outer<T: Copy> {
+ inner_field: Inner<T>,
+}
diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs
new file mode 100644
index 000000000..69edbee61
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/nested.rs
@@ -0,0 +1,19 @@
+pub struct Inner<T> {
+ field: T,
+}
+
+unsafe impl<T> Send for Inner<T>
+where
+ T: Copy,
+{
+}
+
+// @has nested/struct.Foo.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// 'impl<T> Send for Foo<T> where T: Copy'
+//
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
+pub struct Foo<T> {
+ inner_field: Inner<T>,
+}
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
new file mode 100644
index 000000000..16ab876e8
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -0,0 +1,16 @@
+pub struct Inner<T> {
+ field: T,
+}
+
+unsafe impl<T> Send for Inner<T>
+where
+ T: Copy + Send,
+{
+}
+
+// @has no_redundancy/struct.Outer.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> Send for Outer<T> where T: Send + Copy"
+pub struct Outer<T> {
+ inner_field: Inner<T>,
+}
diff --git a/src/test/rustdoc/synthetic_auto/overflow.rs b/src/test/rustdoc/synthetic_auto/overflow.rs
new file mode 100644
index 000000000..c132ab6fb
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/overflow.rs
@@ -0,0 +1,35 @@
+// Tests that we don't fail with an overflow error for certain
+// strange types
+// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915
+
+pub trait Interner {
+ type InternedType;
+}
+
+struct RustInterner<'tcx> {
+ foo: &'tcx ()
+}
+
+impl<'tcx> Interner for RustInterner<'tcx> {
+ type InternedType = Box<TyData<Self>>;
+}
+
+enum TyData<I: Interner> {
+ FnDef(I::InternedType)
+}
+
+struct VariableKind<I: Interner>(I::InternedType);
+
+// @has overflow/struct.BoundVarsCollector.html
+// @has - '//h3[@class="code-header in-band"]' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
+pub struct BoundVarsCollector<'tcx> {
+ val: VariableKind<RustInterner<'tcx>>
+}
+
+fn is_send<T: Send>() {}
+
+struct MyInterner<'tcx> {
+ val: &'tcx ()
+}
+
+fn main() {}
diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs
new file mode 100644
index 000000000..8b0205825
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/project.rs
@@ -0,0 +1,34 @@
+pub struct Inner<'a, T: 'a> {
+ field: &'a T,
+}
+
+trait MyTrait {
+ type MyItem;
+}
+
+trait OtherTrait {}
+
+unsafe impl<'a, T> Send for Inner<'a, T>
+where
+ 'a: 'static,
+ T: MyTrait<MyItem = bool>,
+{
+}
+unsafe impl<'a, T> Sync for Inner<'a, T>
+where
+ 'a: 'static,
+ T: MyTrait,
+ <T as MyTrait>::MyItem: OtherTrait,
+{
+}
+
+// @has project/struct.Foo.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+//
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// 'c: 'static,"
+pub struct Foo<'c, K: 'c> {
+ inner_field: Inner<'c, K>,
+}
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
new file mode 100644
index 000000000..ccef901b1
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -0,0 +1,29 @@
+// Some unusual code minimized from
+// https://github.com/sile/handy_async/tree/7b619b762c06544fc67792c8ff8ebc24a88fdb98
+
+pub trait Pattern {
+ type Value;
+}
+
+pub struct Constrain<A, B = A, C = A>(A, B, C);
+
+impl<A, B, C> Pattern for Constrain<A, B, C>
+ where A: Pattern,
+ B: Pattern<Value = A::Value>,
+ C: Pattern<Value = A::Value>,
+{
+ type Value = A::Value;
+}
+
+pub struct Wrapper<T>(T);
+
+impl<T> Pattern for Wrapper<T> {
+ type Value = T;
+}
+
+
+// @has self_referential/struct.WriteAndThen.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
+pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
+ where P1: Pattern;
diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs
new file mode 100644
index 000000000..36e985144
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/static-region.rs
@@ -0,0 +1,10 @@
+pub trait OwnedTrait<'a> {
+ type Reader;
+}
+
+// @has static_region/struct.Owned.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+pub struct Owned<T> where T: OwnedTrait<'static> {
+ marker: <T as OwnedTrait<'static>>::Reader,
+}
diff --git a/src/test/rustdoc/tab_title.rs b/src/test/rustdoc/tab_title.rs
new file mode 100644
index 000000000..0cc4f147e
--- /dev/null
+++ b/src/test/rustdoc/tab_title.rs
@@ -0,0 +1,44 @@
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// tests for the html <title> element
+
+// @has foo/index.html '//head/title' 'foo - Rust'
+
+// @has foo/fn.widget_count.html '//head/title' 'widget_count in foo - Rust'
+/// blah
+pub fn widget_count() {}
+
+// @has foo/struct.Widget.html '//head/title' 'Widget in foo - Rust'
+pub struct Widget;
+
+// @has foo/constant.ANSWER.html '//head/title' 'ANSWER in foo - Rust'
+pub const ANSWER: u8 = 42;
+
+// @has foo/blah/index.html '//head/title' 'foo::blah - Rust'
+pub mod blah {
+ // @has foo/blah/struct.Widget.html '//head/title' 'Widget in foo::blah - Rust'
+ pub struct Widget;
+
+ // @has foo/blah/trait.Awesome.html '//head/title' 'Awesome in foo::blah - Rust'
+ pub trait Awesome {}
+
+ // @has foo/blah/fn.make_widget.html '//head/title' 'make_widget in foo::blah - Rust'
+ pub fn make_widget() {}
+
+ // @has foo/macro.cool_macro.html '//head/title' 'cool_macro in foo - Rust'
+ #[macro_export]
+ macro_rules! cool_macro {
+ ($t:tt) => { $t }
+ }
+}
+
+// @has foo/keyword.continue.html '//head/title' 'continue - Rust'
+#[doc(keyword = "continue")]
+mod continue_keyword {}
+
+// @has foo/primitive.u8.html '//head/title' 'u8 - Rust'
+// @!has - '//head/title' 'foo'
+#[doc(primitive = "u8")]
+/// `u8` docs
+mod u8 {}
diff --git a/src/test/rustdoc/table-in-docblock.rs b/src/test/rustdoc/table-in-docblock.rs
new file mode 100644
index 000000000..858b58919
--- /dev/null
+++ b/src/test/rustdoc/table-in-docblock.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @count - '//*[@class="docblock"]/div/table' 2
+// @!has - '//*[@class="docblock"]/table'
+/// | hello | hello2 |
+/// | ----- | ------ |
+/// | data | data2 |
+pub struct Foo;
+
+impl Foo {
+ /// | hello | hello2 |
+ /// | ----- | ------ |
+ /// | data | data2 |
+ pub fn foo(&self) {}
+}
diff --git a/src/test/rustdoc/task-lists.rs b/src/test/rustdoc/task-lists.rs
new file mode 100644
index 000000000..c2e7dd60f
--- /dev/null
+++ b/src/test/rustdoc/task-lists.rs
@@ -0,0 +1,13 @@
+// ignore-tidy-linelength
+// FIXME: this doesn't test as much as I'd like; ideally it would have these query too:
+ // has task_lists/index.html '//li/input[@type="checkbox" and disabled]/following-sibling::text()' 'a'
+ // has task_lists/index.html '//li/input[@type="checkbox"]/following-sibling::text()' 'b'
+// Unfortunately that requires LXML, because the built-in xml module doesn't support all of xpath.
+
+// @has task_lists/index.html '//ul/li/input[@type="checkbox"]' ''
+// @has task_lists/index.html '//ul/li/input[@disabled]' ''
+// @has task_lists/index.html '//ul/li' 'a'
+// @has task_lists/index.html '//ul/li' 'b'
+//! This tests 'task list' support, a common markdown extension.
+//! - [ ] a
+//! - [x] b
diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs
new file mode 100644
index 000000000..6a510b9ac
--- /dev/null
+++ b/src/test/rustdoc/test-lists.rs
@@ -0,0 +1,26 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - //ol/li "list"
+// @has - //ol/li/ol/li "fooooo"
+// @has - //ol/li/ol/li "x"
+// @has - //ol/li "foo"
+/// 1. list
+/// 1. fooooo
+/// 2. x
+/// 2. foo
+pub fn f() {}
+
+// @has foo/fn.foo2.html
+// @has - //ul/li "normal list"
+// @has - //ul/li/ul/li "sub list"
+// @has - //ul/li/ul/li "new elem still same elem and again same elem!"
+// @has - //ul/li "new big elem"
+/// * normal list
+/// * sub list
+/// * new elem
+/// still same elem
+///
+/// and again same elem!
+/// * new big elem
+pub fn foo2() {}
diff --git a/src/test/rustdoc/test-parens.rs b/src/test/rustdoc/test-parens.rs
new file mode 100644
index 000000000..d9b9c7957
--- /dev/null
+++ b/src/test/rustdoc/test-parens.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="rust fn"]' "_: &(dyn ToString + 'static)"
+pub fn foo(_: &(ToString + 'static)) {}
diff --git a/src/test/rustdoc/test-strikethrough.rs b/src/test/rustdoc/test-strikethrough.rs
new file mode 100644
index 000000000..c7855729a
--- /dev/null
+++ b/src/test/rustdoc/test-strikethrough.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - //del "Y"
+/// ~~Y~~
+pub fn f() {}
diff --git a/src/test/rustdoc/test_option_check/bar.rs b/src/test/rustdoc/test_option_check/bar.rs
new file mode 100644
index 000000000..50a182cf7
--- /dev/null
+++ b/src/test/rustdoc/test_option_check/bar.rs
@@ -0,0 +1,9 @@
+// compile-flags: --test
+// check-test-line-numbers-match
+
+/// This looks like another awesome test!
+///
+/// ```
+/// println!("foo?");
+/// ```
+pub fn foooo() {}
diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs
new file mode 100644
index 000000000..964e8e37e
--- /dev/null
+++ b/src/test/rustdoc/test_option_check/test.rs
@@ -0,0 +1,18 @@
+// compile-flags: --test
+// check-test-line-numbers-match
+
+pub mod bar;
+
+/// This is a Foo;
+///
+/// ```
+/// println!("baaaaaar");
+/// ```
+pub struct Foo;
+
+/// This is a Bar;
+///
+/// ```
+/// println!("fooooo");
+/// ```
+pub struct Bar;
diff --git a/src/test/rustdoc/thread-local-src.rs b/src/test/rustdoc/thread-local-src.rs
new file mode 100644
index 000000000..6de35e323
--- /dev/null
+++ b/src/test/rustdoc/thread-local-src.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source'
+
+// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source'
+thread_local!(pub static FOO: bool = false);
diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs
new file mode 100644
index 000000000..69e8b856b
--- /dev/null
+++ b/src/test/rustdoc/titles.rs
@@ -0,0 +1,56 @@
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @matches 'foo/index.html' '//h1' 'Crate foo'
+// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
+
+// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
+// @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
+pub mod foo_mod {
+ pub struct __Thing {}
+}
+
+extern "C" {
+ // @matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn'
+ pub fn foo_ffn();
+}
+
+// @matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn'
+pub fn foo_fn() {}
+
+// @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
+// @matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
+pub trait FooTrait {}
+
+// @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
+// @matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
+pub struct FooStruct;
+
+// @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
+// @matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
+pub enum FooEnum {}
+
+// @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType'
+// @matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
+pub type FooType = FooStruct;
+
+// @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
+#[macro_export]
+macro_rules! foo_macro {
+ () => {};
+}
+
+// @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
+#[doc(primitive = "bool")]
+mod bool {}
+
+// @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'
+pub static FOO_STATIC: FooStruct = FooStruct;
+
+extern "C" {
+ // @matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC'
+ pub static FOO_FSTATIC: FooStruct;
+}
+
+// @matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT'
+pub const FOO_CONSTANT: FooStruct = FooStruct;
diff --git a/src/test/rustdoc/toggle-item-contents.rs b/src/test/rustdoc/toggle-item-contents.rs
new file mode 100644
index 000000000..c1df4613e
--- /dev/null
+++ b/src/test/rustdoc/toggle-item-contents.rs
@@ -0,0 +1,185 @@
+#![allow(unused)]
+
+// @has 'toggle_item_contents/struct.PubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub struct PubStruct {
+ pub a: usize,
+ pub b: usize,
+}
+
+// @has 'toggle_item_contents/struct.BigPubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+pub struct BigPubStruct {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.BigUnion.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+pub union BigUnion {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.Union.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub union Union {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+}
+
+// @has 'toggle_item_contents/struct.PrivStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @has - '//div[@class="docblock item-decl"]' '/* private fields */'
+pub struct PrivStruct {
+ a: usize,
+ b: usize,
+}
+
+// @has 'toggle_item_contents/enum.Enum.html'
+// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]'
+pub enum Enum {
+ A, B, C,
+ D {
+ a: u8,
+ b: u8
+ }
+}
+
+// @has 'toggle_item_contents/enum.EnumStructVariant.html'
+// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]'
+pub enum EnumStructVariant {
+ A, B, C,
+ D {
+ a: u8,
+ }
+}
+
+// @has 'toggle_item_contents/enum.LargeEnum.html'
+// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants'
+pub enum LargeEnum {
+ A, B, C, D, E, F(u8), G, H, I, J, K, L, M
+}
+
+// @has 'toggle_item_contents/trait.Trait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub trait Trait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.GinormousTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items'
+pub trait GinormousTrait {
+ type A;
+ type B;
+ type C;
+ type D;
+ type E;
+ type F;
+ type G;
+ type H;
+ type I;
+ type J;
+ type K;
+ type L;
+ type M;
+ const N: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.HugeTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
+pub trait HugeTrait {
+ type A;
+ const M: usize = 1;
+ const N: usize = 1;
+ const O: usize = 1;
+ const P: usize = 1;
+ const Q: usize = 1;
+ const R: usize = 1;
+ const S: usize = 1;
+ const T: usize = 1;
+ const U: usize = 1;
+ const V: usize = 1;
+ const W: usize = 1;
+ const X: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.GiganticTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
+pub trait GiganticTrait {
+ type A;
+ type B;
+ type C;
+ type D;
+ type E;
+ type F;
+ type G;
+ type H;
+ type I;
+ type J;
+ type K;
+ type L;
+ const M: usize = 1;
+ #[must_use]
+ fn foo();
+}
+
+// @has 'toggle_item_contents/trait.BigTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods'
+pub trait BigTrait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+ fn baz();
+ fn quux();
+ fn frob();
+ fn greeble();
+ fn blap();
+ fn whoop();
+ fn pow();
+ fn bang();
+ fn oomph();
+ fn argh();
+ fn wap();
+ fn ouch();
+}
diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs
new file mode 100644
index 000000000..1aa74e596
--- /dev/null
+++ b/src/test/rustdoc/toggle-method.rs
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+
+// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Struct methods with no documentation should not be wrapped.
+//
+// @has foo/struct.Foo.html
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+pub struct Foo {
+}
+
+impl Foo {
+ pub fn not_documented() {}
+
+ /// is_documented is documented
+ pub fn is_documented() {}
+}
diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs
new file mode 100644
index 000000000..65e8daeb0
--- /dev/null
+++ b/src/test/rustdoc/toggle-trait-fn.rs
@@ -0,0 +1,23 @@
+#![crate_name = "foo"]
+
+// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Trait methods with no documentation should not be wrapped.
+//
+// @has foo/trait.Foo.html
+// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+pub trait Foo {
+ fn not_documented();
+
+ /// is_documented is documented
+ fn is_documented();
+
+ fn not_documented_optional() {}
+
+ /// is_documented_optional is documented
+ fn is_documented_optional() {}
+}
diff --git a/src/test/rustdoc/trait-alias-mention.rs b/src/test/rustdoc/trait-alias-mention.rs
new file mode 100644
index 000000000..6da0dc687
--- /dev/null
+++ b/src/test/rustdoc/trait-alias-mention.rs
@@ -0,0 +1,10 @@
+// aux-build:trait-alias-mention.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate trait_alias_mention;
+
+// @has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
+pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
+}
diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs
new file mode 100644
index 000000000..b5a97c610
--- /dev/null
+++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs
@@ -0,0 +1,65 @@
+pub trait MyTrait {
+ type Assoc;
+ const VALUE: u32 = 12;
+ fn trait_function(&self);
+ fn defaulted(&self) {}
+ fn defaulted_override(&self) {}
+}
+
+impl MyTrait for String {
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+ type Assoc = ();
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+ const VALUE: u32 = 5;
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ fn trait_function(&self) {}
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+ fn defaulted_override(&self) {}
+}
+
+impl MyTrait for Vec<u8> {
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+ type Assoc = ();
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+ const VALUE: u32 = 5;
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+ fn trait_function(&self) {}
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+ fn defaulted_override(&self) {}
+}
+
+impl MyTrait for MyStruct {
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="associatedtype"]/@href' trait.MyTrait.html#associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+ type Assoc = bool;
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+ const VALUE: u32 = 20;
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ fn trait_function(&self) {}
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+ fn defaulted_override(&self) {}
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+}
+
+pub struct MyStruct;
+
+// We check that associated items with default values aren't generated in the implementors list.
+impl MyTrait for (u8, u8) {
+ // @!has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-4"]'
+ type Assoc = bool;
+ fn trait_function(&self) {}
+}
diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs
new file mode 100644
index 000000000..4f7e2dfe3
--- /dev/null
+++ b/src/test/rustdoc/trait-impl.rs
@@ -0,0 +1,47 @@
+pub trait Trait {
+ /// Some long docs here.
+ ///
+ /// These docs are long enough that a link will be added to the end.
+ fn a();
+
+ /// These docs contain a [reference link].
+ ///
+ /// [reference link]: https://example.com
+ fn b();
+
+ /// ```
+ /// This code block should not be in the output, but a Read more link should be generated
+ /// ```
+ fn c();
+
+ /// Escaped formatting a\*b\*c\* works
+ fn d();
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+ // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'Some long docs'
+ // @!has - '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'link will be added'
+ // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a' 'Read more'
+ // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.a'
+ fn a() {}
+
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p' 'These docs contain'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'reference link'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'https://example.com'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'Read more'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.b'
+ fn b() {}
+
+ // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]/p' 'code block'
+ // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a' 'Read more'
+ // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.c'
+ fn c() {}
+
+ // @has - '//*[@id="method.d"]/../../div[@class="docblock"]/p' 'Escaped formatting a*b*c* works'
+ // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
+ fn d() {}
+
+ // @has - '//*[@id="impl-Trait-for-Struct"]/h3//a/@href' 'trait.Trait.html'
+}
diff --git a/src/test/rustdoc/trait-self-link.rs b/src/test/rustdoc/trait-self-link.rs
new file mode 100644
index 000000000..e311dadff
--- /dev/null
+++ b/src/test/rustdoc/trait-self-link.rs
@@ -0,0 +1,6 @@
+// @has trait_self_link/trait.Foo.html //a/@href trait.Foo.html
+pub trait Foo {}
+
+pub struct Bar;
+
+impl Foo for Bar {}
diff --git a/src/test/rustdoc/trait-src-link.rs b/src/test/rustdoc/trait-src-link.rs
new file mode 100644
index 000000000..a6367efba
--- /dev/null
+++ b/src/test/rustdoc/trait-src-link.rs
@@ -0,0 +1,26 @@
+#![crate_name = "quix"]
+pub trait Foo {
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source'
+ fn required();
+
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+ fn provided() {}
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source'
+ fn required() {}
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+}
+
+pub struct Baz;
+
+impl Foo for Baz {
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source'
+ fn required() {}
+
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source'
+ fn provided() {}
+}
diff --git a/src/test/rustdoc/trait-visibility.rs b/src/test/rustdoc/trait-visibility.rs
new file mode 100644
index 000000000..8ba3ee03a
--- /dev/null
+++ b/src/test/rustdoc/trait-visibility.rs
@@ -0,0 +1,8 @@
+// aux-build:trait-visibility.rs
+
+#![crate_name = "foo"]
+
+extern crate trait_visibility;
+
+// @has foo/trait.Bar.html '//a[@href="#tymethod.foo"]/..' "fn foo()"
+pub use trait_visibility::Bar;
diff --git a/src/test/rustdoc/trait_alias.rs b/src/test/rustdoc/trait_alias.rs
new file mode 100644
index 000000000..a0c657d9a
--- /dev/null
+++ b/src/test/rustdoc/trait_alias.rs
@@ -0,0 +1,26 @@
+#![feature(trait_alias)]
+
+#![crate_name = "foo"]
+
+use std::fmt::Debug;
+
+// @has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias'
+// @has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
+// @has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo'
+
+// @has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
+// @has foo/index.html '//a[@class="traitalias"]' 'CopyAlias'
+// @has foo/index.html '//a[@class="traitalias"]' 'Alias2'
+// @has foo/index.html '//a[@class="traitalias"]' 'Foo'
+
+// @has foo/traitalias.CopyAlias.html
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;'
+pub trait CopyAlias = Copy;
+// @has foo/traitalias.Alias2.html
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
+pub trait Alias2 = Copy + Debug;
+// @has foo/traitalias.Foo.html
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
+pub trait Foo<T> = Into<T> + Debug;
+// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
+pub fn bar<T>() where T: Alias2 {}
diff --git a/src/test/rustdoc/traits-in-bodies-private.rs b/src/test/rustdoc/traits-in-bodies-private.rs
new file mode 100644
index 000000000..96b7c4f9d
--- /dev/null
+++ b/src/test/rustdoc/traits-in-bodies-private.rs
@@ -0,0 +1,13 @@
+// when implementing the fix for traits-in-bodies, there was an ICE when documenting private items
+// and a trait was defined in non-module scope
+
+// compile-flags:--document-private-items
+
+// @has traits_in_bodies_private/struct.SomeStruct.html
+// @!has - '//code' 'impl HiddenTrait for SomeStruct'
+pub struct SomeStruct;
+
+fn __implementation_details() {
+ trait HiddenTrait {}
+ impl HiddenTrait for SomeStruct {}
+}
diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs
new file mode 100644
index 000000000..6d450a625
--- /dev/null
+++ b/src/test/rustdoc/traits-in-bodies.rs
@@ -0,0 +1,52 @@
+//prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it
+//didn't see that `SomeStruct` implemented `Clone`
+
+pub struct Bounded<T: Clone>(T);
+
+// @has traits_in_bodies/struct.SomeStruct.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
+pub struct SomeStruct;
+
+fn asdf() -> Bounded<SomeStruct> {
+ impl Clone for SomeStruct {
+ fn clone(&self) -> SomeStruct {
+ SomeStruct
+ }
+ }
+
+ Bounded(SomeStruct)
+}
+
+// @has traits_in_bodies/struct.Point.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Copy for Point'
+#[derive(Clone)]
+pub struct Point {
+ x: i32,
+ y: i32,
+}
+
+const _FOO: () = {
+ impl Copy for Point {}
+ ()
+};
+
+// @has traits_in_bodies/struct.Inception.html
+// @has - '//h3[@class="code-header in-band"]' 'impl Clone for Inception'
+pub struct Inception;
+
+static _BAR: usize = {
+ trait HiddenTrait {
+ fn hidden_fn(&self) {
+ for _ in 0..5 {
+ impl Clone for Inception {
+ fn clone(&self) -> Self {
+ // we need to go deeper
+ Inception
+ }
+ }
+ }
+ }
+ }
+
+ 5
+};
diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs
new file mode 100644
index 000000000..31426131b
--- /dev/null
+++ b/src/test/rustdoc/tuple-struct-fields-doc.rs
@@ -0,0 +1,50 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//h2[@id="fields"]' 'Tuple Fields'
+// @has - '//h3[@class="sidebar-title"]/a[@href="#fields"]' 'Tuple Fields'
+// @has - '//*[@id="structfield.0"]' '0: u32'
+// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'hello'
+// @!has - '//*[@id="structfield.1"]'
+// @has - '//*[@id="structfield.2"]' '2: char'
+// @has - '//*[@id="structfield.3"]' '3: i8'
+// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'not hello'
+pub struct Foo(
+ /// hello
+ pub u32,
+ char,
+ pub char,
+ /// not hello
+ pub i8,
+);
+
+// @has foo/enum.Bar.html
+// @has - '//pre[@class="rust enum"]' 'BarVariant(String),'
+// @matches - '//*[@id="variant.BarVariant.fields"]/h4' '^Tuple Fields$'
+// @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
+// @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
+// @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$'
+// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox'
+// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox'
+// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$'
+pub enum Bar {
+ BarVariant(
+ /// Hello docs
+ String
+ ),
+ FooVariant {
+ /// hello
+ x: u32,
+ },
+ BazVariant(
+ String,
+ /// dox
+ u32,
+ ),
+ OtherVariant(
+ /// dox
+ String,
+ u32,
+ ),
+ QuuxVariant(String),
+}
diff --git a/src/test/rustdoc/tuples.link1_i32.html b/src/test/rustdoc/tuples.link1_i32.html
new file mode 100644
index 000000000..4efde28ed
--- /dev/null
+++ b/src/test/rustdoc/tuples.link1_i32.html
@@ -0,0 +1 @@
+<code>pub fn tuple1(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)</code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.link1_t.html b/src/test/rustdoc/tuples.link1_t.html
new file mode 100644
index 000000000..1cbaec057
--- /dev/null
+++ b/src/test/rustdoc/tuples.link1_t.html
@@ -0,0 +1 @@
+<code>pub fn tuple1_t&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a></code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.link2_i32.html b/src/test/rustdoc/tuples.link2_i32.html
new file mode 100644
index 000000000..77c8d81b8
--- /dev/null
+++ b/src/test/rustdoc/tuples.link2_i32.html
@@ -0,0 +1 @@
+<code>pub fn tuple2(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)</code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.link2_t.html b/src/test/rustdoc/tuples.link2_t.html
new file mode 100644
index 000000000..2477aa6be
--- /dev/null
+++ b/src/test/rustdoc/tuples.link2_t.html
@@ -0,0 +1 @@
+<code>pub fn tuple2_t&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a></code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.link2_tu.html b/src/test/rustdoc/tuples.link2_tu.html
new file mode 100644
index 000000000..b02f8dd8d
--- /dev/null
+++ b/src/test/rustdoc/tuples.link2_tu.html
@@ -0,0 +1 @@
+<code>pub fn tuple2_tu&lt;T, U&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a></code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.link_unit.html b/src/test/rustdoc/tuples.link_unit.html
new file mode 100644
index 000000000..839990e15
--- /dev/null
+++ b/src/test/rustdoc/tuples.link_unit.html
@@ -0,0 +1 @@
+<code>pub fn tuple0(x: <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>)</code> \ No newline at end of file
diff --git a/src/test/rustdoc/tuples.rs b/src/test/rustdoc/tuples.rs
new file mode 100644
index 000000000..62e2f9e7e
--- /dev/null
+++ b/src/test/rustdoc/tuples.rs
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.tuple0.html //pre 'pub fn tuple0(x: ())'
+// @snapshot link_unit - '//pre[@class="rust fn"]/code'
+pub fn tuple0(x: ()) -> () { x }
+// @has foo/fn.tuple1.html //pre 'pub fn tuple1(x: (i32,)) -> (i32,)'
+// @snapshot link1_i32 - '//pre[@class="rust fn"]/code'
+pub fn tuple1(x: (i32,)) -> (i32,) { x }
+// @has foo/fn.tuple2.html //pre 'pub fn tuple2(x: (i32, i32)) -> (i32, i32)'
+// @snapshot link2_i32 - '//pre[@class="rust fn"]/code'
+pub fn tuple2(x: (i32, i32)) -> (i32, i32) { x }
+// @has foo/fn.tuple1_t.html //pre 'pub fn tuple1_t<T>(x: (T,)) -> (T,)'
+// @snapshot link1_t - '//pre[@class="rust fn"]/code'
+pub fn tuple1_t<T>(x: (T,)) -> (T,) { x }
+// @has foo/fn.tuple2_t.html //pre 'pub fn tuple2_t<T>(x: (T, T)) -> (T, T)'
+// @snapshot link2_t - '//pre[@class="rust fn"]/code'
+pub fn tuple2_t<T>(x: (T, T)) -> (T, T) { x }
+// @has foo/fn.tuple2_tu.html //pre 'pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U)'
+// @snapshot link2_tu - '//pre[@class="rust fn"]/code'
+pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U) { x }
diff --git a/src/test/rustdoc/type-layout-flag-required.rs b/src/test/rustdoc/type-layout-flag-required.rs
new file mode 100644
index 000000000..a01fbd229
--- /dev/null
+++ b/src/test/rustdoc/type-layout-flag-required.rs
@@ -0,0 +1,4 @@
+// Tests that `--show-type-layout` is required in order to show layout info.
+
+// @!has type_layout_flag_required/struct.Foo.html 'Size: '
+pub struct Foo(usize);
diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs
new file mode 100644
index 000000000..e5c6e9dc3
--- /dev/null
+++ b/src/test/rustdoc/type-layout.rs
@@ -0,0 +1,85 @@
+// compile-flags: --show-type-layout -Z unstable-options
+
+// @has type_layout/struct.Foo.html 'Size: '
+// @has - ' bytes'
+// @has - '//*[@id="layout"]/a[@href="#layout"]' ''
+pub struct Foo {
+ pub a: usize,
+ b: Vec<String>,
+}
+
+// @has type_layout/enum.Bar.html 'Size: '
+// @has - ' bytes'
+pub enum Bar<'a> {
+ A(String),
+ B(&'a str, (std::collections::HashMap<String, usize>, Foo)),
+}
+
+// @has type_layout/union.Baz.html 'Size: '
+// @has - ' bytes'
+pub union Baz {
+ a: &'static str,
+ b: usize,
+ c: &'static [u8],
+}
+
+// @has type_layout/struct.X.html 'Size: '
+// @has - ' bytes'
+pub struct X(usize);
+
+// @has type_layout/struct.Y.html 'Size: '
+// @has - '1 byte'
+// @!has - ' bytes'
+pub struct Y(u8);
+
+// @has type_layout/struct.Z.html 'Size: '
+// @has - '0 bytes'
+pub struct Z;
+
+// We can't compute layout for generic types.
+// @has type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters'
+// @!has - 'Size: '
+pub struct Generic<T>(T);
+
+// We *can*, however, compute layout for types that are only generic over lifetimes,
+// because lifetimes are a type-system construct.
+// @has type_layout/struct.GenericLifetimes.html 'Size: '
+// @has - ' bytes'
+pub struct GenericLifetimes<'a>(&'a str);
+
+// @has type_layout/struct.Unsized.html 'Size: '
+// @has - '(unsized)'
+pub struct Unsized([u8]);
+
+// @has type_layout/type.TypeAlias.html 'Size: '
+// @has - ' bytes'
+pub type TypeAlias = X;
+
+// @has type_layout/type.GenericTypeAlias.html 'Size: '
+// @has - '8 bytes'
+pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
+
+// Regression test for the rustdoc equivalent of #85103.
+// @has type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.'
+pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;
+
+// @!has type_layout/trait.MyTrait.html 'Size: '
+pub trait MyTrait {}
+
+// @has type_layout/enum.Variants.html 'Size: '
+// @has - '2 bytes'
+// @has - '<code>A</code>: 0 bytes'
+// @has - '<code>B</code>: 1 byte'
+pub enum Variants {
+ A,
+ B(u8),
+}
+
+// @has type_layout/enum.WithNiche.html 'Size: '
+// @has - //p '4 bytes'
+// @has - '<code>None</code>: 0 bytes'
+// @has - '<code>Some</code>: 4 bytes'
+pub enum WithNiche {
+ None,
+ Some(std::num::NonZeroU32),
+}
diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs
new file mode 100644
index 000000000..4ecd62cde
--- /dev/null
+++ b/src/test/rustdoc/typedef.rs
@@ -0,0 +1,25 @@
+pub trait MyTrait {
+ fn method_on_mytrait() {}
+}
+
+pub struct MyStruct;
+
+impl MyStruct {
+ pub fn method_on_mystruct() {}
+}
+
+// @has typedef/type.MyAlias.html
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias'
+// @has - 'Alias docstring'
+// @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
+// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
+// @has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations'
+/// Alias docstring
+pub type MyAlias = MyStruct;
+
+impl MyAlias {
+ pub fn method_on_myalias() {}
+}
+
+impl MyTrait for MyAlias {}
diff --git a/src/test/rustdoc/unindent.md b/src/test/rustdoc/unindent.md
new file mode 100644
index 000000000..8e4e7a25a
--- /dev/null
+++ b/src/test/rustdoc/unindent.md
@@ -0,0 +1 @@
+Just some text.
diff --git a/src/test/rustdoc/unindent.rs b/src/test/rustdoc/unindent.rs
new file mode 100644
index 000000000..372af5f46
--- /dev/null
+++ b/src/test/rustdoc/unindent.rs
@@ -0,0 +1,62 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Example.html
+// @matches - '//pre[@class="rust rust-example-rendered"]' \
+// '(?m)let example = Example::new\(\)\n \.first\(\)\n \.second\(\)\n \.build\(\);\Z'
+/// ```rust
+/// let example = Example::new()
+/// .first()
+#[cfg_attr(not(feature = "one"), doc = " .second()")]
+/// .build();
+/// ```
+pub struct Example;
+
+// @has foo/struct.F.html
+// @matches - '//pre[@class="rust rust-example-rendered"]' \
+// '(?m)let example = Example::new\(\)\n \.first\(\)\n \.another\(\)\n \.build\(\);\Z'
+///```rust
+///let example = Example::new()
+/// .first()
+#[cfg_attr(not(feature = "one"), doc = " .another()")]
+/// .build();
+/// ```
+pub struct F;
+
+// @has foo/struct.G.html
+// @matches - '//pre[@class="rust rust-example-rendered"]' \
+// '(?m)let example = Example::new\(\)\n\.first\(\)\n \.another\(\)\n\.build\(\);\Z'
+///```rust
+///let example = Example::new()
+///.first()
+#[cfg_attr(not(feature = "one"), doc = " .another()")]
+///.build();
+///```
+pub struct G;
+
+// @has foo/struct.H.html
+// @has - '//div[@class="docblock"]/p' 'no whitespace lol'
+///no whitespace
+#[doc = " lol"]
+pub struct H;
+
+// @has foo/struct.I.html
+// @matches - '//pre[@class="rust rust-example-rendered"]' '(?m)4 whitespaces!\Z'
+/// 4 whitespaces!
+#[doc = "something"]
+pub struct I;
+
+// @has foo/struct.J.html
+// @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z'
+///a
+///no whitespace
+#[doc = include_str!("unindent.md")]
+pub struct J;
+
+// @has foo/struct.K.html
+// @matches - '//pre[@class="rust rust-example-rendered"]' '(?m)4 whitespaces!\Z'
+///a
+///
+/// 4 whitespaces!
+///
+#[doc = include_str!("unindent.md")]
+pub struct K;
diff --git a/src/test/rustdoc/union.rs b/src/test/rustdoc/union.rs
new file mode 100644
index 000000000..5a788eb1b
--- /dev/null
+++ b/src/test/rustdoc/union.rs
@@ -0,0 +1,8 @@
+// @has union/union.U.html
+pub union U {
+ // @has - //pre "pub a: u8"
+ pub a: u8,
+ // @has - //pre "/* private fields */"
+ // @!has - //pre "b: u16"
+ b: u16,
+}
diff --git a/src/test/rustdoc/unit-return.rs b/src/test/rustdoc/unit-return.rs
new file mode 100644
index 000000000..ae3a60315
--- /dev/null
+++ b/src/test/rustdoc/unit-return.rs
@@ -0,0 +1,17 @@
+// aux-build:unit-return.rs
+
+#![crate_name = "foo"]
+
+extern crate unit_return;
+
+// @has 'foo/fn.f0.html' '//*[@class="rust fn"]' 'F: FnMut(u8) + Clone'
+pub fn f0<F: FnMut(u8) + Clone>(f: F) {}
+
+// @has 'foo/fn.f1.html' '//*[@class="rust fn"]' 'F: FnMut(u16) + Clone'
+pub fn f1<F: FnMut(u16) -> () + Clone>(f: F) {}
+
+// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: FnMut(u32) + Clone'
+pub use unit_return::f2;
+
+// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: FnMut(u64) + Clone'
+pub use unit_return::f3;
diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs
new file mode 100644
index 000000000..b10b1b865
--- /dev/null
+++ b/src/test/rustdoc/universal-impl-trait.rs
@@ -0,0 +1,55 @@
+#![crate_name = "foo"]
+
+use std::io::Read;
+use std::borrow::Borrow;
+
+// @has foo/fn.foo.html
+// @has - //pre 'foo('
+// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"'
+// @matches - '_z: .+impl.+trait\.Copy\.html.+, impl.+trait\.Clone\.html'
+pub fn foo(_x: impl Clone, _y: i32, _z: (impl Copy, impl Clone)) {
+}
+
+pub trait Trait {
+ // @has foo/trait.Trait.html
+ // @has - 'method</a>('
+ // @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
+ fn method(&self, _x: impl std::fmt::Debug) {
+ }
+}
+
+pub struct S<T>(T);
+
+impl<T> S<T> {
+ // @has foo/struct.S.html
+ // @has - 'bar</a>('
+ // @matches - '_bar: impl <a class="trait" href="[^"]+/trait\.Copy\.html"'
+ pub fn bar(_bar: impl Copy) {
+ }
+
+ // @has - 'baz</a>('
+ // @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html'
+ pub fn baz(_baz: S<impl Clone>) {
+ }
+
+ // @has - 'qux</a>('
+ // @matches - 'trait\.Read\.html'
+ pub fn qux(_qux: impl IntoIterator<Item = S<impl Read>>) {
+ }
+}
+
+// @has - 'method</a>('
+// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
+impl<T> Trait for S<T> {}
+
+// @has foo/fn.much_universe.html
+// @matches - 'T:.+Borrow.+impl .+trait\.Trait\.html'
+// @matches - 'U:.+IntoIterator.+= impl.+Iterator\.html.+= impl.+Clone\.html'
+// @matches - '_: impl .+trait\.Read\.html.+ \+ .+trait\.Clone\.html'
+pub fn much_universe<
+ T: Borrow<impl Trait>,
+ U: IntoIterator<Item = impl Iterator<Item = impl Clone>>,
+>(
+ _: impl Read + Clone,
+) {
+}
diff --git a/src/test/rustdoc/unneeded-trait-implementations-title.rs b/src/test/rustdoc/unneeded-trait-implementations-title.rs
new file mode 100644
index 000000000..e1bcfd3b9
--- /dev/null
+++ b/src/test/rustdoc/unneeded-trait-implementations-title.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+
+pub struct Bar;
+
+// @count foo/struct.Bar.html '//*[@id="implementations"]' 0
diff --git a/src/test/rustdoc/use-attr.rs b/src/test/rustdoc/use-attr.rs
new file mode 100644
index 000000000..996b7bba6
--- /dev/null
+++ b/src/test/rustdoc/use-attr.rs
@@ -0,0 +1,8 @@
+// edition:2018
+
+// ICE when rustdoc encountered a use statement of a non-macro attribute (see #58054)
+
+// @has use_attr/index.html
+// @has - '//code' 'pub use proc_macro_attribute'
+pub use proc_macro_attribute;
+use proc_macro_derive;
diff --git a/src/test/rustdoc/useless_lifetime_bound.rs b/src/test/rustdoc/useless_lifetime_bound.rs
new file mode 100644
index 000000000..f530d8a65
--- /dev/null
+++ b/src/test/rustdoc/useless_lifetime_bound.rs
@@ -0,0 +1,13 @@
+use std::marker::PhantomData;
+
+// @has useless_lifetime_bound/struct.Scope.html
+// @!has - '//*[@class="rust struct"]' "'env: 'env"
+pub struct Scope<'env> {
+ _marker: PhantomData<&'env mut &'env ()>,
+}
+
+// @has useless_lifetime_bound/struct.Scope.html
+// @!has - '//*[@class="rust struct"]' "T: 'a + 'a"
+pub struct SomeStruct<'a, T: 'a> {
+ _marker: PhantomData<&'a T>,
+}
diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs
new file mode 100644
index 000000000..bd8f1775b
--- /dev/null
+++ b/src/test/rustdoc/variadic.rs
@@ -0,0 +1,4 @@
+extern "C" {
+ // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)'
+ pub fn foo(x: i32, ...);
+}
diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs
new file mode 100644
index 000000000..ae866deba
--- /dev/null
+++ b/src/test/rustdoc/version-separator-without-source.rs
@@ -0,0 +1,23 @@
+#![doc(html_no_source)]
+#![feature(staged_api)]
+#![stable(feature = "bar", since = "1.0")]
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub fn foo() {}
+
+// @has foo/struct.Bar.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub struct Bar;
+
+impl Bar {
+ // @has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0'
+ // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+ #[stable(feature = "foobar", since = "2.0")]
+ pub fn bar() {}
+}
diff --git a/src/test/rustdoc/viewpath-rename.rs b/src/test/rustdoc/viewpath-rename.rs
new file mode 100644
index 000000000..546127637
--- /dev/null
+++ b/src/test/rustdoc/viewpath-rename.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+
+pub mod io {
+ pub trait Reader { fn dummy(&self) { } }
+}
+
+pub enum Maybe<A> {
+ Just(A),
+ Nothing
+}
+
+// @has foo/prelude/index.html
+pub mod prelude {
+ // @has foo/prelude/index.html '//code' 'pub use io as FooIo;'
+ // @has foo/prelude/index.html '//code' 'pub use io::Reader as FooReader;'
+ #[doc(no_inline)] pub use io::{self as FooIo, Reader as FooReader};
+ // @has foo/prelude/index.html '//code' 'pub use Maybe;'
+ // @has foo/prelude/index.html '//code' 'pub use Maybe::Just as MaybeJust;'
+ // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;'
+ #[doc(no_inline)] pub use Maybe::{self, Just as MaybeJust, Nothing};
+}
diff --git a/src/test/rustdoc/viewpath-self.rs b/src/test/rustdoc/viewpath-self.rs
new file mode 100644
index 000000000..a6b659295
--- /dev/null
+++ b/src/test/rustdoc/viewpath-self.rs
@@ -0,0 +1,21 @@
+#![crate_name = "foo"]
+
+pub mod io {
+ pub trait Reader { fn dummy(&self) { } }
+}
+
+pub enum Maybe<A> {
+ Just(A),
+ Nothing
+}
+
+// @has foo/prelude/index.html
+pub mod prelude {
+ // @has foo/prelude/index.html '//code' 'pub use io;'
+ // @has foo/prelude/index.html '//code' 'pub use io::Reader;'
+ #[doc(no_inline)] pub use io::{self, Reader};
+ // @has foo/prelude/index.html '//code' 'pub use Maybe;'
+ // @has foo/prelude/index.html '//code' 'pub use Maybe::Just;'
+ // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;'
+ #[doc(no_inline)] pub use Maybe::{self, Just, Nothing};
+}
diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs
new file mode 100644
index 000000000..4099b54f0
--- /dev/null
+++ b/src/test/rustdoc/visibility.rs
@@ -0,0 +1,105 @@
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+// @!has 'foo/index.html' '//a[@href="struct.FooPublic.html"]/..' 'FooPublic 🔒'
+// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic'
+pub struct FooPublic;
+// @has 'foo/index.html' '//a[@href="struct.FooJustCrate.html"]/..' 'FooJustCrate 🔒'
+// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate'
+pub(crate) struct FooJustCrate;
+// @has 'foo/index.html' '//a[@href="struct.FooPubCrate.html"]/..' 'FooPubCrate 🔒'
+// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate'
+pub(crate) struct FooPubCrate;
+// @has 'foo/index.html' '//a[@href="struct.FooSelf.html"]/..' 'FooSelf 🔒'
+// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf'
+pub(self) struct FooSelf;
+// @has 'foo/index.html' '//a[@href="struct.FooInSelf.html"]/..' 'FooInSelf 🔒'
+// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf'
+pub(in self) struct FooInSelf;
+// @has 'foo/index.html' '//a[@href="struct.FooPriv.html"]/..' 'FooPriv 🔒'
+// @has 'foo/struct.FooPriv.html' '//pre' 'pub(crate) struct FooPriv'
+struct FooPriv;
+
+// @!has 'foo/index.html' '//a[@href="pub_mod/index.html"]/..' 'pub_mod 🔒'
+pub mod pub_mod {}
+
+// @has 'foo/index.html' '//a[@href="pub_crate_mod/index.html"]/..' 'pub_crate_mod 🔒'
+pub(crate) mod pub_crate_mod {}
+
+// @has 'foo/index.html' '//a[@href="a/index.html"]/..' 'a 🔒'
+mod a {
+ // @has 'foo/a/index.html' '//a[@href="struct.FooASuper.html"]/..' 'FooASuper 🔒'
+ // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper'
+ pub(super) struct FooASuper;
+ // @has 'foo/a/index.html' '//a[@href="struct.FooAInSuper.html"]/..' 'FooAInSuper 🔒'
+ // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper'
+ pub(in super) struct FooAInSuper;
+ // @has 'foo/a/index.html' '//a[@href="struct.FooAInA.html"]/..' 'FooAInA 🔒'
+ // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA'
+ // @!has 'foo/a/struct.FooAInA.html' '//pre' 'pub'
+ pub(in a) struct FooAInA;
+ // @has 'foo/a/index.html' '//a[@href="struct.FooAPriv.html"]/..' 'FooAPriv 🔒'
+ // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv'
+ // @!has 'foo/a/struct.FooAPriv.html' '//pre' 'pub'
+ struct FooAPriv;
+
+ // @has 'foo/a/index.html' '//a[@href="b/index.html"]/..' 'b 🔒'
+ mod b {
+ // @has 'foo/a/b/index.html' '//a[@href="struct.FooBSuper.html"]/..' 'FooBSuper 🔒'
+ // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper'
+ pub(super) struct FooBSuper;
+ // @has 'foo/a/b/index.html' '//a[@href="struct.FooBInSuperSuper.html"]/..' 'FooBInSuperSuper 🔒'
+ // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper'
+ pub(in super::super) struct FooBInSuperSuper;
+ // @has 'foo/a/b/index.html' '//a[@href="struct.FooBInAB.html"]/..' 'FooBInAB 🔒'
+ // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB'
+ // @!has 'foo/a/b/struct.FooBInAB.html' '//pre' 'pub'
+ pub(in a::b) struct FooBInAB;
+ // @has 'foo/a/b/index.html' '//a[@href="struct.FooBPriv.html"]/..' 'FooBPriv 🔒'
+ // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv'
+ // @!has 'foo/a/b/struct.FooBPriv.html' '//pre' 'pub'
+ struct FooBPriv;
+
+ // @!has 'foo/a/b/index.html' '//a[@href="struct.FooBPub.html"]/..' 'FooBPub 🔒'
+ // @has 'foo/a/b/struct.FooBPub.html' '//pre' 'pub struct FooBPub'
+ pub struct FooBPub;
+ }
+}
+
+// @has 'foo/trait.PubTrait.html' '//pre' 'pub trait PubTrait'
+//
+// @has 'foo/trait.PubTrait.html' '//pre' 'type Type;'
+// @!has 'foo/trait.PubTrait.html' '//pre' 'pub type Type;'
+//
+// @has 'foo/trait.PubTrait.html' '//pre' 'const CONST: usize;'
+// @!has 'foo/trait.PubTrait.html' '//pre' 'pub const CONST: usize;'
+//
+// @has 'foo/trait.PubTrait.html' '//pre' 'fn function();'
+// @!has 'foo/trait.PubTrait.html' '//pre' 'pub fn function();'
+//
+// @!has 'foo/index.html' '//a[@href="trait.PubTrait.html"]/..' 'PubTrait 🔒'
+
+pub trait PubTrait {
+ type Type;
+ const CONST: usize;
+ fn function();
+}
+
+// @has 'foo/index.html' '//a[@href="trait.PrivTrait.html"]/..' 'PrivTrait 🔒'
+trait PrivTrait {}
+
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'type Type'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub type Type'
+//
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'const CONST: usize'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub const CONST: usize'
+//
+// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'fn function()'
+// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub fn function()'
+
+impl PubTrait for FooPublic {
+ type Type = usize;
+ const CONST: usize = 0;
+ fn function() {}
+}
diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs
new file mode 100644
index 000000000..3150a8ea0
--- /dev/null
+++ b/src/test/rustdoc/where-clause-order.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+pub trait SomeTrait<Rhs = Self>
+where
+ Rhs: ?Sized,
+{
+}
+
+// @has 'foo/trait.SomeTrait.html'
+// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
+where
+ A: PartialOrd<A> + PartialEq<A>,
+ B: PartialOrd<B> + PartialEq<B>,
+ C: PartialOrd<C> + PartialEq<C>,
+ D: PartialOrd<D> + PartialEq<D>,
+ E: PartialOrd<E> + PartialEq<E> + ?Sized,
+{
+}
diff --git a/src/test/rustdoc/where-sized.rs b/src/test/rustdoc/where-sized.rs
new file mode 100644
index 000000000..fe7cad8c3
--- /dev/null
+++ b/src/test/rustdoc/where-sized.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="rust fn"]' 'pub fn foo<X, Y: ?Sized>(_: &X)'
+// @has - '//*[@class="rust fn"]' 'where X: ?Sized,'
+pub fn foo<X, Y: ?Sized>(_: &X) where X: ?Sized {}
diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
new file mode 100644
index 000000000..0133bcaeb
--- /dev/null
+++ b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
@@ -0,0 +1 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd&lt;T&gt;(_) <br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div> \ No newline at end of file
diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
new file mode 100644
index 000000000..54026ff03
--- /dev/null
+++ b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+ type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160; <span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
+}</code></pre></div> \ No newline at end of file
diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs
new file mode 100644
index 000000000..50a5722fb
--- /dev/null
+++ b/src/test/rustdoc/where.rs
@@ -0,0 +1,51 @@
+#![feature(generic_associated_types)]
+#![crate_name = "foo"]
+
+pub trait MyTrait { fn dummy(&self) { } }
+
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
+pub struct Alpha<A>(A) where A: MyTrait;
+// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
+pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
+// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>() where C: MyTrait"
+pub fn charlie<C>() where C: MyTrait {}
+
+pub struct Delta<D>(D);
+
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<D> Delta<D> where D: MyTrait"
+impl<D> Delta<D> where D: MyTrait {
+ pub fn delta() {}
+}
+
+pub struct Echo<E>(E);
+
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T>([T; 1])
+where
+ T: MyTrait;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+ type Item<'a> where Self: 'a;
+}
+
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<E> MyTrait for Echo<E> where E: MyTrait"
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
+// "impl<E> MyTrait for Echo<E> where E: MyTrait"
+impl<E> MyTrait for Echo<E> where E: MyTrait {}
+
+pub enum Foxtrot<F> { Foxtrot1(F) }
+
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
+// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
+impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
+
+// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
+// "type Golf<T> where T: Clone, = (T, T)"
+pub type Golf<T> where T: Clone = (T, T);
diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum.html b/src/test/rustdoc/whitespace-after-where-clause.enum.html
new file mode 100644
index 000000000..9e5bf45ae
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.enum.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+ Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+ Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum2.html b/src/test/rustdoc/whitespace-after-where-clause.enum2.html
new file mode 100644
index 000000000..6bc47beae
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.enum2.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+ Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+ Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.rs b/src/test/rustdoc/whitespace-after-where-clause.rs
new file mode 100644
index 000000000..c36386a2a
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.rs
@@ -0,0 +1,77 @@
+// This test ensures there is no whitespace before the first brace of
+// trait, enum, struct and union items when they have a where clause.
+
+#![crate_name = "foo"]
+
+// @has 'foo/trait.ToOwned.html'
+// @snapshot trait - '//*[@class="docblock item-decl"]'
+pub trait ToOwned<T>
+where T: Clone
+{
+ type Owned;
+ fn to_owned(&self) -> Self::Owned;
+ fn whatever(&self) -> T;
+}
+
+// @has 'foo/trait.ToOwned2.html'
+// @snapshot trait2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub trait ToOwned2<T: Clone> {
+ type Owned;
+ fn to_owned(&self) -> Self::Owned;
+ fn whatever(&self) -> T;
+}
+
+// @has 'foo/enum.Cow.html'
+// @snapshot enum - '//*[@class="docblock item-decl"]'
+pub enum Cow<'a, B: ?Sized + 'a>
+where
+ B: ToOwned<Clone>,
+{
+ Borrowed(&'a B),
+ Whatever(u32),
+}
+
+// @has 'foo/enum.Cow2.html'
+// @snapshot enum2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+ Borrowed(&'a B),
+ Whatever(u32),
+}
+
+// @has 'foo/struct.Struct.html'
+// @snapshot struct - '//*[@class="docblock item-decl"]'
+pub struct Struct<'a, B: ?Sized + 'a>
+where
+ B: ToOwned<Clone>,
+{
+ pub a: &'a B,
+ pub b: u32,
+}
+
+// @has 'foo/struct.Struct2.html'
+// @snapshot struct2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+ pub a: &'a B,
+ pub b: u32,
+}
+
+// @has 'foo/union.Union.html'
+// @snapshot union - '//*[@class="docblock item-decl"]'
+pub union Union<'a, B: ?Sized + 'a>
+where
+ B: ToOwned<Clone>,
+{
+ a: &'a B,
+ b: u32,
+}
+
+// @has 'foo/union.Union2.html'
+// @snapshot union2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+ a: &'a B,
+ b: u32,
+}
diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct.html b/src/test/rustdoc/whitespace-after-where-clause.struct.html
new file mode 100644
index 000000000..236cc3b30
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.struct.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+ pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+ pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct2.html b/src/test/rustdoc/whitespace-after-where-clause.struct2.html
new file mode 100644
index 000000000..47f5c6ba9
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.struct2.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+ pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+ pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait.html b/src/test/rustdoc/whitespace-after-where-clause.trait.html
new file mode 100644
index 000000000..98f03b837
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.trait.html
@@ -0,0 +1,6 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned&lt;T&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,&#160;</span>{
+ type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
+
+ fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>;
+<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait2.html b/src/test/rustdoc/whitespace-after-where-clause.trait2.html
new file mode 100644
index 000000000..35052869e
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.trait2.html
@@ -0,0 +1,6 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned2&lt;T:&#160;<a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; {
+ type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
+
+ fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>;
+<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.union.html b/src/test/rustdoc/whitespace-after-where-clause.union.html
new file mode 100644
index 000000000..97e1bbcf3
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.union.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+ /* private fields */
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.union2.html b/src/test/rustdoc/whitespace-after-where-clause.union2.html
new file mode 100644
index 000000000..6c752a8b4
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.union2.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust union"><code>pub union Union2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+ /* private fields */
+}</code></pre></div>
diff --git a/src/test/rustdoc/without-redirect.rs b/src/test/rustdoc/without-redirect.rs
new file mode 100644
index 000000000..a076f8a3c
--- /dev/null
+++ b/src/test/rustdoc/without-redirect.rs
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+
+// @has foo/macro.bar.html
+// @has foo/macro.bar!.html
+// @!has foo/bar.m.html
+#[macro_export]
+macro_rules! bar {
+ () => {}
+}
+
+// @has foo/struct.Bar.html
+// @!has foo/Bar.t.html
+pub struct Bar;
diff --git a/src/test/rustdoc/wrapping.rs b/src/test/rustdoc/wrapping.rs
new file mode 100644
index 000000000..8d8221bcd
--- /dev/null
+++ b/src/test/rustdoc/wrapping.rs
@@ -0,0 +1,5 @@
+use std::fmt::Debug;
+
+// @has 'wrapping/fn.foo.html' '//pre[@class="rust fn"]' 'pub fn foo() -> impl Debug'
+// @count - '//pre[@class="rust fn"]/br' 0
+pub fn foo() -> impl Debug {}