1
Fork 0

Auto merge of #109824 - GuillaumeGomez:rollup-i5r4uts, r=GuillaumeGomez

Rollup of 7 pull requests

Successful merges:

 - #109104 (rustdoc: Fix invalid suggestions on ambiguous intra doc links v2)
 - #109443 (Move `doc(primitive)` future incompat warning to `invalid_doc_attributes`)
 - #109680 (Fix subslice capture in closure)
 - #109798 (fluent_messages macro: don't emit the OS error in a note)
 - #109805 (Source map cleanups)
 - #109818 (rustdoc: Add GUI test for jump to collapsed item)
 - #109820 (rustdoc-search: update docs for comma in `?` help popover)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-31 20:38:06 +00:00
commit 5e1d3299a2
83 changed files with 1025 additions and 411 deletions

View file

@ -54,7 +54,7 @@ impl base::BangProcMacro for BangProcMacro {
) -> Result<TokenStream, ErrorGuaranteed> { ) -> Result<TokenStream, ErrorGuaranteed> {
let _timer = let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
recorder.record_arg_with_span(ecx.expansion_descr(), span); recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span);
}); });
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
@ -85,7 +85,7 @@ impl base::AttrProcMacro for AttrProcMacro {
) -> Result<TokenStream, ErrorGuaranteed> { ) -> Result<TokenStream, ErrorGuaranteed> {
let _timer = let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
recorder.record_arg_with_span(ecx.expansion_descr(), span); recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span);
}); });
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
@ -134,7 +134,11 @@ impl MultiItemModifier for DeriveProcMacro {
let stream = { let stream = {
let _timer = let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
recorder.record_arg_with_span(ecx.expansion_descr(), span); recorder.record_arg_with_span(
ecx.sess.source_map(),
ecx.expansion_descr(),
span,
);
}); });
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx); let strategy = exec_strategy(ecx);

View file

@ -225,7 +225,7 @@ declare_features! (
(active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
/// Allows using compiler's own crates. /// Allows using compiler's own crates.
(active, rustc_private, "1.0.0", Some(27812), None), (active, rustc_private, "1.0.0", Some(27812), None),
/// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`. /// Allows using internal rustdoc features like `doc(keyword)`.
(active, rustdoc_internals, "1.58.0", Some(90418), None), (active, rustdoc_internals, "1.58.0", Some(90418), None),
/// Allows using the `rustdoc::missing_doc_code_examples` lint /// Allows using the `rustdoc::missing_doc_code_examples` lint
(active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None), (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),

View file

@ -778,6 +778,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
definition of a trait, it's currently in experimental form and should be changed before \ definition of a trait, it's currently in experimental form and should be changed before \
being exposed outside of the std" being exposed outside of the std"
), ),
rustc_attr!(
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
r#"`rustc_doc_primitive` is a rustc internal attribute"#,
),
// ========================================================================== // ==========================================================================
// Internal attributes, Testing: // Internal attributes, Testing:

View file

@ -1893,14 +1893,13 @@ fn restrict_capture_precision(
for (i, proj) in place.projections.iter().enumerate() { for (i, proj) in place.projections.iter().enumerate() {
match proj.kind { match proj.kind {
ProjectionKind::Index => { ProjectionKind::Index | ProjectionKind::Subslice => {
// Arrays are completely captured, so we drop Index projections // Arrays are completely captured, so we drop Index and Subslice projections
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i); truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
return (place, curr_mode); return (place, curr_mode);
} }
ProjectionKind::Deref => {} ProjectionKind::Deref => {}
ProjectionKind::Field(..) => {} // ignore ProjectionKind::Field(..) => {} // ignore
ProjectionKind::Subslice => {} // We never capture this
} }
} }

View file

