diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index fef6602b9ccbb..c669f7fed272a 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -464,6 +464,7 @@ E0776: include_str!("./error_codes/E0776.md"), E0777: include_str!("./error_codes/E0777.md"), E0778: include_str!("./error_codes/E0778.md"), E0779: include_str!("./error_codes/E0779.md"), +E0780: include_str!("./error_codes/E0780.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0780.md b/compiler/rustc_error_codes/src/error_codes/E0780.md new file mode 100644 index 0000000000000..704b4ae181bb2 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0780.md @@ -0,0 +1,19 @@ +Cannot use `doc(inline)` with anonymous imports + +Erroneous code example: + +```ignore (cannot-doctest-multicrate-project) + +#[doc(inline)] // error: invalid doc argument +pub use foo::Foo as _; +``` + +Anonymous imports are always rendered with `#[doc(no_inline)]`. To fix this +error, remove the `#[doc(inline)]` attribute. + +Example: + +```ignore (cannot-doctest-multicrate-project) + +pub use foo::Foo as _; +``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cc5f68bc29773..9a15a4bb91747 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2157,11 +2157,26 @@ impl Clean> for doctree::Import<'_> { return Vec::new(); } + let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline); + let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore; + + if pub_underscore && please_inline { + rustc_errors::struct_span_err!( + cx.tcx.sess, + doc_meta_item.unwrap().span(), + E0780, + "anonymous imports cannot be inlined" + ) + .span_label(self.span, "anonymous import") + .emit(); + } + // We consider inlining the documentation of `pub use` statements, but we // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let mut denied = !self.vis.node.is_pub() + || pub_underscore || self.attrs.iter().any(|a| { a.has_name(sym::doc) && match a.meta_item_list() { @@ -2174,7 +2189,6 @@ impl Clean> for doctree::Import<'_> { }); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ - let please_inline = self.attrs.lists(sym::doc).has_word(sym::inline); let path = self.path.clean(cx); let inner = if self.glob { if !denied { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cd6eccea53218..d8dfdd0941be8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -431,12 +431,22 @@ impl AttributesExt for [ast::Attribute] { crate trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `Word` fn has_word(self, word: Symbol) -> bool; + fn get_word_attr(self, word: Symbol) -> (Option, bool); } -impl> NestedAttributesExt for I { +impl + IntoIterator> + NestedAttributesExt for I +{ fn has_word(self, word: Symbol) -> bool { self.into_iter().any(|attr| attr.is_word() && attr.has_name(word)) } + + fn get_word_attr(mut self, word: Symbol) -> (Option, bool) { + match self.find(|attr| attr.is_word() && attr.has_name(word)) { + Some(a) => (Some(a), true), + None => (None, false), + } + } } /// A portion of documentation, extracted from a `#[doc]` attribute. diff --git a/src/test/rustdoc-ui/auxiliary/issue-61592.rs b/src/test/rustdoc-ui/auxiliary/issue-61592.rs new file mode 100644 index 0000000000000..57a365b3f386a --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/issue-61592.rs @@ -0,0 +1,3 @@ +#![crate_name = "foo"] + +pub trait Foo {} diff --git a/src/test/rustdoc-ui/issue-61592-2.rs b/src/test/rustdoc-ui/issue-61592-2.rs new file mode 100644 index 0000000000000..5b4fc5ee70063 --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592-2.rs @@ -0,0 +1,10 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +#[doc = "bar"] +#[doc(inline)] //~ ERROR +#[doc = "baz"] +pub use foo::Foo as _; + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-61592-2.stderr b/src/test/rustdoc-ui/issue-61592-2.stderr new file mode 100644 index 0000000000000..1b7f8bb552c0c --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592-2.stderr @@ -0,0 +1,12 @@ +error[E0780]: anonymous imports cannot be inlined + --> $DIR/issue-61592-2.rs:6:7 + | +LL | #[doc(inline)] + | ^^^^^^ +LL | #[doc = "baz"] +LL | pub use foo::Foo as _; + | ---------------------- anonymous import + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0780`. diff --git a/src/test/rustdoc-ui/issue-61592.rs b/src/test/rustdoc-ui/issue-61592.rs new file mode 100644 index 0000000000000..66772557f2c2f --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592.rs @@ -0,0 +1,8 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +#[doc(inline)] //~ ERROR +pub use foo::Foo as _; + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-61592.stderr b/src/test/rustdoc-ui/issue-61592.stderr new file mode 100644 index 0000000000000..9c9c9106f8ac3 --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592.stderr @@ -0,0 +1,11 @@ +error[E0780]: anonymous imports cannot be inlined + --> $DIR/issue-61592.rs:5:7 + | +LL | #[doc(inline)] + | ^^^^^^ +LL | pub use foo::Foo as _; + | ---------------------- anonymous import + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0780`. diff --git a/src/test/rustdoc/auxiliary/issue-61592.rs b/src/test/rustdoc/auxiliary/issue-61592.rs new file mode 100644 index 0000000000000..6e16a4caf5948 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-61592.rs @@ -0,0 +1,4 @@ +#![crate_name = "foo"] + +pub trait FooTrait {} +pub struct FooStruct; diff --git a/src/test/rustdoc/issue-61592.rs b/src/test/rustdoc/issue-61592.rs new file mode 100644 index 0000000000000..aef038c07d891 --- /dev/null +++ b/src/test/rustdoc/issue-61592.rs @@ -0,0 +1,15 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +// @has issue_61592/index.html +// @has - '//a[@href="#reexports"]' 'Re-exports' +// @has - '//code' 'pub use foo::FooTrait as _;' +// @!has - '//a[@href="trait._.html"]' +pub use foo::FooTrait as _; + +// @has issue_61592/index.html +// @has - '//a[@href="#reexports"]' 'Re-exports' +// @has - '//code' 'pub use foo::FooStruct as _;' +// @!has - '//a[@href="struct._.html"]' +pub use foo::FooStruct as _;