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> {
let _timer =
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;
@ -85,7 +85,7 @@ impl base::AttrProcMacro for AttrProcMacro {
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
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;
@ -134,7 +134,11 @@ impl MultiItemModifier for DeriveProcMacro {
let stream = {
let _timer =
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 strategy = exec_strategy(ecx);

View file

@ -225,7 +225,7 @@ declare_features! (
(active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
/// Allows using compiler's own crates.
(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),
/// Allows using the `rustdoc::missing_doc_code_examples` lint
(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 \
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:

View file

@ -1893,14 +1893,13 @@ fn restrict_capture_precision(
for (i, proj) in place.projections.iter().enumerate() {
match proj.kind {
ProjectionKind::Index => {
// Arrays are completely captured, so we drop Index projections
ProjectionKind::Index | ProjectionKind::Subslice => {
// 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);
return (place, curr_mode);
}
ProjectionKind::Deref => {}
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,
};
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 _sess_abort_error = OnDrop(|| {
compiler.sess.finish_diagnostics(registry);

View file

@ -15,8 +15,7 @@ use proc_macro2::TokenStream;
use quote::quote;
use std::{
collections::{HashMap, HashSet},
fs::File,
io::Read,
fs::read_to_string,
path::{Path, PathBuf},
};
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
// re-executed when the file changes.
let mut resource_file = match File::open(absolute_ftl_path) {
Ok(resource_file) => resource_file,
let resource_contents = match read_to_string(absolute_ftl_path) {
Ok(resource_contents) => resource_contents,
Err(e) => {
Diagnostic::spanned(resource_span, Level::Error, "could not open Fluent resource")
.note(e.to_string())
.emit();
Diagnostic::spanned(
resource_span,
Level::Error,
format!("could not open Fluent resource: {}", e.to_string()),
)
.emit();
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;
for esc in ["\\n", "\\\"", "\\'"] {
for _ in resource_contents.matches(esc) {

View file

@ -148,9 +148,6 @@ passes_doc_test_unknown =
passes_doc_test_takes_list =
`#[doc(test(...)]` takes a list of attributes
passes_doc_primitive =
`doc(primitive)` should never have been stable
passes_doc_cfg_hide_takes_list =
`#[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);
if i_meta.has_name(sym::spotlight) {

View file

@ -288,10 +288,6 @@ pub struct DocTestTakesList;
#[diag(passes_doc_cfg_hide_takes_list)]
pub struct DocCfgHideTakesList;
#[derive(LintDiagnostic)]
#[diag(passes_doc_primitive)]
pub struct DocPrimitive;
#[derive(LintDiagnostic)]
#[diag(passes_doc_test_unknown_any)]
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)
}
/// Has `#[doc(primitive)]` or `#[doc(keyword)]`.
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool {
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 {
if item.has_name(sym::primitive) || item.has_name(sym::keyword) {
if item.has_name(sym::keyword) {
return true;
}
}

View file

@ -87,6 +87,14 @@ pub struct SessionGlobals {
symbol_interner: symbol::Interner,
span_interner: Lock<span_encoding::SpanInterner>,
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>>>,
}
@ -1013,16 +1021,9 @@ impl<D: Decoder> Decodable<D> for Span {
}
}
/// Calls the provided closure, using the provided `SourceMap` to format
/// any spans that are debug-printed during the closure's execution.
///
/// 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 {
/// Insert `source_map` into the session globals for the duration of the
/// closure's execution.
pub fn set_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
with_session_globals(|session_globals| {
*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 {
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| {
if let Some(source_map) = &*session_globals.source_map.borrow() {
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 rustc_data_structures::profiling::EventArgRecorder;
@ -11,25 +13,17 @@ pub trait SpannedEventArgRecorder {
///
/// 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.
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
A: Borrow<str> + Into<String>;
}
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
A: Borrow<str> + Into<String>,
{
self.record_arg(event_arg);
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);
self.record_arg(source_map.span_to_embeddable_string(span));
}
}

View file

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

View file

@ -1,7 +1,8 @@
// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
// 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.
#[doc(primitive = "bool")]
#[cfg_attr(bootstrap, doc(primitive = "bool"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
#[doc(alias = "true")]
#[doc(alias = "false")]
/// The boolean type.
@ -63,7 +64,8 @@
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool {}
#[doc(primitive = "never")]
#[cfg_attr(bootstrap, doc(primitive = "never"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
#[doc(alias = "!")]
//
/// The `!` type, also called "never".
@ -274,7 +276,8 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")]
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)]
/// A character type.
///
@ -398,7 +401,8 @@ mod prim_never {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "()")]
@ -460,7 +464,8 @@ impl Copy for () {
// empty
}
#[doc(primitive = "pointer")]
#[cfg_attr(bootstrap, doc(primitive = "pointer"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
#[doc(alias = "ptr")]
#[doc(alias = "*")]
#[doc(alias = "*const")]
@ -577,7 +582,8 @@ impl Copy for () {
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_pointer {}
#[doc(primitive = "array")]
#[cfg_attr(bootstrap, doc(primitive = "array"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
#[doc(alias = "[]")]
#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
#[doc(alias = "[T; N]")]
@ -778,7 +784,8 @@ mod prim_pointer {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "[]")]
@ -870,7 +877,8 @@ mod prim_array {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {}
#[doc(primitive = "str")]
#[cfg_attr(bootstrap, doc(primitive = "str"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
/// String slices.
///
/// *[See also the `std::str` module](crate::str).*
@ -937,7 +945,8 @@ mod prim_slice {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "()")]
@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
// 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).
///
/// 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")]
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).
///
/// This type is very similar to [`f32`], but has increased
@ -1162,67 +1173,78 @@ mod prim_f32 {}
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "i128", since = "1.26.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "i128", since = "1.26.0")]
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.
///
@ -1232,7 +1254,8 @@ mod prim_u128 {}
#[stable(feature = "rust1", since = "1.0.0")]
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.
///
@ -1242,7 +1265,8 @@ mod prim_isize {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize {}
#[doc(primitive = "reference")]
#[cfg_attr(bootstrap, doc(primitive = "reference"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
#[doc(alias = "&")]
#[doc(alias = "&mut")]
//
@ -1373,7 +1397,8 @@ mod prim_usize {}
#[stable(feature = "rust1", since = "1.0.0")]
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`.
///

View file

@ -1,7 +1,8 @@
// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
// 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.
#[doc(primitive = "bool")]
#[cfg_attr(bootstrap, doc(primitive = "bool"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
#[doc(alias = "true")]
#[doc(alias = "false")]
/// The boolean type.
@ -63,7 +64,8 @@
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_bool {}
#[doc(primitive = "never")]
#[cfg_attr(bootstrap, doc(primitive = "never"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
#[doc(alias = "!")]
//
/// The `!` type, also called "never".
@ -274,7 +276,8 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")]
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)]
/// A character type.
///
@ -398,7 +401,8 @@ mod prim_never {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "()")]
@ -460,7 +464,8 @@ impl Copy for () {
// empty
}
#[doc(primitive = "pointer")]
#[cfg_attr(bootstrap, doc(primitive = "pointer"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
#[doc(alias = "ptr")]
#[doc(alias = "*")]
#[doc(alias = "*const")]
@ -577,7 +582,8 @@ impl Copy for () {
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_pointer {}
#[doc(primitive = "array")]
#[cfg_attr(bootstrap, doc(primitive = "array"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
#[doc(alias = "[]")]
#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
#[doc(alias = "[T; N]")]
@ -778,7 +784,8 @@ mod prim_pointer {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "[]")]
@ -870,7 +877,8 @@ mod prim_array {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {}
#[doc(primitive = "str")]
#[cfg_attr(bootstrap, doc(primitive = "str"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
/// String slices.
///
/// *[See also the `std::str` module](crate::str).*
@ -937,7 +945,8 @@ mod prim_slice {}
#[stable(feature = "rust1", since = "1.0.0")]
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 = "()")]
@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
// 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).
///
/// 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")]
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).
///
/// This type is very similar to [`f32`], but has increased
@ -1162,67 +1173,78 @@ mod prim_f32 {}
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "i128", since = "1.26.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "rust1", since = "1.0.0")]
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.
#[stable(feature = "i128", since = "1.26.0")]
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.
///
@ -1232,7 +1254,8 @@ mod prim_u128 {}
#[stable(feature = "rust1", since = "1.0.0")]
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.
///
@ -1242,7 +1265,8 @@ mod prim_isize {}
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize {}
#[doc(primitive = "reference")]
#[cfg_attr(bootstrap, doc(primitive = "reference"))]
#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
#[doc(alias = "&")]
#[doc(alias = "&mut")]
//
@ -1373,7 +1397,8 @@ mod prim_usize {}
#[stable(feature = "rust1", since = "1.0.0")]
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`.
///

View file

@ -177,9 +177,9 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
This is for Rust compiler internal use only.
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
to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
enable.
attributes. The `#[rustc_doc_primitive = "..."]` attribute is used by the standard library to
provide a way to generate documentation for primitive types, and requires `#![feature(rustc_attrs)]`
to enable.
### Document keywords

View file

@ -249,38 +249,24 @@ impl ExternalCrate {
//
// 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
// 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
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
// `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
//
// 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.
//
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
let as_primitive = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res {
let mut prim = None;
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?
}
}
}
return prim.map(|p| (def_id, p));
}
None
let Res::Def(DefKind::Mod, def_id) = res else { return None };
tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| {
// FIXME: should warn on unknown primitives?
Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?))
})
};
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.
///
/// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
/// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
/// In particular, if a crate depends on both `std` and another crate that also defines `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.)
/// This gives precedence to primitives defined in the current crate, and deprioritizes
/// primitives defined in `core`,
/// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
/// 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> {
static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
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>, \
and <code>const</code>.",
"Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
<code>-&gt; vec</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>)",
<code>-&gt; vec</code> or <code>String, enum:Cow -&gt; bool</code>)",
"You can look for items with an exact name by putting double quotes around \
your request: <code>\"string\"</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
// generate the ID.
if matches!(tcx.def_kind(def_id), DefKind::Mod) &&
let Some(prim) = tcx.get_attrs(*def_id, sym::doc)
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
.filter(|attr| attr.has_name(sym::primitive))
let Some(prim) = tcx.get_attrs(*def_id, sym::rustc_doc_primitive)
.find_map(|attr| attr.value_str()) {
format!(":{}", prim.as_u32())
} else {

View file

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

View file

@ -47,7 +47,18 @@ fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
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 {
Def(DefKind, DefId),
Primitive(PrimitiveType),
@ -59,7 +70,7 @@ impl Res {
fn descr(self) -> &'static str {
match self {
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,
ns: Namespace,
item_name: Symbol,
) -> Option<(Res, DefId)> {
) -> Vec<(Res, DefId)> {
let tcx = self.cx.tcx;
prim_ty.impls(tcx).find_map(|impl_| {
tcx.associated_items(impl_)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
prim_ty
.impls(tcx)
.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))
})
})
.collect::<Vec<_>>()
}
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,
item_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) {
return Ok(match res {
Res::Def(
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Variant,
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 {
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
// links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
// links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity
// error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all
// primitives.
resolve_primitive(&path_root, TypeNS)
match resolve_primitive(&path_root, TypeNS)
.or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
.and_then(|ty_res| {
self.resolve_associated_item(ty_res, item_name, ns, module_id).map(Ok)
})
.unwrap_or_else(|| {
let candidates = self
.resolve_associated_item(ty_res, item_name, ns, module_id)
.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 {
self.variant_field(path_str, item_id, module_id)
.map(|(res, def_id)| vec![(res, Some(def_id))])
} else {
Err(UnresolvedPath {
item_id,
@ -452,8 +479,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
unresolved: path_root.into(),
})
}
})
.map(|(res, def_id)| (res, Some(def_id)))
}
}
}
/// Convert a DefId to a Res, where possible.
@ -535,24 +562,31 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
item_name: Symbol,
ns: Namespace,
module_id: DefId,
) -> Option<(Res, DefId)> {
) -> Vec<(Res, DefId)> {
let tcx = self.cx.tcx;
match root_res {
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)
.and_then(|ty| {
.map(|ty| {
resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
.iter()
.map(|item| (root_res, item.def_id))
.collect::<Vec<_>>()
})
.map(|item| (root_res, item.def_id))
})
.unwrap_or(Vec::new())
}
}
Res::Def(DefKind::TyAlias, did) => {
// Resolve the link on the type the alias points to.
// 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.
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)
}
Res::Def(
@ -566,7 +600,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty::Adt(adt_def, _) => {
for variant in adt_def.variants() {
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`
let assoc_item = tcx
let mut assoc_items: Vec<_> = tcx
.inherent_impls(did)
.iter()
.flat_map(|&imp| {
tcx.associated_items(imp).find_by_name_and_namespace(
filter_assoc_items_by_name_and_namespace(
tcx,
imp,
Ident::with_dummy_span(item_name),
ns,
imp,
)
})
.copied()
// There should only ever be one associated item that matches from any inherent impl
.next()
.map(|item| (root_res, item.def_id))
.collect();
if assoc_items.is_empty() {
// Check if item_name belongs to `impl SomeTrait for SomeItem`
// FIXME(#74563): This gives precedence to `impl SomeItem`:
// Although having both would be ambiguous, use impl version for compatibility's sake.
// To handle that properly resolve() would have to support
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
.or_else(|| {
resolve_associated_trait_item(
tcx.type_of(did).subst_identity(),
module_id,
item_name,
ns,
self.cx,
)
});
assoc_items = resolve_associated_trait_item(
tcx.type_of(did).subst_identity(),
module_id,
item_name,
ns,
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 {
return Some((root_res, item.def_id));
if !assoc_items.is_empty() {
return assoc_items;
}
if ns != Namespace::ValueNS {
return None;
return Vec::new();
}
debug!("looking for fields named {} for {:?}", item_name, did);
// 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.
let def = match tcx.type_of(did).subst_identity().kind() {
ty::Adt(def, _) if !def.is_enum() => def,
_ => return None,
_ => return Vec::new(),
};
let field =
def.non_enum_variant().fields.iter().find(|item| item.name == item_name)?;
Some((root_res, field.did))
def.non_enum_variant()
.fields
.iter()
.filter(|field| field.name == item_name)
.map(|field| (root_res, field.did))
.collect::<Vec<_>>()
}
Res::Def(DefKind::Trait, did) => tcx
.associated_items(did)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
.map(|item| {
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
(res, item.def_id)
}),
_ => None,
Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
tcx,
did,
Ident::with_dummy_span(item_name),
ns,
)
.map(|item| {
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
(res, item.def_id)
})
.collect::<Vec<_>>(),
_ => Vec::new(),
}
}
}
@ -664,7 +708,7 @@ fn resolve_associated_trait_item<'a>(
item_name: Symbol,
ns: Namespace,
cx: &mut DocContext<'a>,
) -> Option<ty::AssocItem> {
) -> Vec<ty::AssocItem> {
// 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
// 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`
// Give precedence to inherent impls.
let traits = trait_impls_for(cx, ty, module);
let tcx = cx.tcx;
debug!("considering traits {:?}", traits);
let mut candidates = traits.iter().filter_map(|&(impl_, trait_)| {
cx.tcx
.associated_items(trait_)
.find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_)
.map(|trait_assoc| {
trait_assoc_to_impl_assoc_item(cx.tcx, impl_, trait_assoc.def_id)
let candidates = traits
.iter()
.flat_map(|&(impl_, trait_)| {
filter_assoc_items_by_name_and_namespace(
cx.tcx,
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)
})
});
})
.collect::<Vec<_>>();
// FIXME(#74563): warn about ambiguity
debug!("the candidates were {:?}", candidates.clone().collect::<Vec<_>>());
candidates.next()
debug!("the candidates were {:?}", candidates);
candidates
}
/// 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.
///
/// 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 {
matches!(
*ns,
PerNS {
type_ns: Ok((Res::Def(DefKind::Trait, _), _)),
macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)),
..
}
)
fn is_derive_trait_collision<T>(ns: &PerNS<Result<Vec<(Res, T)>, ResolutionFailure<'_>>>) -> bool {
if let (&Ok(ref type_ns), &Ok(ref macro_ns)) = (&ns.type_ns, &ns.macro_ns) {
type_ns.iter().any(|(res, _)| matches!(res, Res::Def(DefKind::Trait, _)))
&& macro_ns
.iter()
.any(|(res, _)| matches!(res, Res::Def(DefKind::Macro(MacroKind::Derive), _)))
} else {
false
}
}
impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
@ -987,15 +1038,15 @@ impl LinkCollector<'_, '_> {
res = prim;
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
ambiguity_error(self.cx, diag_info, path_str, candidates);
let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)];
ambiguity_error(self.cx, &diag_info, path_str, candidates);
return None;
}
}
}
match res {
Res::Primitive(prim) => {
Res::Primitive(_) => {
if let Some(UrlFragment::Item(id)) = fragment {
// 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.
@ -1015,15 +1066,6 @@ impl LinkCollector<'_, '_> {
item,
&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 {
match disambiguator {
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| {
item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
}) {
@ -1144,10 +1186,9 @@ impl LinkCollector<'_, '_> {
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) {
let span =
super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
.unwrap_or_else(|| item.attr_span(self.cx.tcx));
fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) {
let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs)
.unwrap_or_else(|| item.attr_span(self.cx.tcx));
rustc_session::parse::feature_err(
&self.cx.tcx.sess.parse_sess,
sym::intra_doc_pointers,
@ -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) {
(Some(_), Some(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, None) => None,
};
Some((res, fragment))
});
if res.is_some() || cache_errors {
self.visited_links.insert(key, res.clone());
let r = Some((res, fragment));
self.visited_links.insert(key, r.clone());
return r;
}
res
if cache_errors {
self.visited_links.insert(key, None);
}
None
}
/// After parsing the disambiguator, resolve the main part of the link.
@ -1197,7 +1264,7 @@ impl LinkCollector<'_, '_> {
&mut self,
key: &ResolutionInfo,
diag: DiagnosticInfo<'_>,
) -> Option<(Res, Option<DefId>)> {
) -> Vec<(Res, Option<DefId>)> {
let disambiguator = key.dis;
let path_str = &key.path_str;
let item_id = key.item_id;
@ -1206,7 +1273,7 @@ impl LinkCollector<'_, '_> {
match disambiguator.map(Disambiguator::ns) {
Some(expected_ns) => {
match self.resolve(path_str, expected_ns, item_id, module_id) {
Ok(res) => Some(res),
Ok(candidates) => candidates,
Err(err) => {
// 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`.
@ -1215,10 +1282,11 @@ impl LinkCollector<'_, '_> {
for other_ns in [TypeNS, ValueNS, MacroNS] {
if other_ns != expected_ns {
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 {
res: full_res(self.cx.tcx, res),
res: full_res(self.cx.tcx, res[0]),
expected_ns,
};
break;
@ -1239,18 +1307,26 @@ impl LinkCollector<'_, '_> {
let candidates = PerNS {
macro_ns: candidate(MacroNS),
type_ns: candidate(TypeNS),
value_ns: candidate(ValueNS).and_then(|(res, def_id)| {
match res {
// Constructors are picked up in the type namespace.
Res::Def(DefKind::Ctor(..), _) => {
Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS })
value_ns: candidate(ValueNS).and_then(|v_res| {
for (res, _) in v_res.iter() {
match res {
// Constructors are picked up in the type namespace.
Res::Def(DefKind::Ctor(..), _) => {
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 {
return resolution_failure(
@ -1260,22 +1336,21 @@ impl LinkCollector<'_, '_> {
disambiguator,
candidates.into_iter().filter_map(|res| res.err()).collect(),
);
}
if len == 1 {
Some(candidates.into_iter().find_map(|res| res.ok()).unwrap())
} else if len == 2 && is_derive_trait_collision(&candidates) {
Some(candidates.type_ns.unwrap())
} else if len == 1 {
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
} else {
let ignore_macro = is_derive_trait_collision(&candidates);
// If we're reporting an ambiguity, don't mention the namespaces that failed
let mut candidates =
candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
if ignore_macro {
candidates.macro_ns = None;
let has_derive_trait_collision = is_derive_trait_collision(&candidates);
if len == 2 && has_derive_trait_collision {
candidates.type_ns.unwrap()
} else {
// If we're reporting an ambiguity, don't mention the namespaces that failed
let mut candidates = candidates.map(|candidate| candidate.ok());
// If there a collision between a trait and a derive, we ignore the derive.
if has_derive_trait_collision {
candidates.macro_ns = None;
}
candidates.into_iter().filter_map(|res| res).flatten().collect::<Vec<_>>()
}
ambiguity_error(self.cx, diag, path_str, candidates.present_items().collect());
None
}
}
}
@ -1563,7 +1638,7 @@ fn resolution_failure(
path_str: &str,
disambiguator: Option<Disambiguator>,
kinds: SmallVec<[ResolutionFailure<'_>; 3]>,
) -> Option<(Res, Option<DefId>)> {
) -> Vec<(Res, Option<DefId>)> {
let tcx = collector.cx.tcx;
let mut recovered_res = None;
report_diagnostic(
@ -1622,11 +1697,13 @@ fn resolution_failure(
};
name = start;
for ns in [TypeNS, ValueNS, MacroNS] {
if let Ok(res) = collector.resolve(start, ns, item_id, module_id) {
debug!("found partial_res={:?}", res);
*partial_res = Some(full_res(collector.cx.tcx, res));
*unresolved = end.into();
break 'outer;
if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
debug!("found partial_res={:?}", v_res);
if !v_res.is_empty() {
*partial_res = Some(full_res(collector.cx.tcx, v_res[0]));
*unresolved = end.into();
break 'outer;
}
}
}
*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<'_>) {
@ -1859,28 +1939,47 @@ fn report_malformed_generics(
}
/// 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(
cx: &DocContext<'_>,
diag_info: DiagnosticInfo<'_>,
diag_info: &DiagnosticInfo<'_>,
path_str: &str,
candidates: Vec<Res>,
) {
let mut msg = format!("`{}` is ", path_str);
candidates: &[(Res, Option<DefId>)],
) -> bool {
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() {
[first_def, second_def] => {
let mut msg = format!("`{}` is ", path_str);
match kinds.as_slice() {
[res1, res2] => {
msg += &format!(
"both {} {} and {} {}",
first_def.article(),
first_def.descr(),
second_def.article(),
second_def.descr(),
res1.article(),
res1.descr(),
res2.article(),
res2.descr()
);
}
_ => {
let mut candidates = candidates.iter().peekable();
while let Some(res) = candidates.next() {
if candidates.peek().is_some() {
let mut kinds = kinds.iter().peekable();
while let Some(res) = kinds.next() {
if kinds.peek().is_some() {
msg += &format!("{} {}, ", res.article(), res.descr());
} else {
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 {
diag.span_label(sp, "ambiguous link");
} else {
diag.note("ambiguous link");
}
for res in candidates {
for res in kinds {
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
}
});
true
}
/// 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(rustdoc_internals)]
#![feature(rustc_attrs)]
#![no_core]
// @set Local = "$.index[*][?(@.name=='Local')].id"
@ -16,6 +16,6 @@ impl Local for bool {}
// FIXME(#101695): Test bool's `impls` include "Local for bool"
// @has "$.index[*][?(@.name=='bool')]"
#[doc(primitive = "bool")]
#[rustc_doc_primitive = "bool"]
/// Boolean docs
mod prim_bool {}

View file

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

View file

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

View file

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

View file

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

View file

@ -2,12 +2,13 @@
// check-pass
#![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
//! properly as well
/// woo, check it out, we can write our own primitive docs lol
#[doc(primitive="unit")]
#[rustc_doc_primitive = "unit"]
mod prim_unit {}
/// keywords? sure, pile them on

View file

@ -35,6 +35,6 @@ pub mod foo {
/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
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]
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
|
LL | /// [true]
@ -13,89 +13,89 @@ help: to link to the module, prefix with `mod@`
|
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]
| +++++
error: `ambiguous` is both a struct and a function
error: `ambiguous` is both a function and a struct
--> $DIR/ambiguity.rs:27:7
|
LL | /// [`ambiguous`] is ambiguous.
| ^^^^^^^^^ ambiguous link
|
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@ambiguous`] is ambiguous.
| +++++++
help: to link to the function, add parentheses
|
LL | /// [`ambiguous()`] is ambiguous.
| ++
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
|
LL | /// [ambiguous] is ambiguous.
| ^^^^^^^^^ ambiguous link
|
help: to link to the struct, prefix with `struct@`
|
LL | /// [struct@ambiguous] is ambiguous.
| +++++++
help: to link to the function, add parentheses
|
LL | /// [ambiguous()] is ambiguous.
| ++
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
|
LL | /// [`multi_conflict`] is a three-way conflict.
| ^^^^^^^^^^^^^^ ambiguous link
|
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@multi_conflict`] is a three-way conflict.
| +++++++
help: to link to the function, add parentheses
|
LL | /// [`multi_conflict()`] is a three-way conflict.
| ++
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@multi_conflict`] is a three-way conflict.
| +++++++
help: to link to the macro, add an exclamation mark
|
LL | /// [`multi_conflict!`] is a three-way conflict.
| +
error: `type_and_value` is both a module and a constant
error: `type_and_value` is both a constant and a module
--> $DIR/ambiguity.rs:33:16
|
LL | /// Ambiguous [type_and_value].
| ^^^^^^^^^^^^^^ ambiguous link
|
help: to link to the module, prefix with `mod@`
|
LL | /// Ambiguous [mod@type_and_value].
| ++++
help: to link to the constant, prefix with `const@`
|
LL | /// Ambiguous [const@type_and_value].
| ++++++
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
|
LL | /// Ambiguous non-implied shortcut link [`foo::bar`].
| ^^^^^^^^ ambiguous link
|
help: to link to the enum, prefix with `enum@`
|
LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`].
| +++++
help: to link to the function, add parentheses
|
LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
| ++
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

View file

@ -54,11 +54,11 @@
/// [u8::not_found]
//~^ 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]
//~^ 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]
//~^ ERROR unresolved link

View file

@ -80,13 +80,13 @@ error: unresolved link to `u8::not_found`
--> $DIR/errors.rs:55:6
|
LL | /// [u8::not_found]
| ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
| ^^^^^^^^^^^^^ the primitive type `u8` has no associated item named `not_found`
error: unresolved link to `std::primitive::u8::not_found`
--> $DIR/errors.rs:59:6
|
LL | /// [std::primitive::u8::not_found]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the primitive type `u8` has no associated item named `not_found`
error: unresolved link to `Vec::into_iter`
--> $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
|
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`
--> $DIR/non-path-primitives.rs:29:6
|
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`
--> $DIR/non-path-primitives.rs:30:6
|
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`
--> $DIR/non-path-primitives.rs:34:6
|
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

View file

@ -2,16 +2,16 @@
//~^ NOTE lint level is defined
/// [char]
//~^ ERROR both a module and a builtin type
//~^ ERROR both a module and a primitive type
//~| NOTE ambiguous link
//~| HELP to link to the module
//~| HELP to link to the builtin type
//~| HELP to link to the primitive type
/// [type@char]
//~^ ERROR both a module and a builtin type
//~^ ERROR both a module and a primitive type
//~| NOTE ambiguous link
//~| HELP to link to the module
//~| HELP to link to the builtin type
//~| HELP to link to the primitive type
/// [mod@char] // ok
/// [prim@char] // ok
@ -26,5 +26,5 @@ pub mod inner {
//! [struct@char]
//~^ ERROR incompatible link
//~| 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
|
LL | /// [char]
@ -13,12 +13,12 @@ help: to link to the module, prefix with `mod@`
|
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]
| +++++
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
|
LL | /// [type@char]
@ -28,7 +28,7 @@ help: to link to the module, prefix with `mod@`
|
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]
| ~~~~~
@ -48,9 +48,9 @@ error: incompatible link kind for `char`
--> $DIR/prim-conflict.rs:26:10
|
LL | //! [struct@char]
| ^^^^^^^^^^^ this link resolved to a builtin type, which is not a struct
| ^^^^^^^^^^^ 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]
| ~~~~~

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@
#![rustc_coherence_is_core]
#![crate_type="rlib"]
#[doc(primitive = "char")]
#[rustc_doc_primitive = "char"]
/// Some char docs
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)]
#![feature(no_core, lang_items, rustc_attrs)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,8 @@
#![feature(rustdoc_internals)]
#![feature(rustc_attrs)]
#![crate_name = "foo"]
// @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!
mod i32 {}

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
#![crate_name = "foo"]
#![feature(rustdoc_internals)]
#![feature(rustc_attrs)]
// @matches 'foo/index.html' '//h1' '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'
#[doc(primitive = "bool")]
#[rustc_doc_primitive = "bool"]
mod bool {}
// @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)]
#![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
|
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
|
LL | fluent_messages! { "../definitely_does_not_exist.ftl" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: os-specific message
error: could not parse Fluent resource
--> $DIR/test.rs:38:24
@ -89,7 +85,7 @@ error: invalid escape `\n` in Fluent resource
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
--> $DIR/test.rs:99:24
@ -97,7 +93,7 @@ error: invalid escape `\"` in Fluent resource
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
--> $DIR/test.rs:99:24
@ -105,7 +101,7 @@ error: invalid escape `\'` in Fluent resource
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

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
#[doc(primitive = "usize")]
//~^ WARNING `doc(primitive)` should never have been stable
//~| WARNING hard error in a future release
#[rustc_doc_primitive = "usize"]
//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
/// Some docs
mod usize {}

View file

@ -1,12 +1,11 @@
warning: `doc(primitive)` should never have been stable
--> $DIR/feature-gate-doc_primitive.rs:2:7
error[E0658]: `rustc_doc_primitive` is a rustc internal attribute
--> $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!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
warning: 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.