@ -292,7 +292,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
override_queries: config.override_queries, override_queries: config.override_queries,
}; };
rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
let r = { let r = {
let _sess_abort_error = OnDrop(|| { let _sess_abort_error = OnDrop(|| {
compiler.sess.finish_diagnostics(registry); compiler.sess.finish_diagnostics(registry);

View file

@ -15,8 +15,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fs::File, fs::read_to_string,
io::Read,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use syn::{parse_macro_input, Ident, LitStr}; use syn::{parse_macro_input, Ident, LitStr};
@ -95,22 +94,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
// As this macro also outputs an `include_str!` for this file, the macro will always be // As this macro also outputs an `include_str!` for this file, the macro will always be
// re-executed when the file changes. // re-executed when the file changes.
let mut resource_file = match File::open(absolute_ftl_path) { let resource_contents = match read_to_string(absolute_ftl_path) {
Ok(resource_file) => resource_file, Ok(resource_contents) => resource_contents,
Err(e) => { Err(e) => {
Diagnostic::spanned(resource_span, Level::Error, "could not open Fluent resource") Diagnostic::spanned(
.note(e.to_string()) resource_span,
Level::Error,
format!("could not open Fluent resource: {}", e.to_string()),
)
.emit(); .emit();
return failed(&crate_name); return failed(&crate_name);
} }
}; };
let mut resource_contents = String::new();
if let Err(e) = resource_file.read_to_string(&mut resource_contents) {
Diagnostic::spanned(resource_span, Level::Error, "could not read Fluent resource")
.note(e.to_string())
.emit();
return failed(&crate_name);
}
let mut bad = false; let mut bad = false;
for esc in ["\\n", "\\\"", "\\'"] { for esc in ["\\n", "\\\"", "\\'"] {
for _ in resource_contents.matches(esc) { for _ in resource_contents.matches(esc) {

View file

@ -148,9 +148,6 @@ passes_doc_test_unknown =
passes_doc_test_takes_list = passes_doc_test_takes_list =
`#[doc(test(...)]` takes a list of attributes `#[doc(test(...)]` takes a list of attributes
passes_doc_primitive =
`doc(primitive)` should never have been stable
passes_doc_cfg_hide_takes_list = passes_doc_cfg_hide_takes_list =
`#[doc(cfg_hide(...)]` takes a list of attributes `#[doc(cfg_hide(...)]` takes a list of attributes

View file

@ -1109,17 +1109,6 @@ impl CheckAttrVisitor<'_> {
} }
} }
sym::primitive => {
if !self.tcx.features().rustdoc_internals {
self.tcx.emit_spanned_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
i_meta.span,
errors::DocPrimitive,
);
}
}
_ => { _ => {
let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
if i_meta.has_name(sym::spotlight) { if i_meta.has_name(sym::spotlight) {

View file

@ -288,10 +288,6 @@ pub struct DocTestTakesList;
#[diag(passes_doc_cfg_hide_takes_list)] #[diag(passes_doc_cfg_hide_takes_list)]
pub struct DocCfgHideTakesList; pub struct DocCfgHideTakesList;
#[derive(LintDiagnostic)]
#[diag(passes_doc_primitive)]
pub struct DocPrimitive;
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]
#[diag(passes_doc_test_unknown_any)] #[diag(passes_doc_test_unknown_any)]
pub struct DocTestUnknownAny { pub struct DocTestUnknownAny {

View file

@ -339,12 +339,14 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool {
attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner) attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner)
} }
/// Has `#[doc(primitive)]` or `#[doc(keyword)]`. /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool {
for attr in attrs { for attr in attrs {
if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() { if attr.has_name(sym::rustc_doc_primitive) {
return true;
} else if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
if item.has_name(sym::primitive) || item.has_name(sym::keyword) { if item.has_name(sym::keyword) {
return true; return true;
} }
} }

View file

@ -87,6 +87,14 @@ pub struct SessionGlobals {
symbol_interner: symbol::Interner, symbol_interner: symbol::Interner,
span_interner: Lock<span_encoding::SpanInterner>, span_interner: Lock<span_encoding::SpanInterner>,
hygiene_data: Lock<hygiene::HygieneData>, hygiene_data: Lock<hygiene::HygieneData>,
/// A reference to the source map in the `Session`. It's an `Option`
/// because it can't be initialized until `Session` is created, which
/// happens after `SessionGlobals`. `set_source_map` does the
/// initialization.
///
/// This field should only be used in places where the `Session` is truly
/// not available, such as `<Span as Debug>::fmt`.
source_map: Lock<Option<Lrc<SourceMap>>>, source_map: Lock<Option<Lrc<SourceMap>>>,
} }
@ -1013,16 +1021,9 @@ impl<D: Decoder> Decodable<D> for Span {
} }
} }
/// Calls the provided closure, using the provided `SourceMap` to format /// Insert `source_map` into the session globals for the duration of the
/// any spans that are debug-printed during the closure's execution. /// closure's execution.
/// pub fn set_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
/// (see `rustc_interface::callbacks::span_debug1`). However, some parts
/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
/// a `TyCtxt` is available. In this case, we fall back to
/// the `SourceMap` provided to this function. If that is not available,
/// we fall back to printing the raw `Span` field values.
pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
with_session_globals(|session_globals| { with_session_globals(|session_globals| {
*session_globals.source_map.borrow_mut() = Some(source_map); *session_globals.source_map.borrow_mut() = Some(source_map);
}); });
@ -1041,6 +1042,8 @@ pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) ->
impl fmt::Debug for Span { impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Use the global `SourceMap` to print the span. If that's not
// available, fall back to printing the raw values.
with_session_globals(|session_globals| { with_session_globals(|session_globals| {
if let Some(source_map) = &*session_globals.source_map.borrow() { if let Some(source_map) = &*session_globals.source_map.borrow() {
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())

View file

@ -1,3 +1,5 @@
use crate::source_map::SourceMap;
use std::borrow::Borrow; use std::borrow::Borrow;
use rustc_data_structures::profiling::EventArgRecorder; use rustc_data_structures::profiling::EventArgRecorder;
@ -11,25 +13,17 @@ pub trait SpannedEventArgRecorder {
/// ///
/// Note: when self-profiling with costly event arguments, at least one argument /// Note: when self-profiling with costly event arguments, at least one argument
/// needs to be recorded. A panic will be triggered if that doesn't happen. /// needs to be recorded. A panic will be triggered if that doesn't happen.
fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span) fn record_arg_with_span<A>(&mut self, source_map: &SourceMap, event_arg: A, span: crate::Span)
where where
A: Borrow<str> + Into<String>; A: Borrow<str> + Into<String>;
} }
impl SpannedEventArgRecorder for EventArgRecorder<'_> { impl SpannedEventArgRecorder for EventArgRecorder<'_> {
fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span) fn record_arg_with_span<A>(&mut self, source_map: &SourceMap, event_arg: A, span: crate::Span)
where where
A: Borrow<str> + Into<String>, A: Borrow<str> + Into<String>,
{ {
self.record_arg(event_arg); self.record_arg(event_arg);
self.record_arg(source_map.span_to_embeddable_string(span));
let span_arg = crate::with_session_globals(|session_globals| {
if let Some(source_map) = &*session_globals.source_map.borrow() {
source_map.span_to_embeddable_string(span)
} else {
format!("{span:?}")
}
});
self.record_arg(span_arg);
} }
} }

View file

@ -1247,6 +1247,7 @@ symbols! {
rustc_diagnostic_macros, rustc_diagnostic_macros,
rustc_dirty, rustc_dirty,
rustc_do_not_const_check, rustc_do_not_const_check,
rustc_doc_primitive,
rustc_dummy, rustc_dummy,
rustc_dump_env_program_clauses, rustc_dump_env_program_clauses,
rustc_dump_program_clauses, rustc_dump_program_clauses,

View file

@ -1,7 +1,8 @@
// `library/{std,core}/src/primitive_docs.rs` should have the same contents. // `library/{std,core}/src/primitive_docs.rs` should have the same contents.
// These are different files so that relative links work properly without // These are different files so that relative links work properly without
// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. // having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
#[doc(primitive = "bool")] #[cfg_attr(bootstrap, doc(primitive = "bool"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
#[doc(alias = "true")] #[doc(alias = "true")]
#[doc(alias = "false")] #[doc(alias = "false")]
/// The boolean type. /// The boolean type.
@ -63,7 +64,8 @@
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool {} mod prim_bool {}
#[doc(primitive = "never")] #[cfg_attr(bootstrap, doc(primitive = "never"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
#[doc(alias = "!")] #[doc(alias = "!")]
// //
/// The `!` type, also called "never". /// The `!` type, also called "never".
@ -274,7 +276,8 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type", issue = "35121")]
mod prim_never {} mod prim_never {}
#[doc(primitive = "char")] #[cfg_attr(bootstrap, doc(primitive = "char"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "char")]
#[allow(rustdoc::invalid_rust_codeblocks)] #[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type. /// A character type.
/// ///
@ -398,7 +401,8 @@ mod prim_never {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_char {} mod prim_char {}
#[doc(primitive = "unit")] #[cfg_attr(bootstrap, doc(primitive = "unit"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "unit")]
#[doc(alias = "(")] #[doc(alias = "(")]
#[doc(alias = ")")] #[doc(alias = ")")]
#[doc(alias = "()")] #[doc(alias = "()")]
@ -460,7 +464,8 @@ impl Copy for () {
// empty // empty
} }
#[doc(primitive = "pointer")] #[cfg_attr(bootstrap, doc(primitive = "pointer"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
#[doc(alias = "ptr")] #[doc(alias = "ptr")]
#[doc(alias = "*")] #[doc(alias = "*")]
#[doc(alias = "*const")] #[doc(alias = "*const")]
@ -577,7 +582,8 @@ impl Copy for () {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_pointer {} mod prim_pointer {}
#[doc(primitive = "array")] #[cfg_attr(bootstrap, doc(primitive = "array"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
#[doc(alias = "[]")] #[doc(alias = "[]")]
#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases #[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
#[doc(alias = "[T; N]")] #[doc(alias = "[T; N]")]
@ -778,7 +784,8 @@ mod prim_pointer {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_array {} mod prim_array {}
#[doc(primitive = "slice")] #[cfg_attr(bootstrap, doc(primitive = "slice"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "slice")]
#[doc(alias = "[")] #[doc(alias = "[")]
#[doc(alias = "]")] #[doc(alias = "]")]
#[doc(alias = "[]")] #[doc(alias = "[]")]
@ -870,7 +877,8 @@ mod prim_array {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {} mod prim_slice {}
#[doc(primitive = "str")] #[cfg_attr(bootstrap, doc(primitive = "str"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
/// String slices. /// String slices.
/// ///
/// *[See also the `std::str` module](crate::str).* /// *[See also the `std::str` module](crate::str).*
@ -937,7 +945,8 @@ mod prim_slice {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_str {} mod prim_str {}
#[doc(primitive = "tuple")] #[cfg_attr(bootstrap, doc(primitive = "tuple"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "tuple")]
#[doc(alias = "(")] #[doc(alias = "(")]
#[doc(alias = ")")] #[doc(alias = ")")]
#[doc(alias = "()")] #[doc(alias = "()")]
@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
// empty // empty
} }
#[doc(primitive = "f32")] #[cfg_attr(bootstrap, doc(primitive = "f32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f32")]
/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008). /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
/// ///
/// This type can represent a wide range of decimal numbers, like `3.5`, `27`, /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@ -1147,7 +1157,8 @@ impl<T: Copy> Copy for (T,) {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_f32 {} mod prim_f32 {}
#[doc(primitive = "f64")] #[cfg_attr(bootstrap, doc(primitive = "f64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f64")]
/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
/// ///
/// This type is very similar to [`f32`], but has increased /// This type is very similar to [`f32`], but has increased
@ -1162,67 +1173,78 @@ mod prim_f32 {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_f64 {} mod prim_f64 {}
#[doc(primitive = "i8")] #[cfg_attr(bootstrap, doc(primitive = "i8"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i8")]
// //
/// The 8-bit signed integer type. /// The 8-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i8 {} mod prim_i8 {}
#[doc(primitive = "i16")] #[cfg_attr(bootstrap, doc(primitive = "i16"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i16")]
// //
/// The 16-bit signed integer type. /// The 16-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i16 {} mod prim_i16 {}
#[doc(primitive = "i32")] #[cfg_attr(bootstrap, doc(primitive = "i32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i32")]
// //
/// The 32-bit signed integer type. /// The 32-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i32 {} mod prim_i32 {}
#[doc(primitive = "i64")] #[cfg_attr(bootstrap, doc(primitive = "i64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i64")]
// //
/// The 64-bit signed integer type. /// The 64-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i64 {} mod prim_i64 {}
#[doc(primitive = "i128")] #[cfg_attr(bootstrap, doc(primitive = "i128"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i128")]
// //
/// The 128-bit signed integer type. /// The 128-bit signed integer type.
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
mod prim_i128 {} mod prim_i128 {}
#[doc(primitive = "u8")] #[cfg_attr(bootstrap, doc(primitive = "u8"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u8")]
// //
/// The 8-bit unsigned integer type. /// The 8-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u8 {} mod prim_u8 {}
#[doc(primitive = "u16")] #[cfg_attr(bootstrap, doc(primitive = "u16"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u16")]
// //
/// The 16-bit unsigned integer type. /// The 16-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u16 {} mod prim_u16 {}
#[doc(primitive = "u32")] #[cfg_attr(bootstrap, doc(primitive = "u32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u32")]
// //
/// The 32-bit unsigned integer type. /// The 32-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u32 {} mod prim_u32 {}
#[doc(primitive = "u64")] #[cfg_attr(bootstrap, doc(primitive = "u64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u64")]
// //
/// The 64-bit unsigned integer type. /// The 64-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u64 {} mod prim_u64 {}
#[doc(primitive = "u128")] #[cfg_attr(bootstrap, doc(primitive = "u128"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u128")]
// //
/// The 128-bit unsigned integer type. /// The 128-bit unsigned integer type.
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
mod prim_u128 {} mod prim_u128 {}
#[doc(primitive = "isize")] #[cfg_attr(bootstrap, doc(primitive = "isize"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "isize")]
// //
/// The pointer-sized signed integer type. /// The pointer-sized signed integer type.
/// ///
@ -1232,7 +1254,8 @@ mod prim_u128 {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize {} mod prim_isize {}
#[doc(primitive = "usize")] #[cfg_attr(bootstrap, doc(primitive = "usize"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "usize")]
// //
/// The pointer-sized unsigned integer type. /// The pointer-sized unsigned integer type.
/// ///
@ -1242,7 +1265,8 @@ mod prim_isize {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize {} mod prim_usize {}
#[doc(primitive = "reference")] #[cfg_attr(bootstrap, doc(primitive = "reference"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
#[doc(alias = "&")] #[doc(alias = "&")]
#[doc(alias = "&mut")] #[doc(alias = "&mut")]
// //
@ -1373,7 +1397,8 @@ mod prim_usize {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_ref {} mod prim_ref {}
#[doc(primitive = "fn")] #[cfg_attr(bootstrap, doc(primitive = "fn"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "fn")]
// //
/// Function pointers, like `fn(usize) -> bool`. /// Function pointers, like `fn(usize) -> bool`.
/// ///

View file

@ -1,7 +1,8 @@
// `library/{std,core}/src/primitive_docs.rs` should have the same contents. // `library/{std,core}/src/primitive_docs.rs` should have the same contents.
// These are different files so that relative links work properly without // These are different files so that relative links work properly without
// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. // having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
#[doc(primitive = "bool")] #[cfg_attr(bootstrap, doc(primitive = "bool"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
#[doc(alias = "true")] #[doc(alias = "true")]
#[doc(alias = "false")] #[doc(alias = "false")]
/// The boolean type. /// The boolean type.
@ -63,7 +64,8 @@
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool {} mod prim_bool {}
#[doc(primitive = "never")] #[cfg_attr(bootstrap, doc(primitive = "never"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
#[doc(alias = "!")] #[doc(alias = "!")]
// //
/// The `!` type, also called "never". /// The `!` type, also called "never".
@ -274,7 +276,8 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type", issue = "35121")]
mod prim_never {} mod prim_never {}
#[doc(primitive = "char")] #[cfg_attr(bootstrap, doc(primitive = "char"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "char")]
#[allow(rustdoc::invalid_rust_codeblocks)] #[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type. /// A character type.
/// ///
@ -398,7 +401,8 @@ mod prim_never {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_char {} mod prim_char {}
#[doc(primitive = "unit")] #[cfg_attr(bootstrap, doc(primitive = "unit"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "unit")]
#[doc(alias = "(")] #[doc(alias = "(")]
#[doc(alias = ")")] #[doc(alias = ")")]
#[doc(alias = "()")] #[doc(alias = "()")]
@ -460,7 +464,8 @@ impl Copy for () {
// empty // empty
} }
#[doc(primitive = "pointer")] #[cfg_attr(bootstrap, doc(primitive = "pointer"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
#[doc(alias = "ptr")] #[doc(alias = "ptr")]
#[doc(alias = "*")] #[doc(alias = "*")]
#[doc(alias = "*const")] #[doc(alias = "*const")]
@ -577,7 +582,8 @@ impl Copy for () {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_pointer {} mod prim_pointer {}
#[doc(primitive = "array")] #[cfg_attr(bootstrap, doc(primitive = "array"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
#[doc(alias = "[]")] #[doc(alias = "[]")]
#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases #[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
#[doc(alias = "[T; N]")] #[doc(alias = "[T; N]")]
@ -778,7 +784,8 @@ mod prim_pointer {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_array {} mod prim_array {}
#[doc(primitive = "slice")] #[cfg_attr(bootstrap, doc(primitive = "slice"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "slice")]
#[doc(alias = "[")] #[doc(alias = "[")]
#[doc(alias = "]")] #[doc(alias = "]")]
#[doc(alias = "[]")] #[doc(alias = "[]")]
@ -870,7 +877,8 @@ mod prim_array {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {} mod prim_slice {}
#[doc(primitive = "str")] #[cfg_attr(bootstrap, doc(primitive = "str"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
/// String slices. /// String slices.
/// ///
/// *[See also the `std::str` module](crate::str).* /// *[See also the `std::str` module](crate::str).*
@ -937,7 +945,8 @@ mod prim_slice {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_str {} mod prim_str {}
#[doc(primitive = "tuple")] #[cfg_attr(bootstrap, doc(primitive = "tuple"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "tuple")]
#[doc(alias = "(")] #[doc(alias = "(")]
#[doc(alias = ")")] #[doc(alias = ")")]
#[doc(alias = "()")] #[doc(alias = "()")]
@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
// empty // empty
} }
#[doc(primitive = "f32")] #[cfg_attr(bootstrap, doc(primitive = "f32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f32")]
/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008). /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
/// ///
/// This type can represent a wide range of decimal numbers, like `3.5`, `27`, /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@ -1147,7 +1157,8 @@ impl<T: Copy> Copy for (T,) {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_f32 {} mod prim_f32 {}
#[doc(primitive = "f64")] #[cfg_attr(bootstrap, doc(primitive = "f64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f64")]
/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
/// ///
/// This type is very similar to [`f32`], but has increased /// This type is very similar to [`f32`], but has increased
@ -1162,67 +1173,78 @@ mod prim_f32 {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_f64 {} mod prim_f64 {}
#[doc(primitive = "i8")] #[cfg_attr(bootstrap, doc(primitive = "i8"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i8")]
// //
/// The 8-bit signed integer type. /// The 8-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i8 {} mod prim_i8 {}
#[doc(primitive = "i16")] #[cfg_attr(bootstrap, doc(primitive = "i16"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i16")]
// //
/// The 16-bit signed integer type. /// The 16-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i16 {} mod prim_i16 {}
#[doc(primitive = "i32")] #[cfg_attr(bootstrap, doc(primitive = "i32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i32")]
// //
/// The 32-bit signed integer type. /// The 32-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i32 {} mod prim_i32 {}
#[doc(primitive = "i64")] #[cfg_attr(bootstrap, doc(primitive = "i64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i64")]
// //
/// The 64-bit signed integer type. /// The 64-bit signed integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_i64 {} mod prim_i64 {}
#[doc(primitive = "i128")] #[cfg_attr(bootstrap, doc(primitive = "i128"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i128")]
// //
/// The 128-bit signed integer type. /// The 128-bit signed integer type.
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
mod prim_i128 {} mod prim_i128 {}
#[doc(primitive = "u8")] #[cfg_attr(bootstrap, doc(primitive = "u8"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u8")]
// //
/// The 8-bit unsigned integer type. /// The 8-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u8 {} mod prim_u8 {}
#[doc(primitive = "u16")] #[cfg_attr(bootstrap, doc(primitive = "u16"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u16")]
// //
/// The 16-bit unsigned integer type. /// The 16-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u16 {} mod prim_u16 {}
#[doc(primitive = "u32")] #[cfg_attr(bootstrap, doc(primitive = "u32"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u32")]
// //
/// The 32-bit unsigned integer type. /// The 32-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u32 {} mod prim_u32 {}
#[doc(primitive = "u64")] #[cfg_attr(bootstrap, doc(primitive = "u64"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u64")]
// //
/// The 64-bit unsigned integer type. /// The 64-bit unsigned integer type.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_u64 {} mod prim_u64 {}
#[doc(primitive = "u128")] #[cfg_attr(bootstrap, doc(primitive = "u128"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u128")]
// //
/// The 128-bit unsigned integer type. /// The 128-bit unsigned integer type.
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
mod prim_u128 {} mod prim_u128 {}
#[doc(primitive = "isize")] #[cfg_attr(bootstrap, doc(primitive = "isize"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "isize")]
// //
/// The pointer-sized signed integer type. /// The pointer-sized signed integer type.
/// ///
@ -1232,7 +1254,8 @@ mod prim_u128 {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize {} mod prim_isize {}
#[doc(primitive = "usize")] #[cfg_attr(bootstrap, doc(primitive = "usize"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "usize")]
// //
/// The pointer-sized unsigned integer type. /// The pointer-sized unsigned integer type.
/// ///
@ -1242,7 +1265,8 @@ mod prim_isize {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize {} mod prim_usize {}
#[doc(primitive = "reference")] #[cfg_attr(bootstrap, doc(primitive = "reference"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
#[doc(alias = "&")] #[doc(alias = "&")]
#[doc(alias = "&mut")] #[doc(alias = "&mut")]
// //
@ -1373,7 +1397,8 @@ mod prim_usize {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_ref {} mod prim_ref {}
#[doc(primitive = "fn")] #[cfg_attr(bootstrap, doc(primitive = "fn"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "fn")]
// //
/// Function pointers, like `fn(usize) -> bool`. /// Function pointers, like `fn(usize) -> bool`.
/// ///

View file

@ -177,9 +177,9 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
This is for Rust compiler internal use only. This is for Rust compiler internal use only.
Since primitive types are defined in the compiler, there's no place to attach documentation Since primitive types are defined in the compiler, there's no place to attach documentation
attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way attributes. The `#[rustc_doc_primitive = "..."]` attribute is used by the standard library to
to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to provide a way to generate documentation for primitive types, and requires `#![feature(rustc_attrs)]`
enable. to enable.
### Document keywords ### Document keywords

View file

@ -249,38 +249,24 @@ impl ExternalCrate {
// //
// Note that this loop only searches the top-level items of the crate, // Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an // and this is intentional. If we were to search the entire crate for an
// item tagged with `#[doc(primitive)]` then we would also have to // item tagged with `#[rustc_doc_primitive]` then we would also have to
// search the entirety of external modules for items tagged // search the entirety of external modules for items tagged
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding // `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally). // all that metadata unconditionally).
// //
// In order to keep the metadata load under control, the // In order to keep the metadata load under control, the
// `#[doc(primitive)]` feature is explicitly designed to only allow the // `#[rustc_doc_primitive]` feature is explicitly designed to only allow the
// primitive tags to show up as the top level items in a crate. // primitive tags to show up as the top level items in a crate.
// //
// Also note that this does not attempt to deal with modules tagged // Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when // duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map. // rendering by delegating everything to a hash map.
let as_primitive = |res: Res<!>| { let as_primitive = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res { let Res::Def(DefKind::Mod, def_id) = res else { return None };
let mut prim = None; tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| {
let meta_items = tcx
.get_attrs(def_id, sym::doc)
.flat_map(|attr| attr.meta_item_list().unwrap_or_default());
for meta in meta_items {
if let Some(v) = meta.value_str() {
if meta.has_name(sym::primitive) {
prim = PrimitiveType::from_symbol(v);
if prim.is_some() {
break;
}
// FIXME: should warn on unknown primitives? // FIXME: should warn on unknown primitives?
} Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?))
} })
}
return prim.map(|p| (def_id, p));
}
None
}; };
if root.is_local() { if root.is_local() {
@ -1829,13 +1815,17 @@ impl PrimitiveType {
} }
} }
/// Returns the DefId of the module with `doc(primitive)` for this primitive type. /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
/// Panics if there is no such module. /// Panics if there is no such module.
/// ///
/// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`, /// This gives precedence to primitives defined in the current crate, and deprioritizes
/// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked. /// primitives defined in `core`,
/// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
/// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.) /// will be picked.
///
/// In particular, if a crate depends on both `std` and another crate that also defines
/// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
/// (no_std crates are usually fine unless multiple dependencies define a primitive.)
pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> { pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new(); static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
PRIMITIVE_LOCATIONS.get_or_init(|| { PRIMITIVE_LOCATIONS.get_or_init(|| {

View file

@ -1016,9 +1016,7 @@ function preLoadCss(cssUrl) {
<code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \ <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
and <code>const</code>.", and <code>const</code>.",
"Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \ "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
<code>-&gt; vec</code>)", <code>-&gt; vec</code> or <code>String, enum:Cow -&gt; bool</code>)",
"Search multiple things at once by splitting your query with comma (e.g., \
<code>str,u8</code> or <code>String,struct:Vec,test</code>)",
"You can look for items with an exact name by putting double quotes around \ "You can look for items with an exact name by putting double quotes around \
your request: <code>\"string\"</code>", your request: <code>\"string\"</code>",
"Look for items inside another one by searching for a path: <code>vec::Vec</code>", "Look for items inside another one by searching for a path: <code>vec::Vec</code>",

View file

@ -249,9 +249,7 @@ pub(crate) fn id_from_item_inner(
// instead, we directly get the primitive symbol and convert it to u32 to // instead, we directly get the primitive symbol and convert it to u32 to
// generate the ID. // generate the ID.
if matches!(tcx.def_kind(def_id), DefKind::Mod) && if matches!(tcx.def_kind(def_id), DefKind::Mod) &&
let Some(prim) = tcx.get_attrs(*def_id, sym::doc) let Some(prim) = tcx.get_attrs(*def_id, sym::rustc_doc_primitive)
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
.filter(|attr| attr.has_name(sym::primitive))
.find_map(|attr| attr.value_str()) { .find_map(|attr| attr.value_str()) {
format!(":{}", prim.as_u32()) format!(":{}", prim.as_u32())
} else { } else {

View file

@ -78,7 +78,7 @@ impl<'tcx> JsonRenderer<'tcx> {
// HACK(hkmatsumoto): For impls of primitive types, we index them // HACK(hkmatsumoto): For impls of primitive types, we index them
// regardless of whether they're local. This is because users can // regardless of whether they're local. This is because users can
// document primitive items in an arbitrary crate by using // document primitive items in an arbitrary crate by using
// `doc(primitive)`. // `rustc_doc_primitive`.
let mut is_primitive_impl = false; let mut is_primitive_impl = false;
if let clean::types::ItemKind::ImplItem(ref impl_) = *item.kind && if let clean::types::ItemKind::ImplItem(ref impl_) = *item.kind &&
impl_.trait_.is_none() && impl_.trait_.is_none() &&

View file

@ -47,7 +47,18 @@ fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
krate krate
} }
#[derive(Copy, Clone, Debug, Hash)] fn filter_assoc_items_by_name_and_namespace<'a>(
tcx: TyCtxt<'a>,
assoc_items_of: DefId,
ident: Ident,
ns: Namespace,
) -> impl Iterator<Item = &ty::AssocItem> + 'a {
tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
})
}
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
enum Res { enum Res {
Def(DefKind, DefId), Def(DefKind, DefId),
Primitive(PrimitiveType), Primitive(PrimitiveType),
@ -59,7 +70,7 @@ impl Res {
fn descr(self) -> &'static str { fn descr(self) -> &'static str {
match self { match self {
Res::Def(kind, id) => ResolveRes::Def(kind, id).descr(), Res::Def(kind, id) => ResolveRes::Def(kind, id).descr(),
Res::Primitive(_) => "builtin type", Res::Primitive(_) => "primitive type",
} }
} }
@ -317,14 +328,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
prim_ty: PrimitiveType, prim_ty: PrimitiveType,
ns: Namespace, ns: Namespace,
item_name: Symbol, item_name: Symbol,
) -> Option<(Res, DefId)> { ) -> Vec<(Res, DefId)> {
let tcx = self.cx.tcx; let tcx = self.cx.tcx;
prim_ty.impls(tcx).find_map(|impl_| { prim_ty
tcx.associated_items(impl_) .impls(tcx)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_) .flat_map(|impl_| {
filter_assoc_items_by_name_and_namespace(
tcx,
impl_,
Ident::with_dummy_span(item_name),
ns,
)
.map(|item| (Res::Primitive(prim_ty), item.def_id)) .map(|item| (Res::Primitive(prim_ty), item.def_id))
}) })
.collect::<Vec<_>>()
} }
fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> { fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> {
@ -394,14 +412,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ns: Namespace, ns: Namespace,
item_id: DefId, item_id: DefId,
module_id: DefId, module_id: DefId,
) -> Result<(Res, Option<DefId>), UnresolvedPath<'path>> { ) -> Result<Vec<(Res, Option<DefId>)>, UnresolvedPath<'path>> {
if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) {
return Ok(match res { return Ok(match res {
Res::Def( Res::Def(
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Variant, DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Variant,
def_id, def_id,
) => (Res::from_def_id(self.cx.tcx, self.cx.tcx.parent(def_id)), Some(def_id)), ) => {
_ => (res, None), vec![(Res::from_def_id(self.cx.tcx, self.cx.tcx.parent(def_id)), Some(def_id))]
}
_ => vec![(res, None)],
}); });
} else if ns == MacroNS { } else if ns == MacroNS {
return Err(UnresolvedPath { return Err(UnresolvedPath {
@ -433,17 +453,24 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
})?; })?;
// FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
// links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity // links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity
// error instead and special case *only* modules with `#[doc(primitive)]`, not all // error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all
// primitives. // primitives.
resolve_primitive(&path_root, TypeNS) match resolve_primitive(&path_root, TypeNS)
.or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id)) .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
.and_then(|ty_res| { .and_then(|ty_res| {
self.resolve_associated_item(ty_res, item_name, ns, module_id).map(Ok) let candidates = self
}) .resolve_associated_item(ty_res, item_name, ns, module_id)
.unwrap_or_else(|| { .into_iter()
.map(|(res, def_id)| (res, Some(def_id)))
.collect::<Vec<_>>();
if !candidates.is_empty() { Some(candidates) } else { None }
}) {
Some(r) => Ok(r),
None => {
if ns == Namespace::ValueNS { if ns == Namespace::ValueNS {
self.variant_field(path_str, item_id, module_id) self.variant_field(path_str, item_id, module_id)
.map(|(res, def_id)| vec![(res, Some(def_id))])
} else { } else {
Err(UnresolvedPath { Err(UnresolvedPath {
item_id, item_id,
@ -452,8 +479,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
unresolved: path_root.into(), unresolved: path_root.into(),
}) })
} }
}) }
.map(|(res, def_id)| (res, Some(def_id))) }
} }
/// Convert a DefId to a Res, where possible. /// Convert a DefId to a Res, where possible.
@ -535,24 +562,31 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
item_name: Symbol, item_name: Symbol,
ns: Namespace, ns: Namespace,
module_id: DefId, module_id: DefId,
) -> Option<(Res, DefId)> { ) -> Vec<(Res, DefId)> {
let tcx = self.cx.tcx; let tcx = self.cx.tcx;
match root_res { match root_res {
Res::Primitive(prim) => { Res::Primitive(prim) => {
self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| { let items = self.resolve_primitive_associated_item(prim, ns, item_name);
if !items.is_empty() {
items
// Inherent associated items take precedence over items that come from trait impls.
} else {
self.primitive_type_to_ty(prim) self.primitive_type_to_ty(prim)
.and_then(|ty| { .map(|ty| {
resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx) resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
}) .iter()
.map(|item| (root_res, item.def_id)) .map(|item| (root_res, item.def_id))
.collect::<Vec<_>>()
}) })
.unwrap_or(Vec::new())
}
} }
Res::Def(DefKind::TyAlias, did) => { Res::Def(DefKind::TyAlias, did) => {
// Resolve the link on the type the alias points to. // Resolve the link on the type the alias points to.
// FIXME: if the associated item is defined directly on the type alias, // FIXME: if the associated item is defined directly on the type alias,
// it will show up on its documentation page, we should link there instead. // it will show up on its documentation page, we should link there instead.
let res = self.def_id_to_res(did)?; let Some(res) = self.def_id_to_res(did) else { return Vec::new() };
self.resolve_associated_item(res, item_name, ns, module_id) self.resolve_associated_item(res, item_name, ns, module_id)
} }
Res::Def( Res::Def(
@ -566,7 +600,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty::Adt(adt_def, _) => { ty::Adt(adt_def, _) => {
for variant in adt_def.variants() { for variant in adt_def.variants() {
if variant.name == item_name { if variant.name == item_name {
return Some((root_res, variant.def_id)); return vec![(root_res, variant.def_id)];
} }
} }
} }
@ -575,43 +609,46 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
// Checks if item_name belongs to `impl SomeItem` // Checks if item_name belongs to `impl SomeItem`
let assoc_item = tcx let mut assoc_items: Vec<_> = tcx
.inherent_impls(did) .inherent_impls(did)
.iter() .iter()
.flat_map(|&imp| { .flat_map(|&imp| {
tcx.associated_items(imp).find_by_name_and_namespace( filter_assoc_items_by_name_and_namespace(
tcx, tcx,
imp,
Ident::with_dummy_span(item_name), Ident::with_dummy_span(item_name),
ns, ns,
imp,
) )
}) })
.copied() .map(|item| (root_res, item.def_id))
// There should only ever be one associated item that matches from any inherent impl .collect();
.next()
if assoc_items.is_empty() {
// Check if item_name belongs to `impl SomeTrait for SomeItem` // Check if item_name belongs to `impl SomeTrait for SomeItem`
// FIXME(#74563): This gives precedence to `impl SomeItem`: // FIXME(#74563): This gives precedence to `impl SomeItem`:
// Although having both would be ambiguous, use impl version for compatibility's sake. // Although having both would be ambiguous, use impl version for compatibility's sake.
// To handle that properly resolve() would have to support // To handle that properly resolve() would have to support
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn) // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
.or_else(|| { assoc_items = resolve_associated_trait_item(
resolve_associated_trait_item(
tcx.type_of(did).subst_identity(), tcx.type_of(did).subst_identity(),
module_id, module_id,
item_name, item_name,
ns, ns,
self.cx, self.cx,
) )
}); .into_iter()
.map(|item| (root_res, item.def_id))
.collect::<Vec<_>>();
}
debug!("got associated item {:?}", assoc_item); debug!("got associated item {:?}", assoc_items);
if let Some(item) = assoc_item { if !assoc_items.is_empty() {
return Some((root_res, item.def_id)); return assoc_items;
} }
if ns != Namespace::ValueNS { if ns != Namespace::ValueNS {
return None; return Vec::new();
} }
debug!("looking for fields named {} for {:?}", item_name, did); debug!("looking for fields named {} for {:?}", item_name, did);
// FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
@ -631,20 +668,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// field syntax) and are handled by the compiler's resolver. // field syntax) and are handled by the compiler's resolver.
let def = match tcx.type_of(did).subst_identity().kind() { let def = match tcx.type_of(did).subst_identity().kind() {
ty::Adt(def, _) if !def.is_enum() => def, ty::Adt(def, _) if !def.is_enum() => def,
_ => return None, _ => return Vec::new(),
}; };
let field = def.non_enum_variant()
def.non_enum_variant().fields.iter().find(|item| item.name == item_name)?; .fields
Some((root_res, field.did)) .iter()
.filter(|field| field.name == item_name)
.map(|field| (root_res, field.did))
.collect::<Vec<_>>()
} }
Res::Def(DefKind::Trait, did) => tcx Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
.associated_items(did) tcx,
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did) did,
Ident::with_dummy_span(item_name),
ns,
)
.map(|item| { .map(|item| {
let res = Res::Def(item.kind.as_def_kind(), item.def_id); let res = Res::Def(item.kind.as_def_kind(), item.def_id);
(res, item.def_id) (res, item.def_id)
}), })
_ => None, .collect::<Vec<_>>(),
_ => Vec::new(),
} }
} }
} }
@ -664,7 +708,7 @@ fn resolve_associated_trait_item<'a>(
item_name: Symbol, item_name: Symbol,
ns: Namespace, ns: Namespace,
cx: &mut DocContext<'a>, cx: &mut DocContext<'a>,
) -> Option<ty::AssocItem> { ) -> Vec<ty::AssocItem> {
// FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately // FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
// `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
// meantime, just don't look for these blanket impls. // meantime, just don't look for these blanket impls.
@ -672,19 +716,26 @@ fn resolve_associated_trait_item<'a>(
// Next consider explicit impls: `impl MyTrait for MyType` // Next consider explicit impls: `impl MyTrait for MyType`
// Give precedence to inherent impls. // Give precedence to inherent impls.
let traits = trait_impls_for(cx, ty, module); let traits = trait_impls_for(cx, ty, module);
let tcx = cx.tcx;
debug!("considering traits {:?}", traits); debug!("considering traits {:?}", traits);
let mut candidates = traits.iter().filter_map(|&(impl_, trait_)| { let candidates = traits
cx.tcx .iter()
.associated_items(trait_) .flat_map(|&(impl_, trait_)| {
.find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) filter_assoc_items_by_name_and_namespace(
.map(|trait_assoc| { cx.tcx,
trait_assoc_to_impl_assoc_item(cx.tcx, impl_, trait_assoc.def_id) trait_,
Ident::with_dummy_span(item_name),
ns,
)
.map(move |trait_assoc| {
trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id)
.unwrap_or(*trait_assoc) .unwrap_or(*trait_assoc)
}) })
}); })
.collect::<Vec<_>>();
// FIXME(#74563): warn about ambiguity // FIXME(#74563): warn about ambiguity
debug!("the candidates were {:?}", candidates.clone().collect::<Vec<_>>()); debug!("the candidates were {:?}", candidates);
candidates.next() candidates
} }
/// Find the associated item in the impl `impl_id` that corresponds to the /// Find the associated item in the impl `impl_id` that corresponds to the
@ -758,15 +809,15 @@ fn trait_impls_for<'a>(
/// Check for resolve collisions between a trait and its derive. /// Check for resolve collisions between a trait and its derive.
/// ///
/// These are common and we should just resolve to the trait in that case. /// These are common and we should just resolve to the trait in that case.
fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_>>>) -> bool { fn is_derive_trait_collision<T>(ns: &PerNS<Result<Vec<(Res, T)>, ResolutionFailure<'_>>>) -> bool {
matches!( if let (&Ok(ref type_ns), &Ok(ref macro_ns)) = (&ns.type_ns, &ns.macro_ns) {
*ns, type_ns.iter().any(|(res, _)| matches!(res, Res::Def(DefKind::Trait, _)))
PerNS { && macro_ns
type_ns: Ok((Res::Def(DefKind::Trait, _), _)), .iter()
macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), .any(|(res, _)| matches!(res, Res::Def(DefKind::Macro(MacroKind::Derive), _)))
.. } else {
false
} }
)
} }
impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
@ -987,15 +1038,15 @@ impl LinkCollector<'_, '_> {
res = prim; res = prim;
} else { } else {
// `[char]` when a `char` module is in scope // `[char]` when a `char` module is in scope
let candidates = vec![res, prim]; let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)];
ambiguity_error(self.cx, diag_info, path_str, candidates); ambiguity_error(self.cx, &diag_info, path_str, candidates);
return None; return None;
} }
} }
} }
match res { match res {
Res::Primitive(prim) => { Res::Primitive(_) => {
if let Some(UrlFragment::Item(id)) = fragment { if let Some(UrlFragment::Item(id)) = fragment {
// We're actually resolving an associated item of a primitive, so we need to // We're actually resolving an associated item of a primitive, so we need to
// verify the disambiguator (if any) matches the type of the associated item. // verify the disambiguator (if any) matches the type of the associated item.
@ -1015,15 +1066,6 @@ impl LinkCollector<'_, '_> {
item, item,
&diag_info, &diag_info,
)?; )?;
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
// However I'm not sure how to check that across crates.
if prim == PrimitiveType::RawPointer
&& item.item_id.is_local()
&& !self.cx.tcx.features().intra_doc_pointers
{
self.report_rawptr_assoc_feature_gate(dox, ori_link, item);
}
} else { } else {
match disambiguator { match disambiguator {
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
@ -1102,7 +1144,7 @@ impl LinkCollector<'_, '_> {
} }
} }
// item can be non-local e.g. when using #[doc(primitive = "pointer")] // item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]`
if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| { if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| {
item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
}) { }) {
@ -1144,9 +1186,8 @@ impl LinkCollector<'_, '_> {
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, callback); report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, callback);
} }
fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) { fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) {
let span = let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs)
super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
.unwrap_or_else(|| item.attr_span(self.cx.tcx)); .unwrap_or_else(|| item.attr_span(self.cx.tcx));
rustc_session::parse::feature_err( rustc_session::parse::feature_err(
&self.cx.tcx.sess.parse_sess, &self.cx.tcx.sess.parse_sess,
@ -1172,7 +1213,31 @@ impl LinkCollector<'_, '_> {
} }
} }
let res = self.resolve_with_disambiguator(&key, diag.clone()).and_then(|(res, def_id)| { let mut candidates = self.resolve_with_disambiguator(&key, diag.clone());
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
// However I'm not sure how to check that across crates.
if let Some(candidate) = candidates.get(0) &&
candidate.0 == Res::Primitive(PrimitiveType::RawPointer) &&
key.path_str.contains("::") // We only want to check this if this is an associated item.
{
if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers {
self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item);
return None;
} else {
candidates = vec![candidates[0]];
}
}
// If there are multiple items with the same "kind" (for example, both "associated types")
// and after removing duplicated kinds, only one remains, the `ambiguity_error` function
// won't emit an error. So at this point, we can just take the first candidate as it was
// the first retrieved and use it to generate the link.
if candidates.len() > 1 && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates) {
candidates = vec![candidates[0]];
}
if let &[(res, def_id)] = candidates.as_slice() {
let fragment = match (&key.extra_fragment, def_id) { let fragment = match (&key.extra_fragment, def_id) {
(Some(_), Some(def_id)) => { (Some(_), Some(def_id)) => {
report_anchor_conflict(self.cx, diag, def_id); report_anchor_conflict(self.cx, diag, def_id);
@ -1182,13 +1247,15 @@ impl LinkCollector<'_, '_> {
(None, Some(def_id)) => Some(UrlFragment::Item(def_id)), (None, Some(def_id)) => Some(UrlFragment::Item(def_id)),
(None, None) => None, (None, None) => None,
}; };
Some((res, fragment)) let r = Some((res, fragment));
}); self.visited_links.insert(key, r.clone());
return r;
if res.is_some() || cache_errors {
self.visited_links.insert(key, res.clone());
} }
res
if cache_errors {
self.visited_links.insert(key, None);
}
None
} }
/// After parsing the disambiguator, resolve the main part of the link. /// After parsing the disambiguator, resolve the main part of the link.
@ -1197,7 +1264,7 @@ impl LinkCollector<'_, '_> {
&mut self, &mut self,
key: &ResolutionInfo, key: &ResolutionInfo,
diag: DiagnosticInfo<'_>, diag: DiagnosticInfo<'_>,
) -> Option<(Res, Option<DefId>)> { ) -> Vec<(Res, Option<DefId>)> {
let disambiguator = key.dis; let disambiguator = key.dis;
let path_str = &key.path_str; let path_str = &key.path_str;
let item_id = key.item_id; let item_id = key.item_id;
@ -1206,7 +1273,7 @@ impl LinkCollector<'_, '_> {
match disambiguator.map(Disambiguator::ns) { match disambiguator.map(Disambiguator::ns) {
Some(expected_ns) => { Some(expected_ns) => {
match self.resolve(path_str, expected_ns, item_id, module_id) { match self.resolve(path_str, expected_ns, item_id, module_id) {
Ok(res) => Some(res), Ok(candidates) => candidates,
Err(err) => { Err(err) => {
// We only looked in one namespace. Try to give a better error if possible. // We only looked in one namespace. Try to give a better error if possible.
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`. // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`.
@ -1215,10 +1282,11 @@ impl LinkCollector<'_, '_> {
for other_ns in [TypeNS, ValueNS, MacroNS] { for other_ns in [TypeNS, ValueNS, MacroNS] {
if other_ns != expected_ns { if other_ns != expected_ns {
if let Ok(res) = if let Ok(res) =
self.resolve(path_str, other_ns, item_id, module_id) self.resolve(path_str, other_ns, item_id, module_id) &&
!res.is_empty()
{ {
err = ResolutionFailure::WrongNamespace { err = ResolutionFailure::WrongNamespace {
res: full_res(self.cx.tcx, res), res: full_res(self.cx.tcx, res[0]),
expected_ns, expected_ns,
}; };
break; break;
@ -1239,18 +1307,26 @@ impl LinkCollector<'_, '_> {
let candidates = PerNS { let candidates = PerNS {
macro_ns: candidate(MacroNS), macro_ns: candidate(MacroNS),
type_ns: candidate(TypeNS), type_ns: candidate(TypeNS),
value_ns: candidate(ValueNS).and_then(|(res, def_id)| { value_ns: candidate(ValueNS).and_then(|v_res| {
for (res, _) in v_res.iter() {
match res { match res {
// Constructors are picked up in the type namespace. // Constructors are picked up in the type namespace.
Res::Def(DefKind::Ctor(..), _) => { Res::Def(DefKind::Ctor(..), _) => {
Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS }) return Err(ResolutionFailure::WrongNamespace {
res: *res,
expected_ns: TypeNS,
});
} }
_ => Ok((res, def_id)), _ => {}
} }
}
Ok(v_res)
}), }),
}; };
let len = candidates.iter().filter(|res| res.is_ok()).count(); let len = candidates
.iter()
.fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc });
if len == 0 { if len == 0 {
return resolution_failure( return resolution_failure(
@ -1260,22 +1336,21 @@ impl LinkCollector<'_, '_> {
disambiguator, disambiguator,
candidates.into_iter().filter_map(|res| res.err()).collect(), candidates.into_iter().filter_map(|res| res.err()).collect(),
); );
} } else if len == 1 {
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
if len == 1 { } else {
Some(candidates.into_iter().find_map(|res| res.ok()).unwrap()) let has_derive_trait_collision = is_derive_trait_collision(&candidates);
} else if len == 2 && is_derive_trait_collision(&candidates) { if len == 2 && has_derive_trait_collision {
Some(candidates.type_ns.unwrap()) candidates.type_ns.unwrap()
} else { } else {
let ignore_macro = is_derive_trait_collision(&candidates);
// If we're reporting an ambiguity, don't mention the namespaces that failed // If we're reporting an ambiguity, don't mention the namespaces that failed
let mut candidates = let mut candidates = candidates.map(|candidate| candidate.ok());
candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); // If there a collision between a trait and a derive, we ignore the derive.
if ignore_macro { if has_derive_trait_collision {
candidates.macro_ns = None; candidates.macro_ns = None;
} }
ambiguity_error(self.cx, diag, path_str, candidates.present_items().collect()); candidates.into_iter().filter_map(|res| res).flatten().collect::<Vec<_>>()
None }
} }
} }
} }
@ -1563,7 +1638,7 @@ fn resolution_failure(
path_str: &str, path_str: &str,
disambiguator: Option<Disambiguator>, disambiguator: Option<Disambiguator>,
kinds: SmallVec<[ResolutionFailure<'_>; 3]>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>,
) -> Option<(Res, Option<DefId>)> { ) -> Vec<(Res, Option<DefId>)> {
let tcx = collector.cx.tcx; let tcx = collector.cx.tcx;
let mut recovered_res = None; let mut recovered_res = None;
report_diagnostic( report_diagnostic(
@ -1622,13 +1697,15 @@ fn resolution_failure(
}; };
name = start; name = start;
for ns in [TypeNS, ValueNS, MacroNS] { for ns in [TypeNS, ValueNS, MacroNS] {
if let Ok(res) = collector.resolve(start, ns, item_id, module_id) { if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
debug!("found partial_res={:?}", res); debug!("found partial_res={:?}", v_res);
*partial_res = Some(full_res(collector.cx.tcx, res)); if !v_res.is_empty() {
*partial_res = Some(full_res(collector.cx.tcx, v_res[0]));
*unresolved = end.into(); *unresolved = end.into();
break 'outer; break 'outer;
} }
} }
}
*unresolved = end.into(); *unresolved = end.into();
} }
@ -1774,7 +1851,10 @@ fn resolution_failure(
}, },
); );
recovered_res match recovered_res {
Some(r) => vec![r],
None => Vec::new(),
}
} }
fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) {
@ -1859,28 +1939,47 @@ fn report_malformed_generics(
} }
/// Report an ambiguity error, where there were multiple possible resolutions. /// Report an ambiguity error, where there were multiple possible resolutions.
///
/// If all `candidates` have the same kind, it's not possible to disambiguate so in this case,
/// the function won't emit an error and will return `false`. Otherwise, it'll emit the error and
/// return `true`.
fn ambiguity_error( fn ambiguity_error(
cx: &DocContext<'_>, cx: &DocContext<'_>,
diag_info: DiagnosticInfo<'_>, diag_info: &DiagnosticInfo<'_>,
path_str: &str, path_str: &str,
candidates: Vec<Res>, candidates: &[(Res, Option<DefId>)],
) { ) -> bool {
let mut msg = format!("`{}` is ", path_str); let mut descrs = FxHashSet::default();
let kinds = candidates
.iter()
.map(
|(res, def_id)| {
if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res }
},
)
.filter(|res| descrs.insert(res.descr()))
.collect::<Vec<_>>();
if descrs.len() == 1 {
// There is no way for users to disambiguate at this point, so better return the first
// candidate and not show a warning.
return false;
}
match candidates.as_slice() { let mut msg = format!("`{}` is ", path_str);
[first_def, second_def] => { match kinds.as_slice() {
[res1, res2] => {
msg += &format!( msg += &format!(
"both {} {} and {} {}", "both {} {} and {} {}",
first_def.article(), res1.article(),
first_def.descr(), res1.descr(),
second_def.article(), res2.article(),
second_def.descr(), res2.descr()
); );
} }
_ => { _ => {
let mut candidates = candidates.iter().peekable(); let mut kinds = kinds.iter().peekable();
while let Some(res) = candidates.next() { while let Some(res) = kinds.next() {
if candidates.peek().is_some() { if kinds.peek().is_some() {
msg += &format!("{} {}, ", res.article(), res.descr()); msg += &format!("{} {}, ", res.article(), res.descr());
} else { } else {
msg += &format!("and {} {}", res.article(), res.descr()); msg += &format!("and {} {}", res.article(), res.descr());
@ -1889,17 +1988,18 @@ fn ambiguity_error(
} }
} }
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, |diag, sp| { report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, |diag, sp| {
if let Some(sp) = sp { if let Some(sp) = sp {
diag.span_label(sp, "ambiguous link"); diag.span_label(sp, "ambiguous link");
} else { } else {
diag.note("ambiguous link"); diag.note("ambiguous link");
} }
for res in candidates { for res in kinds {
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
} }
}); });
true
} }
/// In case of an ambiguity or mismatched disambiguator, suggest the correct /// In case of an ambiguity or mismatched disambiguator, suggest the correct

View file

@ -0,0 +1,21 @@
// This test ensures that when clicking on a link which leads to an item inside a collapsed element,
// the collapsed element will be expanded.
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// We check that the implementors block is expanded.
assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
// We now collapse the implementors block.
property: ("#implementations-list .implementors-toggle", {"open": "false"})
// And now we click on the link to the method to ensure it'll expand the implementors block.
click: "//*[@class='sidebar']//a[@href='#method.must_use']"
assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
// Now we do the same through search result.
// First we reload the page without the anchor in the URL.
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// Then we collapse the section again...
property: ("#implementations-list .implementors-toggle", {"open": "false"})
// Then we run the search.
write: (".search-input", "foo::must_use")
wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})

View file

@ -1,5 +1,5 @@
#![feature(no_core)] #![feature(no_core)]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![no_core] #![no_core]
// @set Local = "$.index[*][?(@.name=='Local')].id" // @set Local = "$.index[*][?(@.name=='Local')].id"
@ -16,6 +16,6 @@ impl Local for bool {}
// FIXME(#101695): Test bool's `impls` include "Local for bool" // FIXME(#101695): Test bool's `impls` include "Local for bool"
// @has "$.index[*][?(@.name=='bool')]" // @has "$.index[*][?(@.name=='bool')]"
#[doc(primitive = "bool")] #[rustc_doc_primitive = "bool"]
/// Boolean docs /// Boolean docs
mod prim_bool {} mod prim_bool {}

View file

@ -8,7 +8,7 @@
//! Link to [i32][prim@i32] [i64][prim@i64] //! Link to [i32][prim@i32] [i64][prim@i64]
#[doc(primitive = "i32")] #[rustc_doc_primitive = "i32"]
mod prim_i32 {} mod prim_i32 {}
// @set local_i32 = "$.index[*][?(@.name=='i32')].id" // @set local_i32 = "$.index[*][?(@.name=='i32')].id"

View file

@ -25,7 +25,7 @@ pub trait Trait {}
impl Trait for i32 {} impl Trait for i32 {}
/// i32 /// i32
#[doc(primitive = "i32")] #[rustc_doc_primitive = "i32"]
mod prim_i32 {} mod prim_i32 {}
// @set i32 = "$.index[*][?(@.docs=='i32')].id" // @set i32 = "$.index[*][?(@.docs=='i32')].id"

View file

@ -2,7 +2,7 @@
// Regression test for <https://github.com/rust-lang/rust/issues/98006>. // Regression test for <https://github.com/rust-lang/rust/issues/98006>.
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![feature(no_core)] #![feature(no_core)]
#![no_core] #![no_core]
@ -10,7 +10,7 @@
// @has "$.index[*][?(@.name=='usize')]" // @has "$.index[*][?(@.name=='usize')]"
// @has "$.index[*][?(@.name=='prim')]" // @has "$.index[*][?(@.name=='prim')]"
#[doc(primitive = "usize")] #[rustc_doc_primitive = "usize"]
/// This is the built-in type `usize`. /// This is the built-in type `usize`.
mod prim { mod prim {
} }

View file

@ -1,8 +1,8 @@
// edition:2018 // edition:2018
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#[doc(primitive = "usize")] #[rustc_doc_primitive = "usize"]
mod usize {} mod usize {}
// @set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id" // @set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id"

View file

@ -2,12 +2,13 @@
// check-pass // check-pass
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![feature(rustc_attrs)]
//! the features only used in std also have entries in the table, so make sure those get pulled out //! the features only used in std also have entries in the table, so make sure those get pulled out
//! properly as well //! properly as well
/// woo, check it out, we can write our own primitive docs lol /// woo, check it out, we can write our own primitive docs lol
#[doc(primitive="unit")] #[rustc_doc_primitive = "unit"]
mod prim_unit {} mod prim_unit {}
/// keywords? sure, pile them on /// keywords? sure, pile them on

View file

@ -35,6 +35,6 @@ pub mod foo {
/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
pub struct Docs {} pub struct Docs {}
/// [true] //~ ERROR `true` is both a module and a builtin type /// [true] //~ ERROR `true` is both a module and a primitive type
/// [primitive@true] /// [primitive@true]
pub mod r#true {} pub mod r#true {}

View file

@ -1,4 +1,4 @@
error: `true` is both a module and a builtin type error: `true` is both a module and a primitive type
--> $DIR/ambiguity.rs:38:6 --> $DIR/ambiguity.rs:38:6
| |
LL | /// [true] LL | /// [true]
@ -13,89 +13,89 @@ help: to link to the module, prefix with `mod@`
| |
LL | /// [mod@true] LL | /// [mod@true]
| ++++ | ++++
help: to link to the builtin type, prefix with `prim@` help: to link to the primitive type, prefix with `prim@`
| |
LL | /// [prim@true] LL | /// [prim@true]
| +++++ | +++++
error: `ambiguous` is both a struct and a function error: `ambiguous` is both a function and a struct
--> $DIR/ambiguity.rs:27:7 --> $DIR/ambiguity.rs:27:7
| |
LL | /// [`ambiguous`] is ambiguous. LL | /// [`ambiguous`] is ambiguous.
| ^^^^^^^^^ ambiguous link | ^^^^^^^^^ ambiguous link
| |
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@ambiguous`] is ambiguous.
| +++++++
help: to link to the function, add parentheses help: to link to the function, add parentheses
| |
LL | /// [`ambiguous()`] is ambiguous. LL | /// [`ambiguous()`] is ambiguous.
| ++ | ++
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@ambiguous`] is ambiguous.
| +++++++
error: `ambiguous` is both a struct and a function error: `ambiguous` is both a function and a struct
--> $DIR/ambiguity.rs:29:6 --> $DIR/ambiguity.rs:29:6
| |
LL | /// [ambiguous] is ambiguous. LL | /// [ambiguous] is ambiguous.
| ^^^^^^^^^ ambiguous link | ^^^^^^^^^ ambiguous link
| |
help: to link to the struct, prefix with `struct@`
|
LL | /// [struct@ambiguous] is ambiguous.
| +++++++
help: to link to the function, add parentheses help: to link to the function, add parentheses
| |
LL | /// [ambiguous()] is ambiguous. LL | /// [ambiguous()] is ambiguous.
| ++ | ++
help: to link to the struct, prefix with `struct@`
|
LL | /// [struct@ambiguous] is ambiguous.
| +++++++
error: `multi_conflict` is a struct, a function, and a macro error: `multi_conflict` is a function, a struct, and a macro
--> $DIR/ambiguity.rs:31:7 --> $DIR/ambiguity.rs:31:7
| |
LL | /// [`multi_conflict`] is a three-way conflict. LL | /// [`multi_conflict`] is a three-way conflict.
| ^^^^^^^^^^^^^^ ambiguous link | ^^^^^^^^^^^^^^ 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 help: to link to the function, add parentheses
| |
LL | /// [`multi_conflict()`] is a three-way conflict. LL | /// [`multi_conflict()`] is a three-way conflict.
| ++ | ++
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@multi_conflict`] is a three-way conflict.
| +++++++
help: to link to the macro, add an exclamation mark help: to link to the macro, add an exclamation mark
| |
LL | /// [`multi_conflict!`] is a three-way conflict. LL | /// [`multi_conflict!`] is a three-way conflict.
| + | +
error: `type_and_value` is both a module and a constant error: `type_and_value` is both a constant and a module
--> $DIR/ambiguity.rs:33:16 --> $DIR/ambiguity.rs:33:16
| |
LL | /// Ambiguous [type_and_value]. LL | /// Ambiguous [type_and_value].
| ^^^^^^^^^^^^^^ ambiguous link | ^^^^^^^^^^^^^^ 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@` help: to link to the constant, prefix with `const@`
| |
LL | /// Ambiguous [const@type_and_value]. LL | /// Ambiguous [const@type_and_value].
| ++++++ | ++++++
help: to link to the module, prefix with `mod@`
|
LL | /// Ambiguous [mod@type_and_value].
| ++++
error: `foo::bar` is both an enum and a function error: `foo::bar` is both a function and an enum
--> $DIR/ambiguity.rs:35:43 --> $DIR/ambiguity.rs:35:43
| |
LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. LL | /// Ambiguous non-implied shortcut link [`foo::bar`].
| ^^^^^^^^ ambiguous link | ^^^^^^^^ 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 help: to link to the function, add parentheses
| |
LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
| ++ | ++
help: to link to the enum, prefix with `enum@`
|
LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`].
| +++++
error: aborting due to 6 previous errors error: aborting due to 6 previous errors

View file

@ -54,11 +54,11 @@
/// [u8::not_found] /// [u8::not_found]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE the builtin type `u8` has no associated item named `not_found` //~| NOTE the primitive type `u8` has no associated item named `not_found`
/// [std::primitive::u8::not_found] /// [std::primitive::u8::not_found]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE the builtin type `u8` has no associated item named `not_found` //~| NOTE the primitive type `u8` has no associated item named `not_found`
/// [type@Vec::into_iter] /// [type@Vec::into_iter]
//~^ ERROR unresolved link //~^ ERROR unresolved link

View file

@ -80,13 +80,13 @@ error: unresolved link to `u8::not_found`
--> $DIR/errors.rs:55:6 --> $DIR/errors.rs:55:6
| |
LL | /// [u8::not_found] LL | /// [u8::not_found]
| ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` | ^^^^^^^^^^^^^ the primitive type `u8` has no associated item named `not_found`
error: unresolved link to `std::primitive::u8::not_found` error: unresolved link to `std::primitive::u8::not_found`
--> $DIR/errors.rs:59:6 --> $DIR/errors.rs:59:6
| |
LL | /// [std::primitive::u8::not_found] LL | /// [std::primitive::u8::not_found]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the primitive type `u8` has no associated item named `not_found`
error: unresolved link to `Vec::into_iter` error: unresolved link to `Vec::into_iter`
--> $DIR/errors.rs:63:6 --> $DIR/errors.rs:63:6

View file

@ -0,0 +1,22 @@
// This test ensures that this warning doesn't show up:
// warning: `PartialEq` is both a trait and a derive macro
// --> tests/rustdoc-ui/intra-doc/issue-108653-associated-items-10.rs:1:7
// |
// 1 | //! [`PartialEq`]
// | ^^^^^^^^^ ambiguous link
// |
// = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
// help: to link to the trait, prefix with `trait@`
// |
// 1 | //! [`trait@PartialEq`]
// | ++++++
// help: to link to the derive macro, prefix with `derive@`
// |
// 1 | //! [`derive@PartialEq`]
// | +++++++
// check-pass
#![deny(rustdoc::broken_intra_doc_links)]
//! [`PartialEq`]

View file

@ -0,0 +1,17 @@
// This is ensuring that the UI output for associated items is as expected.
#![deny(rustdoc::broken_intra_doc_links)]
/// [`Trait::IDENT`]
//~^ ERROR both an associated constant and an associated type
pub trait Trait {
type IDENT;
const IDENT: usize;
}
/// [`Trait2::IDENT`]
//~^ ERROR both an associated function and an associated type
pub trait Trait2 {
type IDENT;
fn IDENT() {}
}

View file

@ -0,0 +1,37 @@
error: `Trait::IDENT` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items-2.rs:5:7
|
LL | /// [`Trait::IDENT`]
| ^^^^^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-2.rs:3:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@Trait::IDENT`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Trait::IDENT`]
| +++++
error: `Trait2::IDENT` is both an associated function and an associated type
--> $DIR/issue-108653-associated-items-2.rs:12:7
|
LL | /// [`Trait2::IDENT`]
| ^^^^^^^^^^^^^ ambiguous link
|
help: to link to the associated function, add parentheses
|
LL | /// [`Trait2::IDENT()`]
| ++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Trait2::IDENT`]
| +++++
error: aborting due to 2 previous errors

View file

@ -0,0 +1,16 @@
// This is ensuring that the UI output for associated items works when it's being documented
// from another item.
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
pub trait Trait {
type Trait;
const Trait: usize;
}
/// [`Trait`]
//~^ ERROR both a constant and a trait
/// [`Trait::Trait`]
//~^ ERROR both an associated constant and an associated type
pub const Trait: usize = 0;

View file

@ -0,0 +1,37 @@
error: `Trait` is both a constant and a trait
--> $DIR/issue-108653-associated-items-3.rs:12:7
|
LL | /// [`Trait`]
| ^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-3.rs:4:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the constant, prefix with `const@`
|
LL | /// [`const@Trait`]
| ++++++
help: to link to the trait, prefix with `trait@`
|
LL | /// [`trait@Trait`]
| ++++++
error: `Trait::Trait` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items-3.rs:14:7
|
LL | /// [`Trait::Trait`]
| ^^^^^^^^^^^^ ambiguous link
|
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@Trait::Trait`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Trait::Trait`]
| +++++
error: aborting due to 2 previous errors

View file

@ -0,0 +1,21 @@
// This is ensuring that the UI output for associated items works when it's being documented
// from another item.
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
pub trait Trait {
type Trait;
}
/// [`Struct::Trait`]
//~^ ERROR both an associated constant and an associated type
pub struct Struct;
impl Trait for Struct {
type Trait = Struct;
}
impl Struct {
pub const Trait: usize = 0;
}

View file

@ -0,0 +1,22 @@
error: `Struct::Trait` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items-4.rs:11:7
|
LL | /// [`Struct::Trait`]
| ^^^^^^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-4.rs:4:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@Struct::Trait`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Struct::Trait`]
| +++++
error: aborting due to previous error

View file

@ -0,0 +1,8 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
/// [`u32::MAX`]
//~^ ERROR both an associated constant and a trait
pub mod u32 {
pub trait MAX {}
}

View file

@ -0,0 +1,22 @@
error: `u32::MAX` is both an associated constant and a trait
--> $DIR/issue-108653-associated-items-5.rs:4:7
|
LL | /// [`u32::MAX`]
| ^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-5.rs:1:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@u32::MAX`]
| ++++++
help: to link to the trait, prefix with `trait@`
|
LL | /// [`trait@u32::MAX`]
| ++++++
error: aborting due to previous error

View file

@ -0,0 +1,8 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
/// [`u32::MAX`]
//~^ ERROR both an associated constant and a primitive type
pub mod u32 {
pub use std::primitive::u32 as MAX;
}

View file

@ -0,0 +1,22 @@
error: `u32::MAX` is both an associated constant and a primitive type
--> $DIR/issue-108653-associated-items-6.rs:4:7
|
LL | /// [`u32::MAX`]
| ^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-6.rs:1:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@u32::MAX`]
| ++++++
help: to link to the primitive type, prefix with `prim@`
|
LL | /// [`prim@u32::MAX`]
| +++++
error: aborting due to previous error

View file

@ -0,0 +1,12 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
pub trait Trait {
type MAX;
}
/// [`u32::MAX`]
//~^ ERROR both an associated constant and an associated type
impl Trait for u32 {
type MAX = u32;
}

View file

@ -0,0 +1,22 @@
error: `u32::MAX` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items-7.rs:8:7
|
LL | /// [`u32::MAX`]
| ^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-7.rs:1:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@u32::MAX`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@u32::MAX`]
| +++++
error: aborting due to previous error

View file

@ -0,0 +1,12 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(nonstandard_style)]
/// [`u32::MAX`]
//~^ ERROR both an associated constant and an associated type
pub trait T {
type MAX;
}
impl T for u32 {
type MAX = ();
}

View file

@ -0,0 +1,22 @@
error: `u32::MAX` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items-8.rs:4:7
|
LL | /// [`u32::MAX`]
| ^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items-8.rs:1:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@u32::MAX`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@u32::MAX`]
| +++++
error: aborting due to previous error

View file

@ -0,0 +1,11 @@
// check-pass
#![deny(warnings)]
//! [usize::Item]
pub trait Foo { type Item; }
pub trait Bar { type Item; }
impl Foo for usize { type Item = u32; }
impl Bar for usize { type Item = i32; }

View file

@ -0,0 +1,35 @@
// This is ensuring that the UI output for associated items is as expected.
#![deny(rustdoc::broken_intra_doc_links)]
pub enum Enum {
IDENT,
}
/// [`Self::IDENT`]
//~^ ERROR both an associated function and an associated type
pub trait Trait {
type IDENT;
fn IDENT();
}
/// [`Self::IDENT`]
//~^ ERROR both an associated function and a variant
impl Trait for Enum {
type IDENT = usize;
fn IDENT() {}
}
/// [`Self::IDENT2`]
//~^ ERROR both an associated constant and an associated type
pub trait Trait2 {
type IDENT2;
const IDENT2: usize;
}
/// [`Self::IDENT2`]
//~^ ERROR both an associated constant and an associated type
impl Trait2 for Enum {
type IDENT2 = usize;
const IDENT2: usize = 0;
}

View file

@ -0,0 +1,67 @@
error: `Self::IDENT` is both an associated function and an associated type
--> $DIR/issue-108653-associated-items.rs:9:7
|
LL | /// [`Self::IDENT`]
| ^^^^^^^^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/issue-108653-associated-items.rs:3:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to link to the associated function, add parentheses
|
LL | /// [`Self::IDENT()`]
| ++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Self::IDENT`]
| +++++
error: `Self::IDENT2` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items.rs:23:7
|
LL | /// [`Self::IDENT2`]
| ^^^^^^^^^^^^ ambiguous link
|
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@Self::IDENT2`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Self::IDENT2`]
| +++++
error: `Self::IDENT2` is both an associated constant and an associated type
--> $DIR/issue-108653-associated-items.rs:30:7
|
LL | /// [`Self::IDENT2`]
| ^^^^^^^^^^^^ ambiguous link
|
help: to link to the associated constant, prefix with `const@`
|
LL | /// [`const@Self::IDENT2`]
| ++++++
help: to link to the associated type, prefix with `type@`
|
LL | /// [`type@Self::IDENT2`]
| +++++
error: `Self::IDENT` is both an associated function and a variant
--> $DIR/issue-108653-associated-items.rs:16:7
|
LL | /// [`Self::IDENT`]
| ^^^^^^^^^^^ ambiguous link
|
help: to link to the associated function, add parentheses
|
LL | /// [`Self::IDENT()`]
| ++
help: to link to the variant, prefix with `type@`
|
LL | /// [`type@Self::IDENT`]
| +++++
error: aborting due to 4 previous errors

