diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d7d7b6bd157..05690e19d23 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -268,8 +268,8 @@ use crate::vec::Vec; /// /// Here, there's no need to allocate more memory inside the loop. /// -/// [`str`]: type@str -/// [`&str`]: type@str +/// [`str`]: prim@str +/// [`&str`]: prim@str /// [`Deref`]: core::ops::Deref /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] @@ -296,7 +296,7 @@ pub struct String { /// /// [`Utf8Error`]: core::str::Utf8Error /// [`std::str`]: core::str -/// [`&str`]: str +/// [`&str`]: prim@str /// [`utf8_error`]: Self::utf8_error /// /// # Examples @@ -472,7 +472,7 @@ impl String { /// /// [`from_utf8_unchecked`]: String::from_utf8_unchecked /// [`Vec`]: crate::vec::Vec - /// [`&str`]: str + /// [`&str`]: prim@str /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1576,6 +1576,8 @@ impl String { /// /// This will drop any excess capacity. /// + /// [`str`]: prim@str + /// /// # Examples /// /// Basic usage: @@ -1644,7 +1646,7 @@ impl FromUtf8Error { /// on using it. /// /// [`std::str`]: core::str - /// [`&str`]: str + /// [`&str`]: prim@str /// /// # Examples /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 7c1027f60ba..ab9afeb25e0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -476,6 +476,7 @@ Section: Iterators /// This struct is created by the [`chars`] method on [`str`]. /// See its documentation for more. /// +/// [`char`]: prim@char /// [`chars`]: str::chars #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] @@ -673,6 +674,7 @@ impl<'a> Chars<'a> { /// This struct is created by the [`char_indices`] method on [`str`]. /// See its documentation for more. /// +/// [`char`]: prim@char /// [`char_indices`]: str::char_indices #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -2270,6 +2272,8 @@ impl str { /// This length is in bytes, not [`char`]s or graphemes. In other words, /// it may not be what a human considers the length of the string. /// + /// [`char`]: prim@char + /// /// # Examples /// /// Basic usage: @@ -2791,7 +2795,9 @@ impl str { /// assert_eq!(None, chars.next()); /// ``` /// - /// Remember, [`char`]s may not match your human intuition about characters: + /// Remember, [`char`]s may not match your intuition about characters: + /// + /// [`char`]: prim@char /// /// ``` /// let y = "y̆"; @@ -2842,7 +2848,9 @@ impl str { /// assert_eq!(None, char_indices.next()); /// ``` /// - /// Remember, [`char`]s may not match your human intuition about characters: + /// Remember, [`char`]s may not match your intuition about characters: + /// + /// [`char`]: prim@char /// /// ``` /// let yes = "y̆es"; @@ -3053,6 +3061,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3079,6 +3088,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3104,6 +3114,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3132,6 +3143,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3179,6 +3191,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3225,6 +3238,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3344,6 +3358,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -3383,6 +3398,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3434,6 +3450,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// Equivalent to [`split`], except that the trailing substring @@ -3478,6 +3495,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// Equivalent to [`split`], except that the trailing substring is @@ -3526,6 +3544,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3578,6 +3597,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3666,6 +3686,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3702,6 +3723,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3743,6 +3765,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -3785,6 +3808,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Iterator behavior @@ -4003,6 +4027,7 @@ impl str { /// The [pattern] can be a [`char`], a slice of [`char`]s, or a function /// or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4050,6 +4075,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4094,6 +4120,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4121,6 +4148,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Examples @@ -4147,6 +4175,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4195,6 +4224,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality @@ -4231,6 +4261,7 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// [`char`]: prim@char /// [pattern]: self::pattern /// /// # Text directionality diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 1b7681bd4bb..84e686c2fef 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -296,6 +296,8 @@ impl From for Box { impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`str`]: prim@str + /// /// # Examples /// /// ``` @@ -317,6 +319,8 @@ impl<'a> From<&str> for Box { impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// + /// [`str`]: prim@str + /// /// # Examples /// /// ``` diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 11b3f22503e..717967fb768 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -69,7 +69,7 @@ use crate::sys; /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// -/// [`&str`]: str +/// [`&str`]: prim@str /// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr /// [slice.len]: ../primitive.slice.html#method.len /// [`Deref`]: ops::Deref @@ -180,7 +180,7 @@ pub struct CString { /// println!("string: {}", my_string_safe()); /// ``` /// -/// [`&str`]: str +/// [`&str`]: prim@str #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: @@ -1351,7 +1351,7 @@ impl CStr { /// function will return the corresponding [`&str`] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// - /// [`&str`]: str + /// [`&str`]: prim@str /// /// # Examples /// @@ -1379,6 +1379,7 @@ impl CStr { /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// + /// [`str`]: prim@str /// [`Borrowed`]: Cow::Borrowed /// [`Owned`]: Cow::Owned /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 32456294838..462b696db40 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -480,7 +480,7 @@ where /// ``` /// /// [`read()`]: Read::read -/// [`&str`]: str +/// [`&str`]: prim@str /// [`std::io`]: self /// [`File`]: crate::fs::File /// [slice]: ../../std/primitive.slice.html diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 00f37d90c6a..1142b74ff0d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -172,6 +172,7 @@ //! [`Vec`]: vec::Vec //! [`atomic`]: sync::atomic //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for +//! [`str`]: prim@str //! [`mpsc`]: sync::mpsc //! [`std::cmp`]: cmp //! [`std::slice`]: slice diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index f45e2295064..2f49fc8a415 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -81,7 +81,7 @@ impl AsyncReceiver { } ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@` , `macro@`, or `derive@`: +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: ```rust /// See also: [`Foo`](struct@Foo) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 2ed3d07974f..bf091a0a624 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -181,7 +181,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn resolve( &self, path_str: &str, - disambiguator: Option, ns: Namespace, current_item: &Option, parent_id: Option, @@ -218,18 +217,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return Ok((res, Some(path_str.to_owned()))); } Res::Def(DefKind::Mod, _) => { - // This resolved to a module, but we want primitive types to take precedence instead. - if matches!( - disambiguator, - None | Some(Disambiguator::Namespace(Namespace::TypeNS)) - ) { - if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); - } - return Ok((prim, Some(path.to_owned()))); - } - } return Ok((res, extra_fragment.clone())); } _ => { @@ -713,7 +700,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let resolved_self; let mut path_str; let disambiguator; - let (res, fragment) = { + let (mut res, mut fragment) = { path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { disambiguator = Some(d); path @@ -754,14 +741,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { match disambiguator.map(Disambiguator::ns) { Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve( - path_str, - disambiguator, - ns, - ¤t_item, - base_node, - &extra_fragment, - ) { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -784,7 +765,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { .map(|res| (res, extra_fragment.clone())), type_ns: match self.resolve( path_str, - disambiguator, TypeNS, ¤t_item, base_node, @@ -802,7 +782,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }, value_ns: match self.resolve( path_str, - disambiguator, ValueNS, ¤t_item, base_node, @@ -848,13 +827,18 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if is_derive_trait_collision(&candidates) { candidates.macro_ns = None; } + let candidates = + candidates.map(|candidate| candidate.map(|(res, _)| res)); + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))); ambiguity_error( cx, &item, path_str, &dox, link_range, - candidates.map(|candidate| candidate.map(|(res, _)| res)), + candidates.collect(), ); continue; } @@ -870,13 +854,81 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } }; + // Check for a primitive which might conflict with a module + // Report the ambiguity and require that the user specify which one they meant. + // FIXME: could there ever be a primitive not in the type namespace? + if matches!( + disambiguator, + None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) + ) && !matches!(res, Res::PrimTy(_)) + { + if let Some((path, prim)) = is_primitive(path_str, TypeNS) { + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + if fragment.is_some() { + anchor_failure( + cx, + &item, + path_str, + &dox, + link_range, + AnchorFailure::Primitive, + ); + continue; + } + res = prim; + fragment = Some(path.to_owned()); + } else { + // `[char]` when a `char` module is in scope + let candidates = vec![(res, TypeNS), (prim, TypeNS)]; + ambiguity_error(cx, &item, path_str, &dox, link_range, candidates); + continue; + } + } + } + + let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr() + ); + let suggestion = resolved.display_for(path_str); + let help_msg = + format!("to link to the {}, use its disambiguator", resolved.descr()); + diag.note(¬e); + if let Some(sp) = sp { + diag.span_suggestion( + sp, + &help_msg, + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + diag.help(&format!("{}: {}", help_msg, suggestion)); + } + }); + }; if let Res::PrimTy(_) = res { - item.attrs.links.push((ori_link, None, fragment)); + match disambiguator { + Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { + item.attrs.links.push((ori_link, None, fragment)) + } + Some(other) => { + report_mismatch(other, Disambiguator::Primitive); + continue; + } + } } else { debug!("intra-doc link to {} resolved to {:?}", path_str, res); // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, id) = res { + if let Res::Def(kind, _) = res { debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) @@ -890,22 +942,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // All of these are valid, so do nothing => {} (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(Disambiguator::Kind(expected))) => { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| { - // HACK(jynelson): by looking at the source I saw the DefId we pass - // for `expected.descr()` doesn't matter, since it's not a crate - let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id)); - let suggestion = Disambiguator::display_for(kind, path_str); - let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id)); - diag.note(¬e); - if let Some(sp) = sp { - diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect); - } else { - diag.help(&format!("{}: {}", help_msg, suggestion)); - } - }); + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + report_mismatch(specified, Disambiguator::Kind(kind)); continue; } } @@ -961,6 +999,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Disambiguator { + Primitive, Kind(DefKind), Namespace(Namespace), } @@ -968,7 +1007,7 @@ enum Disambiguator { impl Disambiguator { /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { - use Disambiguator::{Kind, Namespace as NS}; + use Disambiguator::{Kind, Namespace as NS, Primitive}; let find_suffix = || { let suffixes = [ @@ -999,6 +1038,7 @@ impl Disambiguator { "type" => NS(Namespace::TypeNS), "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), + "prim" | "primitive" => Primitive, _ => return find_suffix(), }; Ok((d, &rest[1..])) @@ -1007,7 +1047,12 @@ impl Disambiguator { } } - fn display_for(kind: DefKind, path_str: &str) -> String { + fn display_for(self, path_str: &str) -> String { + let kind = match self { + Disambiguator::Primitive => return format!("prim@{}", path_str), + Disambiguator::Kind(kind) => kind, + Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), + }; if kind == DefKind::Macro(MacroKind::Bang) { return format!("{}!", path_str); } else if kind == DefKind::Fn || kind == DefKind::AssocFn { @@ -1043,6 +1088,25 @@ impl Disambiguator { Self::Kind(k) => { k.ns().expect("only DefKinds with a valid namespace can be disambiguators") } + Self::Primitive => TypeNS, + } + } + + fn article(self) -> &'static str { + match self { + Self::Namespace(_) => panic!("article() doesn't make sense for namespaces"), + Self::Kind(k) => k.article(), + Self::Primitive => "a", + } + } + + fn descr(self) -> &'static str { + match self { + Self::Namespace(n) => n.descr(), + // HACK(jynelson): by looking at the source I saw the DefId we pass + // for `expected.descr()` doesn't matter, since it's not a crate + Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))), + Self::Primitive => "builtin type", } } } @@ -1183,14 +1247,10 @@ fn ambiguity_error( path_str: &str, dox: &str, link_range: Option>, - candidates: PerNS>, + candidates: Vec<(Res, Namespace)>, ) { let mut msg = format!("`{}` is ", path_str); - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) - .collect::>(); match candidates.as_slice() { [(first_def, _), (second_def, _)] => { msg += &format!( @@ -1229,6 +1289,7 @@ fn ambiguity_error( } _ => { let type_ = match (res, ns) { + (Res::PrimTy(_), _) => "prim", (Res::Def(DefKind::Const, _), _) => "const", (Res::Def(DefKind::Static, _), _) => "static", (Res::Def(DefKind::Struct, _), _) => "struct", diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs new file mode 100644 index 00000000000..34276fbcf20 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -0,0 +1,30 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +/// [char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [type@char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [mod@char] // ok +/// [prim@char] // ok + +/// [struct@char] +//~^ ERROR incompatible link +//~| HELP use its disambiguator +//~| NOTE resolved to a module +pub mod char {} + +pub mod inner { + //! [struct@char] + //~^ ERROR incompatible link + //~| HELP use its disambiguator + //~| NOTE resolved to a builtin type +} diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr new file mode 100644 index 00000000000..b28a4426666 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -0,0 +1,53 @@ +error: `char` is both a module and a builtin type + --> $DIR/intra-link-prim-conflict.rs:4:6 + | +LL | /// [char] + | ^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/intra-link-prim-conflict.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the module, prefix with the item type + | +LL | /// [module@char] + | ^^^^^^^^^^^ +help: to link to the builtin type, prefix with the item type + | +LL | /// [prim@char] + | ^^^^^^^^^ + +error: `char` is both a module and a builtin type + --> $DIR/intra-link-prim-conflict.rs:10:6 + | +LL | /// [type@char] + | ^^^^^^^^^ ambiguous link + | +help: to link to the module, prefix with the item type + | +LL | /// [module@char] + | ^^^^^^^^^^^ +help: to link to the builtin type, prefix with the item type + | +LL | /// [prim@char] + | ^^^^^^^^^ + +error: incompatible link kind for `char` + --> $DIR/intra-link-prim-conflict.rs:19:6 + | +LL | /// [struct@char] + | ^^^^^^^^^^^ help: to link to the module, use its disambiguator: `mod@char` + | + = note: this link resolved to a module, which is not a struct + +error: incompatible link kind for `char` + --> $DIR/intra-link-prim-conflict.rs:26:10 + | +LL | //! [struct@char] + | ^^^^^^^^^^^ help: to link to the builtin type, use its disambiguator: `prim@char` + | + = note: this link resolved to a builtin type, which is not a struct + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc/intra-link-prim-precedence.rs b/src/test/rustdoc/intra-link-prim-precedence.rs index 15ea1232fd6..0a4e57ef643 100644 --- a/src/test/rustdoc/intra-link-prim-precedence.rs +++ b/src/test/rustdoc/intra-link-prim-precedence.rs @@ -1,17 +1,17 @@ // ignore-tidy-linelength #![deny(broken_intra_doc_links)] -pub mod char {} +pub mod char { + /// [char] + // @has intra_link_prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' + pub struct Inner; +} -/// See also [type@char] +/// See [prim@char] // @has intra_link_prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' pub struct MyString; -/// See also [char] -// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' -pub struct MyString2; - /// See also [crate::char] and [mod@char] -// @has intra_link_prim_precedence/struct.MyString3.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char' +// @has intra_link_prim_precedence/struct.MyString2.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char' // @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char' -pub struct MyString3; +pub struct MyString2;