View file

@ -39,25 +39,25 @@ error: unresolved link to `unit::eq`
--> $DIR/non-path-primitives.rs:28:6 --> $DIR/non-path-primitives.rs:28:6
| |
LL | //! [unit::eq] LL | //! [unit::eq]
| ^^^^^^^^ the builtin type `unit` has no associated item named `eq` | ^^^^^^^^ the primitive type `unit` has no associated item named `eq`
error: unresolved link to `tuple::eq` error: unresolved link to `tuple::eq`
--> $DIR/non-path-primitives.rs:29:6 --> $DIR/non-path-primitives.rs:29:6
| |
LL | //! [tuple::eq] LL | //! [tuple::eq]
| ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq` | ^^^^^^^^^ the primitive type `tuple` has no associated item named `eq`
error: unresolved link to `fn::eq` error: unresolved link to `fn::eq`
--> $DIR/non-path-primitives.rs:30:6 --> $DIR/non-path-primitives.rs:30:6
| |
LL | //! [fn::eq] LL | //! [fn::eq]
| ^^^^^^ the builtin type `fn` has no associated item named `eq` | ^^^^^^ the primitive type `fn` has no associated item named `eq`
error: unresolved link to `reference::deref` error: unresolved link to `reference::deref`
--> $DIR/non-path-primitives.rs:34:6 --> $DIR/non-path-primitives.rs:34:6
| |
LL | //! [reference::deref] LL | //! [reference::deref]
| ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref` | ^^^^^^^^^^^^^^^^ the primitive type `reference` has no associated item named `deref`
error: aborting due to 8 previous errors error: aborting due to 8 previous errors

View file

@ -2,16 +2,16 @@
//~^ NOTE lint level is defined //~^ NOTE lint level is defined
/// [char] /// [char]
//~^ ERROR both a module and a builtin type //~^ ERROR both a module and a primitive type
//~| NOTE ambiguous link //~| NOTE ambiguous link
//~| HELP to link to the module //~| HELP to link to the module
//~| HELP to link to the builtin type //~| HELP to link to the primitive type
/// [type@char] /// [type@char]
//~^ ERROR both a module and a builtin type //~^ ERROR both a module and a primitive type
//~| NOTE ambiguous link //~| NOTE ambiguous link
//~| HELP to link to the module //~| HELP to link to the module
//~| HELP to link to the builtin type //~| HELP to link to the primitive type
/// [mod@char] // ok /// [mod@char] // ok
/// [prim@char] // ok /// [prim@char] // ok
@ -26,5 +26,5 @@ pub mod inner {
//! [struct@char] //! [struct@char]
//~^ ERROR incompatible link //~^ ERROR incompatible link
//~| HELP prefix with `prim@` //~| HELP prefix with `prim@`
//~| NOTE resolved to a builtin type //~| NOTE resolved to a primitive type
} }

View file

@ -1,4 +1,4 @@
error: `char` is both a module and a builtin type error: `char` is both a module and a primitive type
--> $DIR/prim-conflict.rs:4:6 --> $DIR/prim-conflict.rs:4:6
| |
LL | /// [char] LL | /// [char]
@ -13,12 +13,12 @@ help: to link to the module, prefix with `mod@`
| |
LL | /// [mod@char] LL | /// [mod@char]
| ++++ | ++++
help: to link to the builtin type, prefix with `prim@` help: to link to the primitive type, prefix with `prim@`
| |
LL | /// [prim@char] LL | /// [prim@char]
| +++++ | +++++
error: `char` is both a module and a builtin type error: `char` is both a module and a primitive type
--> $DIR/prim-conflict.rs:10:6 --> $DIR/prim-conflict.rs:10:6
| |
LL | /// [type@char] LL | /// [type@char]
@ -28,7 +28,7 @@ help: to link to the module, prefix with `mod@`
| |
LL | /// [mod@char] LL | /// [mod@char]
| ~~~~ | ~~~~
help: to link to the builtin type, prefix with `prim@` help: to link to the primitive type, prefix with `prim@`
| |
LL | /// [prim@char] LL | /// [prim@char]
| ~~~~~ | ~~~~~
@ -48,9 +48,9 @@ error: incompatible link kind for `char`
--> $DIR/prim-conflict.rs:26:10 --> $DIR/prim-conflict.rs:26:10
| |
LL | //! [struct@char] LL | //! [struct@char]
| ^^^^^^^^^^^ this link resolved to a builtin type, which is not a struct | ^^^^^^^^^^^ this link resolved to a primitive type, which is not a struct
| |
help: to link to the builtin type, prefix with `prim@` help: to link to the primitive type, prefix with `prim@`
| |
LL | //! [prim@char] LL | //! [prim@char]
| ~~~~~ | ~~~~~

View file

@ -1,10 +1,10 @@
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![crate_name = "foo"] #![crate_name = "foo"]
pub use std::fs::File; pub use std::fs::File;
// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation' // @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
#[doc(primitive = "i16")] #[rustc_doc_primitive = "i16"]
/// I love poneys! /// I love poneys!
mod prim {} mod prim {}

View file

@ -2,6 +2,7 @@
// compile-flags: -Cmetadata=aux // compile-flags: -Cmetadata=aux
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![doc(html_root_url = "http://example.com/")] #![doc(html_root_url = "http://example.com/")]
#![feature(rustc_attrs)]
#![feature(lang_items)] #![feature(lang_items)]
#![no_std] #![no_std]
@ -12,5 +13,5 @@ fn foo() {}
fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
/// dox /// dox
#[doc(primitive = "pointer")] #[rustc_doc_primitive = "pointer"]
pub mod ptr {} pub mod ptr {}

View file

@ -1,9 +1,10 @@
// compile-flags: --crate-type lib --edition 2018 // compile-flags: --crate-type lib --edition 2018
#![feature(rustc_attrs)]
#![feature(no_core)] #![feature(no_core)]
#![no_core] #![no_core]
#[doc(primitive = "usize")] #[rustc_doc_primitive = "usize"]
/// This is the built-in type `usize`. /// This is the built-in type `usize`.
mod usize { mod usize {
} }

View file

@ -2,7 +2,7 @@
// aux-build:source_code.rs // aux-build:source_code.rs
// build-aux-docs // build-aux-docs
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![crate_name = "foo"] #![crate_name = "foo"]
@ -65,5 +65,5 @@ pub fn foo4() {
} }
// @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool' // @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool'
#[doc(primitive = "bool")] #[rustc_doc_primitive = "bool"]
mod whatever {} mod whatever {}

View file

@ -3,7 +3,7 @@
#![rustc_coherence_is_core] #![rustc_coherence_is_core]
#![crate_type="rlib"] #![crate_type="rlib"]
#[doc(primitive = "char")] #[rustc_doc_primitive = "char"]
/// Some char docs /// Some char docs
mod char {} mod char {}

View file

@ -1,4 +1,4 @@
// Crate tree without a `doc(primitive)` module for primitive type linked to by a doc link. // Crate tree without a `rustc_doc_primitive` module for primitive type linked to by a doc link.
#![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::broken_intra_doc_links)]
#![feature(no_core, lang_items, rustc_attrs)] #![feature(no_core, lang_items, rustc_attrs)]

View file

@ -10,7 +10,7 @@
//! A [prim@`char`] and its [`char::len_utf8`]. //! A [prim@`char`] and its [`char::len_utf8`].
#[doc(primitive = "char")] #[rustc_doc_primitive = "char"]
mod char {} mod char {}
impl char { impl char {

View file

@ -25,7 +25,7 @@ impl usize {
pub type ME = usize; pub type ME = usize;
} }
#[doc(primitive = "usize")] #[rustc_doc_primitive = "usize"]
/// This has some docs. /// This has some docs.
mod usize {} mod usize {}

View file

@ -1,7 +1,7 @@
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has issue_15318_3/primitive.pointer.html // @has issue_15318_3/primitive.pointer.html
/// dox /// dox
#[doc(primitive = "pointer")] #[rustc_doc_primitive = "pointer"]
pub mod ptr {} pub mod ptr {}

View file

@ -3,7 +3,7 @@
#![no_std] #![no_std]
pub mod str { pub mod str {
#![doc(primitive = "str")] #![rustc_doc_primitive = "str"]
impl str { impl str {
// @hasraw search-index.js foo // @hasraw search-index.js foo

View file

@ -6,10 +6,10 @@
//! //!
//! [#80737]: https://github.com/rust-lang/rust/issues/80737 //! [#80737]: https://github.com/rust-lang/rust/issues/80737
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![no_std] #![no_std]
#[doc(primitive = "reference")] #[rustc_doc_primitive = "reference"]
/// Some useless docs, wouhou! /// Some useless docs, wouhou!
/// ///
/// We need to put this in here, because notable traits /// We need to put this in here, because notable traits

View file

@ -5,9 +5,9 @@
//! //!
//! [#78160]: https://github.com/rust-lang/rust/issues/78160 //! [#78160]: https://github.com/rust-lang/rust/issues/78160
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#[doc(primitive = "reference")] #[rustc_doc_primitive = "reference"]
/// Some useless docs, wouhou! /// Some useless docs, wouhou!
/// ///
/// We need to put this in here, because notable traits /// We need to put this in here, because notable traits

View file

@ -1,6 +1,6 @@
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has foo/index.html // @has foo/index.html
// @has - '//h2[@id="primitives"]' 'Primitive Types' // @has - '//h2[@id="primitives"]' 'Primitive Types'
@ -16,7 +16,7 @@
// @count - '//*[@class="impl"]' 1 // @count - '//*[@class="impl"]' 1
// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \ // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
// 'impl<A, B> Foo<&A> for &B' // 'impl<A, B> Foo<&A> for &B'
#[doc(primitive = "reference")] #[rustc_doc_primitive = "reference"]
/// this is a test! /// this is a test!
mod reference {} mod reference {}

View file

@ -1,7 +1,7 @@
// compile-flags: --crate-type lib --edition 2018 // compile-flags: --crate-type lib --edition 2018
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice' // @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
// @has - '//h1' 'Primitive Type slice' // @has - '//h1' 'Primitive Type slice'
@ -9,6 +9,6 @@
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' // @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> Send for [T]where T: Send'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T]where T: Sync' // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T]where T: Sync'
#[doc(primitive = "slice")] #[rustc_doc_primitive = "slice"]
/// this is a test! /// this is a test!
mod slice_prim {} mod slice_prim {}

View file

@ -1,7 +1,7 @@
// compile-flags: --crate-type lib --edition 2018 // compile-flags: --crate-type lib --edition 2018
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple' // @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
// @has - '//h1' 'Primitive Type tuple' // @has - '//h1' 'Primitive Type tuple'
@ -9,7 +9,7 @@
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send' // @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Sync' // @has - '//div[@id="synthetic-implementations-list"]//h3' 'Sync'
#[doc(primitive = "tuple")] #[rustc_doc_primitive = "tuple"]
/// this is a test! /// this is a test!
/// ///
// Hardcoded anchor to header written in library/core/src/primitive_docs.rs // Hardcoded anchor to header written in library/core/src/primitive_docs.rs

View file

@ -1,7 +1,7 @@
// compile-flags: --crate-type lib --edition 2018 // compile-flags: --crate-type lib --edition 2018
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit' // @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
// @has - '//h1' 'Primitive Type unit' // @has - '//h1' 'Primitive Type unit'
@ -9,6 +9,6 @@
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' // @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 Send for ()'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()' // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()'
#[doc(primitive = "unit")] #[rustc_doc_primitive = "unit"]
/// this is a test! /// this is a test!
mod unit_prim {} mod unit_prim {}

View file

@ -1,8 +1,8 @@
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T' // @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T'
#[doc(primitive = "i32")] #[rustc_doc_primitive = "i32"]
/// Some useless docs, wouhou! /// Some useless docs, wouhou!
mod i32 {} mod i32 {}

View file

@ -1,6 +1,6 @@
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types' // @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types'
// @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32' // @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32'
@ -11,11 +11,11 @@
// @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' // @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 '//a/@href' '../foo/index.html'
// @!has foo/index.html '//span' '🔒' // @!has foo/index.html '//span' '🔒'
#[doc(primitive = "i32")] #[rustc_doc_primitive = "i32"]
/// this is a test! /// this is a test!
mod i32{} mod i32{}
// @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' // @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
#[doc(primitive = "bool")] #[rustc_doc_primitive = "bool"]
/// hello /// hello
mod bool {} mod bool {}

View file

@ -1,6 +1,6 @@
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @has 'foo/all.html' // @has 'foo/all.html'
// @has - '//*[@class="sidebar-elems"]//li' 'Structs' // @has - '//*[@class="sidebar-elems"]//li' 'Structs'
@ -31,5 +31,5 @@ macro_rules! foo {
pub type Type = u8; pub type Type = u8;
pub const FOO: u8 = 0; pub const FOO: u8 = 0;
pub static BAR: u8 = 0; pub static BAR: u8 = 0;
#[doc(primitive = "u8")] #[rustc_doc_primitive = "u8"]
mod u8 {} mod u8 {}

View file

@ -1,4 +1,5 @@
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
// tests for the html <title> element // tests for the html <title> element
@ -39,6 +40,6 @@ mod continue_keyword {}
// @has foo/primitive.u8.html '//head/title' 'u8 - Rust' // @has foo/primitive.u8.html '//head/title' 'u8 - Rust'
// @!has - '//head/title' 'foo' // @!has - '//head/title' 'foo'
#[doc(primitive = "u8")] #[rustc_doc_primitive = "u8"]
/// `u8` docs /// `u8` docs
mod u8 {} mod u8 {}

View file

@ -1,5 +1,5 @@
#![crate_name = "foo"] #![crate_name = "foo"]
#![feature(rustdoc_internals)] #![feature(rustc_attrs)]
// @matches 'foo/index.html' '//h1' 'Crate foo' // @matches 'foo/index.html' '//h1' 'Crate foo'
// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo' // @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
@ -41,7 +41,7 @@ macro_rules! foo_macro {
} }
// @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' // @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
#[doc(primitive = "bool")] #[rustc_doc_primitive = "bool"]
mod bool {} mod bool {}
// @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC' // @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'

View file

@ -1,4 +1,4 @@
// normalize-stderr-test "note.*" -> "note: os-specific message" // normalize-stderr-test "could not open Fluent resource:.*" -> "could not open Fluent resource: os-specific message"
#![feature(rustc_private)] #![feature(rustc_private)]
#![crate_type = "lib"] #![crate_type = "lib"]

View file

@ -1,18 +1,14 @@
error: could not open Fluent resource error: could not open Fluent resource: os-specific message
--> $DIR/test.rs:24:24 --> $DIR/test.rs:24:24
| |
LL | fluent_messages! { "/definitely_does_not_exist.ftl" } LL | fluent_messages! { "/definitely_does_not_exist.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: os-specific message
error: could not open Fluent resource error: could not open Fluent resource: os-specific message
--> $DIR/test.rs:31:24 --> $DIR/test.rs:31:24
| |
LL | fluent_messages! { "../definitely_does_not_exist.ftl" } LL | fluent_messages! { "../definitely_does_not_exist.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: os-specific message
error: could not parse Fluent resource error: could not parse Fluent resource
--> $DIR/test.rs:38:24 --> $DIR/test.rs:38:24
@ -89,7 +85,7 @@ error: invalid escape `\n` in Fluent resource
LL | fluent_messages! { "./invalid-escape.ftl" } LL | fluent_messages! { "./invalid-escape.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
| |
= note: os-specific message = note: Fluent does not interpret these escape sequences (<https://projectfluent.org/fluent/guide/special.html>)
error: invalid escape `\"` in Fluent resource error: invalid escape `\"` in Fluent resource
--> $DIR/test.rs:99:24 --> $DIR/test.rs:99:24
@ -97,7 +93,7 @@ error: invalid escape `\"` in Fluent resource
LL | fluent_messages! { "./invalid-escape.ftl" } LL | fluent_messages! { "./invalid-escape.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
| |
= note: os-specific message = note: Fluent does not interpret these escape sequences (<https://projectfluent.org/fluent/guide/special.html>)
error: invalid escape `\'` in Fluent resource error: invalid escape `\'` in Fluent resource
--> $DIR/test.rs:99:24 --> $DIR/test.rs:99:24
@ -105,7 +101,7 @@ error: invalid escape `\'` in Fluent resource
LL | fluent_messages! { "./invalid-escape.ftl" } LL | fluent_messages! { "./invalid-escape.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
| |
= note: os-specific message = note: Fluent does not interpret these escape sequences (<https://projectfluent.org/fluent/guide/special.html>)
error: aborting due to 13 previous errors error: aborting due to 13 previous errors

View file

@ -0,0 +1,13 @@
// regression test for #109298
// edition: 2021
pub fn subslice_array(x: [u8; 3]) {
let f = || {
let [_x @ ..] = x;
let [ref y, ref mut z @ ..] = x; //~ ERROR cannot borrow `x[..]` as mutable
};
f(); //~ ERROR cannot borrow `f` as mutable
}
fn main() {}

View file

@ -0,0 +1,26 @@
error[E0596]: cannot borrow `x[..]` as mutable, as `x` is not declared as mutable
--> $DIR/array_subslice.rs:7:21
|
LL | pub fn subslice_array(x: [u8; 3]) {
| - help: consider changing this to be mutable: `mut x`
...
LL | let [ref y, ref mut z @ ..] = x;
| ^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/array_subslice.rs:10:5
|
LL | let [ref y, ref mut z @ ..] = x;
| - calling `f` requires mutable binding due to mutable borrow of `x`
...
LL | f();
| ^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
LL | let mut f = || {
| +++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0596`.

View file

@ -0,0 +1,8 @@
#![deny(invalid_doc_attributes)]
#[doc(primitive = "foo")]
//~^ ERROR unknown `doc` attribute `primitive`
//~| WARN
mod bar {}
fn main() {}

View file

@ -0,0 +1,16 @@
error: unknown `doc` attribute `primitive`
--> $DIR/doc-primitive.rs:3:7
|
LL | #[doc(primitive = "foo")]
| ^^^^^^^^^^^^^^^^^
|
= 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: the lint level is defined here
--> $DIR/doc-primitive.rs:1:9
|
LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -1,7 +1,5 @@
// check-pass #[rustc_doc_primitive = "usize"]
#[doc(primitive = "usize")] //~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
//~^ WARNING `doc(primitive)` should never have been stable
//~| WARNING hard error in a future release
/// Some docs /// Some docs
mod usize {} mod usize {}

View file

@ -1,12 +1,11 @@
warning: `doc(primitive)` should never have been stable error[E0658]: `rustc_doc_primitive` is a rustc internal attribute
--> $DIR/feature-gate-doc_primitive.rs:2:7 --> $DIR/feature-gate-doc_primitive.rs:1:1
| |
LL | #[doc(primitive = "usize")] LL | #[rustc_doc_primitive = "usize"]
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
warning: 1 warning emitted error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.