From 315d12d73d511efb277426c813e5d40157a0d70a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 5 Aug 2022 23:51:33 +0000 Subject: [PATCH 1/9] Fix ReErased leaking into typeck due to typeof recovery --- compiler/rustc_typeck/src/astconv/mod.rs | 5 ++++- src/test/ui/typeof/issue-100183.rs | 6 ++++++ src/test/ui/typeof/issue-100183.stderr | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/typeof/issue-100183.rs create mode 100644 src/test/ui/typeof/issue-100183.stderr diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8a5c7fee697d1..c094594648cbf 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2667,7 +2667,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { - let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty_erased = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty = tcx.fold_regions(ty_erased, |r, _| { + if r.is_erased() { tcx.lifetimes.re_static } else { r } + }); let span = ast_ty.span; tcx.sess.emit_err(TypeofReservedKeywordUsed { span, diff --git a/src/test/ui/typeof/issue-100183.rs b/src/test/ui/typeof/issue-100183.rs new file mode 100644 index 0000000000000..13e9493eaa59b --- /dev/null +++ b/src/test/ui/typeof/issue-100183.rs @@ -0,0 +1,6 @@ +struct Struct { + y: (typeof("hey"),), + //~^ ERROR `typeof` is a reserved keyword but unimplemented +} + +fn main() {} diff --git a/src/test/ui/typeof/issue-100183.stderr b/src/test/ui/typeof/issue-100183.stderr new file mode 100644 index 0000000000000..01d3079b246d1 --- /dev/null +++ b/src/test/ui/typeof/issue-100183.stderr @@ -0,0 +1,14 @@ +error[E0516]: `typeof` is a reserved keyword but unimplemented + --> $DIR/issue-100183.rs:2:9 + | +LL | y: (typeof("hey"),), + | ^^^^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | y: (&'static str,), + | ~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0516`. From 2126622887e5447610e5d14803e52aa51bc9dd44 Mon Sep 17 00:00:00 2001 From: winxpqq955 Date: Sun, 11 Sep 2022 15:09:39 +0800 Subject: [PATCH 2/9] Add test for #101211 --- .../proc-macro/dollar-crate-issue-101211.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/test/ui/proc-macro/dollar-crate-issue-101211.rs diff --git a/src/test/ui/proc-macro/dollar-crate-issue-101211.rs b/src/test/ui/proc-macro/dollar-crate-issue-101211.rs new file mode 100644 index 0000000000000..fc1acfd32d2fc --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate-issue-101211.rs @@ -0,0 +1,29 @@ +// check-pass +// edition:2021 +// aux-build:test-macros.rs + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + +macro_rules! foo { + ($($path:ident)::*) => ( + test_macros::recollect!( + $($path)::* + ) + ) +} + +macro_rules! baz { + () => ( + foo!($crate::BAR) + ) +} + +pub const BAR: u32 = 19; + +fn main(){ + std::println!("{}", baz!()); +} From cb02b647dc0441cfe152fa037ee14f4606c477cb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 9 Aug 2022 03:20:15 +0400 Subject: [PATCH 3/9] constify `CStr` methods --- library/core/src/ffi/c_str.rs | 19 ++++++++++++------- library/core/src/lib.rs | 1 + library/core/src/slice/memchr.rs | 29 ++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 82e63a7fe1ddb..ec3cce2a234c4 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -121,10 +121,10 @@ enum FromBytesWithNulErrorKind { } impl FromBytesWithNulError { - fn interior_nul(pos: usize) -> FromBytesWithNulError { + const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - fn not_nul_terminated() -> FromBytesWithNulError { + const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -299,7 +299,8 @@ impl CStr { /// ``` /// #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] - pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { + #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] + pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) => { @@ -348,7 +349,8 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) if nul_pos + 1 == bytes.len() => { @@ -497,7 +499,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); // SAFETY: to_bytes_with_nul returns slice with length at least 1 unsafe { bytes.get_unchecked(..bytes.len() - 1) } @@ -524,7 +527,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes_with_nul(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } @@ -547,7 +551,8 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49b9a5..87ffc5abd2ee6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -157,6 +157,7 @@ #![feature(const_slice_from_ref)] #![feature(const_slice_index)] #![feature(const_is_char_boundary)] +#![feature(const_cstr_methods)] // // Language features: #![feature(abi_unadjusted)] diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index dffeaf6a834e7..e0419f0ffdbac 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -2,6 +2,7 @@ // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch use crate::cmp; +use crate::intrinsics; use crate::mem; const LO_USIZE: usize = usize::repeat_u8(0x01); @@ -35,13 +36,31 @@ fn repeat_byte(b: u8) -> usize { /// Returns the first index matching the byte `x` in `text`. #[must_use] #[inline] -pub fn memchr(x: u8, text: &[u8]) -> Option { - // Fast path for small slices - if text.len() < 2 * USIZE_BYTES { - return text.iter().position(|elt| *elt == x); +pub const fn memchr(x: u8, text: &[u8]) -> Option { + #[inline] + fn rt_impl(x: u8, text: &[u8]) -> Option { + // Fast path for small slices + if text.len() < 2 * USIZE_BYTES { + return text.iter().position(|elt| *elt == x); + } + + memchr_general_case(x, text) + } + + const fn const_impl(x: u8, bytes: &[u8]) -> Option { + let mut i = 0; + while i < bytes.len() { + if bytes[i] == x { + return Some(i); + } + i += 1; + } + + None } - memchr_general_case(x, text) + // SAFETY: The const and runtime versions have identical behavior + unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) } } fn memchr_general_case(x: u8, text: &[u8]) -> Option { From 2b7fb8d9418dbf98e6ee8ed406f830b4fcbea55f Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 12 Sep 2022 16:54:25 +0200 Subject: [PATCH 4/9] Impove diagnostic for .await-ing non-futures --- compiler/rustc_ast_lowering/src/expr.rs | 12 +++++++++--- .../src/traits/error_reporting/suggestions.rs | 4 ++-- src/test/ui/async-await/issue-101715.rs | 17 +++++++++++++++++ src/test/ui/async-await/issue-101715.stderr | 16 ++++++++++++++++ src/test/ui/async-await/issue-70594.stderr | 10 ++++------ .../ui/async-await/issues/issue-62009-1.stderr | 10 ++++------ 6 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/async-await/issue-101715.rs create mode 100644 src/test/ui/async-await/issue-101715.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f929549d70448..cd03e3fb4572d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -146,13 +146,19 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), ExprKind::Await(ref expr) => { - let span = if expr.span.hi() < e.span.hi() { - expr.span.shrink_to_hi().with_hi(e.span.hi()) + let dot_await_span = if expr.span.hi() < e.span.hi() { + let span_with_whitespace = self + .tcx + .sess + .source_map() + .span_extend_while(expr.span, char::is_whitespace) + .unwrap_or(expr.span); + span_with_whitespace.shrink_to_hi().with_hi(e.span.hi()) } else { // this is a recovered `await expr` e.span }; - self.lower_expr_await(span, expr) + self.lower_expr_await(dot_await_span, expr) } ExprKind::Closure( ref binder, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ecbeb9d79b118..cb605cacc9c98 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1160,8 +1160,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // and if not maybe suggest doing something else? If we kept the expression around we // could also check if it is an fn call (very likely) and suggest changing *that*, if // it is from the local crate. - err.span_suggestion_verbose( - expr.span.shrink_to_hi().with_hi(span.hi()), + err.span_suggestion( + span, "remove the `.await`", "", Applicability::MachineApplicable, diff --git a/src/test/ui/async-await/issue-101715.rs b/src/test/ui/async-await/issue-101715.rs new file mode 100644 index 0000000000000..1be5d02482e84 --- /dev/null +++ b/src/test/ui/async-await/issue-101715.rs @@ -0,0 +1,17 @@ +// edition:2018 + +struct S; + +impl S { + fn very_long_method_name_the_longest_method_name_in_the_whole_universe(self) {} +} + +async fn foo() { + S.very_long_method_name_the_longest_method_name_in_the_whole_universe() + .await + //~^ error: `()` is not a future + //~| help: remove the `.await` + //~| help: the trait `Future` is not implemented for `()` +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-101715.stderr b/src/test/ui/async-await/issue-101715.stderr new file mode 100644 index 0000000000000..a0e8d2a894371 --- /dev/null +++ b/src/test/ui/async-await/issue-101715.stderr @@ -0,0 +1,16 @@ +error[E0277]: `()` is not a future + --> $DIR/issue-101715.rs:11:9 + | +LL | .await + | ^^^^^^ + | | + | `()` is not a future + | help: remove the `.await` + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required for `()` to implement `IntoFuture` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index f6ff52a5fd29f..d3cf57d3b1402 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -22,16 +22,14 @@ error[E0277]: `()` is not a future --> $DIR/issue-70594.rs:4:11 | LL | [1; ().await]; - | ^^^^^^ `()` is not a future + | ^^^^^^ + | | + | `()` is not a future + | help: remove the `.await` | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` -help: remove the `.await` - | -LL - [1; ().await]; -LL + [1; ()]; - | error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index 0e323443ae8b3..222afb2c7b2bb 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -28,16 +28,14 @@ error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future --> $DIR/issue-62009-1.rs:12:15 | LL | (|_| 2333).await; - | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future + | ^^^^^^ + | | + | `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future + | help: remove the `.await` | = help: the trait `Future` is not implemented for closure `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` = note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited = note: required for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` to implement `IntoFuture` -help: remove the `.await` - | -LL - (|_| 2333).await; -LL + (|_| 2333); - | error: aborting due to 4 previous errors From 91398912d083c0531c37c65de6452fabafe587da Mon Sep 17 00:00:00 2001 From: fee1-dead Date: Mon, 12 Sep 2022 23:04:32 +0800 Subject: [PATCH 5/9] Allow unauthenticated users to add the `const-hack` label --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index ceda7ef5f1658..4b2dcc246e4ee 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -11,6 +11,7 @@ allow-unauthenticated = [ "S-*", "T-*", "WG-*", + "const-hack", "needs-fcp", "relnotes", "requires-nightly", From fd1a399c4f3d0510b0c7528a298bc597d113856d Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Mon, 12 Sep 2022 20:08:58 +0200 Subject: [PATCH 6/9] Allow tool-lints to specify a feature-gate too --- compiler/rustc_lint/src/levels.rs | 6 ++++-- compiler/rustc_lint_defs/src/lib.rs | 10 +++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f1d8ef2e47d31..1e16ac51e9e5d 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -440,8 +440,10 @@ impl<'s> LintLevelsBuilder<'s> { sp, reason, ); - for id in ids { - self.insert_spec(*id, (level, src)); + for &id in ids { + if self.check_gated_lint(id, attr.span) { + self.insert_spec(id, (level, src)); + } } if let Level::Expect(expect_id) = level { self.lint_expectations.push(( diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 9c6530c8a0843..11b2d057a0769 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -658,18 +658,21 @@ macro_rules! declare_lint { macro_rules! declare_tool_lint { ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr + $(, @feature_gate = $gate:expr;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr + $(, @feature_gate = $gate:expr;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr + $(, @feature_gate = $gate:expr;)? ) => ( $(#[$attr])* $vis static $NAME: &$crate::Lint = &$crate::Lint { @@ -680,8 +683,9 @@ macro_rules! declare_tool_lint { report_in_external_macro: $external, future_incompatible: None, is_plugin: true, - feature_gate: None, + $(feature_gate: Some($gate),)? crate_level_only: false, + ..$crate::Lint::default_fields_for_macro() }; ); } From 84ca399465be4eced934733ef3dc0b48005ba6af Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 12 Sep 2022 11:11:37 -0700 Subject: [PATCH 7/9] rustdoc: improve rustdoc HTML suggestions handling of nested generics Based on some poor suggestions produced when stablizing this lint and running it on `manformed-generics.rs` --- src/librustdoc/passes/html_tags.rs | 83 ++++++++++++++++- .../html-as-generics-no-suggestions.rs | 42 +++++++++ .../html-as-generics-no-suggestions.stderr | 48 ++++++++-- .../suggestions/html-as-generics.fixed | 40 +++++++++ .../suggestions/html-as-generics.rs | 40 +++++++++ .../suggestions/html-as-generics.stderr | 90 ++++++++++++++++++- 6 files changed, 330 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index f3a3c853caca6..1bce24b0ad3e8 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -94,6 +94,34 @@ fn extract_path_backwards(text: &str, end_pos: usize) -> Option { if current_pos == end_pos { None } else { Some(current_pos) } } +fn extract_path_forward(text: &str, start_pos: usize) -> Option { + use rustc_lexer::{is_id_continue, is_id_start}; + let mut current_pos = start_pos; + loop { + if current_pos < text.len() && text[current_pos..].starts_with("::") { + current_pos += 2; + } else { + break; + } + let mut chars = text[current_pos..].chars(); + if let Some(c) = chars.next() { + if is_id_start(c) { + current_pos += c.len_utf8(); + } else { + break; + } + } + while let Some(c) = chars.next() { + if is_id_continue(c) { + current_pos += c.len_utf8(); + } else { + break; + } + } + } + if current_pos == start_pos { None } else { Some(current_pos) } +} + fn is_valid_for_html_tag_name(c: char, is_empty: bool) -> bool { // https://spec.commonmark.org/0.30/#raw-html // @@ -218,19 +246,68 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> { // If a tag looks like ``, it might actually be a generic. // We don't try to detect stuff `` because that's not valid HTML, // and we don't try to detect stuff `` because that's not valid Rust. - if let Some(Some(generics_start)) = (is_open_tag - && dox[..range.end].ends_with('>')) + let mut generics_end = range.end; + if let Some(Some(mut generics_start)) = (is_open_tag + && dox[..generics_end].ends_with('>')) .then(|| extract_path_backwards(&dox, range.start)) { + while generics_start != 0 + && generics_end < dox.len() + && dox.as_bytes()[generics_start - 1] == b'<' + && dox.as_bytes()[generics_end] == b'>' + { + generics_end += 1; + generics_start -= 1; + if let Some(new_start) = extract_path_backwards(&dox, generics_start) { + generics_start = new_start; + } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } + } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } let generics_sp = match super::source_span_for_markdown_range( tcx, &dox, - &(generics_start..range.end), + &(generics_start..generics_end), &item.attrs, ) { Some(sp) => sp, None => item.attr_span(tcx), }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter>::Item + // ^^^^^ unclosed HTML tag `u32` + // + // We don't have any code for parsing fully-qualified trait paths. + // In theory, we could add it, but doing it correctly would require + // parsing the entire path grammar, which is problematic because of + // overlap between the path grammar and Markdown. + // + // The example above shows that ambiguity. Is `[u32]` intended to be an + // intra-doc link to the u32 primitive, or is it intended to be a slice? + // + // If the below conditional were removed, we would suggest this, which is + // not what the user probably wants. + // + // <[u32] as `IntoIter`>::Item + // + // We know that the user actually wants to wrap the whole thing in a code + // block, but the only reason we know that is because `u32` does not, in + // fact, implement IntoIter. If the example looks like this: + // + // <[Vec] as IntoIter::Item + // + // The ideal fix would be significantly different. + if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') + || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') + { + diag.emit(); + return; + } // multipart form is chosen here because ``Vec`` would be confusing. diag.multipart_suggestion( "try marking as source code", diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs index 744b3071f1b81..476e3b2d43e4a 100644 --- a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs +++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs @@ -8,6 +8,48 @@ pub struct ConstGeneric; // HTML tags cannot contain commas, so no error. pub struct MultipleGenerics; +/// This <[u32] as Iterator> thing! +//~^ERROR unclosed HTML tag `Item` +// Some forms of fully-qualified path are simultaneously valid HTML tags +// with attributes. They produce an error, but no suggestion, because figuring +// out if this is valid would require parsing the entire path grammar. +// +// The important part is that we don't produce any *wrong* suggestions. +// While several other examples below are added to make sure we don't +// produce suggestions when given complex paths, this example is the actual +// reason behind not just using the real path parser. It's ambiguous: there's +// no way to locally reason out whether that `[u32]` is intended to be a slice +// or an intra-doc link. +pub struct FullyQualifiedPathsDoNotCount; + +/// This ::Iter thing! +//~^ERROR unclosed HTML tag `Vec` +// Some forms of fully-qualified path are simultaneously valid HTML tags +// with attributes. They produce an error, but no suggestion, because figuring +// out if this is valid would require parsing the entire path grammar. +pub struct FullyQualifiedPathsDoNotCount1; + +/// This Vec::Iter thing! +//~^ERROR unclosed HTML tag `Vec` +// Some forms of fully-qualified path are simultaneously valid HTML tags +// with attributes. They produce an error, but no suggestion, because figuring +// out if this is valid would require parsing the entire path grammar. +pub struct FullyQualifiedPathsDoNotCount2; + +/// This Vec thing! +//~^ERROR unclosed HTML tag `Vec` +// Some forms of fully-qualified path are simultaneously valid HTML tags +// with attributes. They produce an error, but no suggestion, because figuring +// out if this is valid would require parsing the entire path grammar. +pub struct FullyQualifiedPathsDoNotCount3; + +/// This Vec as IntoIter> thing! +//~^ERROR unclosed HTML tag `i32` +// Some forms of fully-qualified path are simultaneously valid HTML tags +// with attributes. They produce an error, but no suggestion, because figuring +// out if this is valid would require parsing the entire path grammar. +pub struct FullyQualifiedPathsDoNotCount4; + /// This Vec thing! //~^ERROR unclosed HTML tag `i32` // HTML attributes shouldn't be treated as Rust syntax, so no suggestions. diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr index 832b8b2cac79a..3856a251321b2 100644 --- a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr +++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr @@ -1,8 +1,8 @@ -error: unclosed HTML tag `i32` - --> $DIR/html-as-generics-no-suggestions.rs:11:13 +error: unclosed HTML tag `Item` + --> $DIR/html-as-generics-no-suggestions.rs:11:28 | -LL | /// This Vec thing! - | ^^^^ +LL | /// This <[u32] as Iterator> thing! + | ^^^^^^ | note: the lint level is defined here --> $DIR/html-as-generics-no-suggestions.rs:1:9 @@ -10,29 +10,59 @@ note: the lint level is defined here LL | #![deny(rustdoc::invalid_html_tags)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: unclosed HTML tag `Vec` + --> $DIR/html-as-generics-no-suggestions.rs:25:10 + | +LL | /// This ::Iter thing! + | ^^^^ + +error: unclosed HTML tag `Vec` + --> $DIR/html-as-generics-no-suggestions.rs:32:13 + | +LL | /// This Vec::Iter thing! + | ^^^^ + +error: unclosed HTML tag `Vec` + --> $DIR/html-as-generics-no-suggestions.rs:39:13 + | +LL | /// This Vec thing! + | ^^^^ + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:46:17 + | +LL | /// This Vec as IntoIter> thing! + | ^^^^^ + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:53:13 + | +LL | /// This Vec thing! + | ^^^^ + error: unopened HTML tag `i32` - --> $DIR/html-as-generics-no-suggestions.rs:20:13 + --> $DIR/html-as-generics-no-suggestions.rs:62:13 | LL | /// This Vec thing! | ^^^^^^ error: unclosed HTML tag `i32` - --> $DIR/html-as-generics-no-suggestions.rs:25:13 + --> $DIR/html-as-generics-no-suggestions.rs:67:13 | LL | /// This 123 thing! | ^^^^^ error: unclosed HTML tag `i32` - --> $DIR/html-as-generics-no-suggestions.rs:30:14 + --> $DIR/html-as-generics-no-suggestions.rs:72:14 | LL | /// This Vec: thing! | ^^^^^ error: unclosed HTML tag `i32` - --> $DIR/html-as-generics-no-suggestions.rs:35:39 + --> $DIR/html-as-generics-no-suggestions.rs:77:39 | LL | /// This [link](https://rust-lang.org) thing! | ^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.fixed b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed index c0a0de24c5263..07c8c9ff254bc 100644 --- a/src/test/rustdoc-ui/suggestions/html-as-generics.fixed +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed @@ -30,3 +30,43 @@ pub struct BareTurbofish; //~^ERROR unclosed HTML tag `i32` //~|HELP try marking as source pub struct Nested; + +/// Nested generics `Vec>` +//~^ ERROR unclosed HTML tag `u32` +//~|HELP try marking as source +pub struct NestedGenerics; + +/// Generics with path `Vec::Iter` +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct GenericsWithPath; + +/// Generics with path `>::Iter` +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPath; + +/// Generics with path `Vec>::Iter` +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPath2; + +/// Generics with bump `>`s +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithBump; + +/// Generics with bump `Vec>`s +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithBump2; + +/// Generics with punct `>`! +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPunct; + +/// Generics with punct `Vec>`! +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPunct2; diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.rs b/src/test/rustdoc-ui/suggestions/html-as-generics.rs index 0b6009b0e59c3..cdd652f397ec4 100644 --- a/src/test/rustdoc-ui/suggestions/html-as-generics.rs +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.rs @@ -30,3 +30,43 @@ pub struct BareTurbofish; //~^ERROR unclosed HTML tag `i32` //~|HELP try marking as source pub struct Nested; + +/// Nested generics Vec> +//~^ ERROR unclosed HTML tag `u32` +//~|HELP try marking as source +pub struct NestedGenerics; + +/// Generics with path Vec::Iter +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct GenericsWithPath; + +/// Generics with path >::Iter +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPath; + +/// Generics with path Vec>::Iter +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPath2; + +/// Generics with bump >s +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithBump; + +/// Generics with bump Vec>s +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithBump2; + +/// Generics with punct >! +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPunct; + +/// Generics with punct Vec>! +//~^ ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct NestedGenericsWithPunct2; diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr index df54b71264ebc..211dd4210d50c 100644 --- a/src/test/rustdoc-ui/suggestions/html-as-generics.stderr +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr @@ -69,5 +69,93 @@ help: try marking as source code LL | /// This `Vec::` thing! | + + -error: aborting due to 6 previous errors +error: unclosed HTML tag `u32` + --> $DIR/html-as-generics.rs:34:28 + | +LL | /// Nested generics Vec> + | ^^^^^ + | +help: try marking as source code + | +LL | /// Nested generics `Vec>` + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:39:27 + | +LL | /// Generics with path Vec::Iter + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with path `Vec::Iter` + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:44:28 + | +LL | /// Generics with path >::Iter + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with path `>::Iter` + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:49:31 + | +LL | /// Generics with path Vec>::Iter + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with path `Vec>::Iter` + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:54:28 + | +LL | /// Generics with bump >s + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with bump `>`s + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:59:31 + | +LL | /// Generics with bump Vec>s + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with bump `Vec>`s + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:64:29 + | +LL | /// Generics with punct >! + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with punct `>`! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:69:32 + | +LL | /// Generics with punct Vec>! + | ^^^^^ + | +help: try marking as source code + | +LL | /// Generics with punct `Vec>`! + | + + + +error: aborting due to 14 previous errors From 72cf46aa72b79e044b08b70e5dd9e56e3ef21f89 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Mon, 12 Sep 2022 20:10:35 +0200 Subject: [PATCH 8/9] Feature gate the rustdoc::missing_doc_code_examples lint --- compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/lint.rs | 9 ++++-- .../passes/check_doc_test_visibility.rs | 2 +- src/test/rustdoc-ui/check-fail.rs | 1 + src/test/rustdoc-ui/check-fail.stderr | 12 ++++---- src/test/rustdoc-ui/check.rs | 4 ++- src/test/rustdoc-ui/check.stderr | 18 +++++++----- src/test/rustdoc-ui/doc-without-codeblock.rs | 3 +- .../rustdoc-ui/doc-without-codeblock.stderr | 12 ++++---- ...-gate-rustdoc_missing_doc_code_examples.rs | 10 +++++++ ...e-rustdoc_missing_doc_code_examples.stderr | 29 +++++++++++++++++++ src/test/rustdoc-ui/lint-group.rs | 2 ++ src/test/rustdoc-ui/lint-group.stderr | 12 ++++---- .../lint-missing-doc-code-example.rs | 1 + .../lint-missing-doc-code-example.stderr | 12 ++++---- 16 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs create mode 100644 src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5377ebde1683f..2cbf348f13a1b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -221,6 +221,8 @@ declare_features! ( (active, rustc_private, "1.0.0", Some(27812), None), /// Allows using internal rustdoc features like `doc(primitive)` or `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), /// Allows using `#[start]` on a function indicating that it is the program entrypoint. (active, start, "1.0.0", Some(29633), None), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 871bc5c1cdb06..1779ff4bcf1dc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1292,6 +1292,7 @@ symbols! { rustc_variance, rustdoc, rustdoc_internals, + rustdoc_missing_doc_code_examples, rustfmt, rvalue_static_promotion, s, diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 240aec52cff02..e76c19a61c541 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -64,9 +64,13 @@ where } macro_rules! declare_rustdoc_lint { - ($(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?) => { + ( + $(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)? + $(@feature_gate = $gate:expr;)? + ) => { declare_tool_lint! { $(#[$attr])* pub rustdoc::$name, $level, $descr + $(, @feature_gate = $gate;)? } } } @@ -123,7 +127,8 @@ declare_rustdoc_lint! { /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples MISSING_DOC_CODE_EXAMPLES, Allow, - "detects publicly-exported items without code samples in their documentation" + "detects publicly-exported items without code samples in their documentation", + @feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples; } declare_rustdoc_lint! { diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index e86f9083394cf..55d5f303d3452 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -117,7 +117,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item find_testable_code(dox, &mut tests, ErrorCodes::No, false, None); - if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() { + if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples { if should_have_doc_example(cx, item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = item.attr_span(cx.tcx); diff --git a/src/test/rustdoc-ui/check-fail.rs b/src/test/rustdoc-ui/check-fail.rs index 2355d6a3d6cbc..c5e1759ee2d1d 100644 --- a/src/test/rustdoc-ui/check-fail.rs +++ b/src/test/rustdoc-ui/check-fail.rs @@ -1,5 +1,6 @@ // compile-flags: -Z unstable-options --check +#![feature(rustdoc_missing_doc_code_examples)] #![deny(missing_docs)] #![deny(rustdoc::all)] diff --git a/src/test/rustdoc-ui/check-fail.stderr b/src/test/rustdoc-ui/check-fail.stderr index 5d46dc7201409..217b89d935bf9 100644 --- a/src/test/rustdoc-ui/check-fail.stderr +++ b/src/test/rustdoc-ui/check-fail.stderr @@ -1,30 +1,30 @@ error: missing documentation for a function - --> $DIR/check-fail.rs:11:1 + --> $DIR/check-fail.rs:12:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/check-fail.rs:3:9 + --> $DIR/check-fail.rs:4:9 | LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ error: missing code example in this documentation - --> $DIR/check-fail.rs:11:1 + --> $DIR/check-fail.rs:12:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/check-fail.rs:4:9 + --> $DIR/check-fail.rs:5:9 | LL | #![deny(rustdoc::all)] | ^^^^^^^^^^^^ = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]` error: unknown attribute `testharness`. Did you mean `test_harness`? - --> $DIR/check-fail.rs:6:1 + --> $DIR/check-fail.rs:7:1 | LL | / //! ```rust,testharness LL | | @@ -36,7 +36,7 @@ LL | | //! ``` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function error: unknown attribute `testharness`. Did you mean `test_harness`? - --> $DIR/check-fail.rs:15:1 + --> $DIR/check-fail.rs:16:1 | LL | / /// hello LL | | diff --git a/src/test/rustdoc-ui/check.rs b/src/test/rustdoc-ui/check.rs index 2b44ba24b4426..f70b033615139 100644 --- a/src/test/rustdoc-ui/check.rs +++ b/src/test/rustdoc-ui/check.rs @@ -2,9 +2,11 @@ // compile-flags: -Z unstable-options --check // normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" -#![warn(missing_docs)] +#![feature(rustdoc_missing_doc_code_examples)] //~^ WARN //~^^ WARN + +#![warn(missing_docs)] #![warn(rustdoc::all)] pub fn foo() {} diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr index 06e607fbe55fa..78ae65d313a70 100644 --- a/src/test/rustdoc-ui/check.stderr +++ b/src/test/rustdoc-ui/check.stderr @@ -1,22 +1,23 @@ warning: missing documentation for the crate --> $DIR/check.rs:5:1 | -LL | / #![warn(missing_docs)] +LL | / #![feature(rustdoc_missing_doc_code_examples)] LL | | LL | | -LL | | #![warn(rustdoc::all)] +LL | | +... | LL | | LL | | pub fn foo() {} | |_______________^ | note: the lint level is defined here - --> $DIR/check.rs:5:9 + --> $DIR/check.rs:9:9 | LL | #![warn(missing_docs)] | ^^^^^^^^^^^^ warning: missing documentation for a function - --> $DIR/check.rs:10:1 + --> $DIR/check.rs:12:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^ @@ -24,7 +25,7 @@ LL | pub fn foo() {} warning: no documentation found for this crate's top-level module | note: the lint level is defined here - --> $DIR/check.rs:8:9 + --> $DIR/check.rs:10:9 | LL | #![warn(rustdoc::all)] | ^^^^^^^^^^^^ @@ -35,10 +36,11 @@ LL | #![warn(rustdoc::all)] warning: missing code example in this documentation --> $DIR/check.rs:5:1 | -LL | / #![warn(missing_docs)] +LL | / #![feature(rustdoc_missing_doc_code_examples)] +LL | | LL | | LL | | -LL | | #![warn(rustdoc::all)] +... | LL | | LL | | pub fn foo() {} | |_______________^ @@ -46,7 +48,7 @@ LL | | pub fn foo() {} = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]` warning: missing code example in this documentation - --> $DIR/check.rs:10:1 + --> $DIR/check.rs:12:1 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs index 315fca195873a..86d7c83d33598 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.rs +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -1,4 +1,5 @@ -#![deny(rustdoc::missing_doc_code_examples)] //~ ERROR missing code example in this documentation +#![feature(rustdoc_missing_doc_code_examples)] //~ ERROR missing code example in this documentation +#![deny(rustdoc::missing_doc_code_examples)] /// Some docs. //~^ ERROR missing code example in this documentation diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index 1c138044165f2..ebf2a2d54f75c 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -1,35 +1,35 @@ error: missing code example in this documentation --> $DIR/doc-without-codeblock.rs:1:1 | -LL | / #![deny(rustdoc::missing_doc_code_examples)] +LL | / #![feature(rustdoc_missing_doc_code_examples)] +LL | | #![deny(rustdoc::missing_doc_code_examples)] LL | | LL | | /// Some docs. -LL | | ... | LL | | } LL | | } | |_^ | note: the lint level is defined here - --> $DIR/doc-without-codeblock.rs:1:9 + --> $DIR/doc-without-codeblock.rs:2:9 | LL | #![deny(rustdoc::missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:7:1 + --> $DIR/doc-without-codeblock.rs:8:1 | LL | /// And then, the princess died. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:10:5 + --> $DIR/doc-without-codeblock.rs:11:5 | LL | /// Or maybe not because she saved herself! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:3:1 + --> $DIR/doc-without-codeblock.rs:4:1 | LL | /// Some docs. | ^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs new file mode 100644 index 0000000000000..daba698686408 --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs @@ -0,0 +1,10 @@ +#![deny(unknown_lints)] +//~^ NOTE defined here + +#![allow(rustdoc::missing_doc_code_examples)] +//~^ ERROR unknown lint +//~| ERROR unknown lint +//~| NOTE lint is unstable +//~| NOTE lint is unstable +//~| NOTE see issue +//~| NOTE see issue diff --git a/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr new file mode 100644 index 0000000000000..517e08aa7c974 --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr @@ -0,0 +1,29 @@ +error: unknown lint: `rustdoc::missing_doc_code_examples` + --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1 + | +LL | #![allow(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:1:9 + | +LL | #![deny(unknown_lints)] + | ^^^^^^^^^^^^^ + = note: the `rustdoc::missing_doc_code_examples` lint is unstable + = note: see issue #101730 for more information + = help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable + +error: unknown lint: `rustdoc::missing_doc_code_examples` + --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1 + | +LL | #![allow(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `rustdoc::missing_doc_code_examples` lint is unstable + = note: see issue #101730 for more information + = help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs index 61555a6e68617..09aca6d2b2742 100644 --- a/src/test/rustdoc-ui/lint-group.rs +++ b/src/test/rustdoc-ui/lint-group.rs @@ -1,3 +1,5 @@ +#![feature(rustdoc_missing_doc_code_examples)] + //! Documenting the kinds of lints emitted by rustdoc. //! //! ``` diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index e28600160b1fd..5336c0445747a 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -1,18 +1,18 @@ error: missing code example in this documentation - --> $DIR/lint-group.rs:16:1 + --> $DIR/lint-group.rs:18:1 | LL | /// wait, this doesn't have a doctest? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-group.rs:7:9 + --> $DIR/lint-group.rs:9:9 | LL | #![deny(rustdoc::all)] | ^^^^^^^^^^^^ = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]` error: documentation test in private item - --> $DIR/lint-group.rs:19:1 + --> $DIR/lint-group.rs:21:1 | LL | / /// wait, this *does* have a doctest? LL | | /// @@ -24,13 +24,13 @@ LL | | /// ``` = note: `#[deny(rustdoc::private_doc_tests)]` implied by `#[deny(rustdoc::all)]` error: missing code example in this documentation - --> $DIR/lint-group.rs:26:1 + --> $DIR/lint-group.rs:28:1 | LL | /// | ^^^^^^^^^^^^^ error: unresolved link to `error` - --> $DIR/lint-group.rs:9:29 + --> $DIR/lint-group.rs:11:29 | LL | /// what up, let's make an [error] | ^^^^^ no item named `error` in scope @@ -39,7 +39,7 @@ LL | /// what up, let's make an [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unclosed HTML tag `unknown` - --> $DIR/lint-group.rs:26:5 + --> $DIR/lint-group.rs:28:5 | LL | /// | ^^^^^^^^^ diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs index fac6342cd24b9..40f35728d79b0 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -1,3 +1,4 @@ +#![feature(rustdoc_missing_doc_code_examples)] #![deny(missing_docs)] #![deny(rustdoc::missing_doc_code_examples)] diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr index 9e51ecd2ba017..f9331250154d7 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -1,35 +1,35 @@ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:19:1 + --> $DIR/lint-missing-doc-code-example.rs:20:1 | LL | pub mod module1 { | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-missing-doc-code-example.rs:2:9 + --> $DIR/lint-missing-doc-code-example.rs:3:9 | LL | #![deny(rustdoc::missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:37:3 + --> $DIR/lint-missing-doc-code-example.rs:38:3 | LL | /// doc | ^^^^^^^ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:49:1 + --> $DIR/lint-missing-doc-code-example.rs:50:1 | LL | /// Doc | ^^^^^^^ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:56:1 + --> $DIR/lint-missing-doc-code-example.rs:57:1 | LL | /// Doc | ^^^^^^^ error: missing code example in this documentation - --> $DIR/lint-missing-doc-code-example.rs:63:1 + --> $DIR/lint-missing-doc-code-example.rs:64:1 | LL | /// Doc | ^^^^^^^ From 29f789ffdc3da0cd1d0b0be67284265f6a5ab818 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 12 Sep 2022 12:48:22 -0700 Subject: [PATCH 9/9] rustdoc: fix treatment of backslash-escaped HTML Try generating HTML for this markup: \example It will produce text, not HTML, in both rustdoc's real HTML output and in the commonmark reference implementation: https://spec.commonmark.org/dingus/?text=%5C%3Ca%20href%3D%22https%3A%2F%2Fexample.com%22%3Eexample%3C%2Fa%3E --- src/librustdoc/passes/html_tags.rs | 2 +- src/test/rustdoc-ui/invalid-html-tags.rs | 7 +++++++ src/test/rustdoc-ui/invalid-html-tags.stderr | 8 +++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index f3a3c853caca6..5cea9def2d966 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -278,7 +278,7 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> { for (event, range) in p { match event { Event::Start(Tag::CodeBlock(_)) => in_code_block = true, - Event::Html(text) | Event::Text(text) if !in_code_block => { + Event::Html(text) if !in_code_block => { extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) } Event::End(Tag::CodeBlock(_)) => in_code_block = false, diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs index 0f9d2e4b35d05..317f1fd1d4641 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.rs +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -114,3 +114,10 @@ pub fn k() {} /// Web Components style //~^ ERROR unopened HTML tag `unopened-tag` pub fn m() {} + +/// backslashed \ +pub fn no_error_1() {} + +/// backslashed \< +//~^ ERROR unclosed HTML tag `a` +pub fn p() {} diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr index 24a455576e80a..9c2bfcf2c3dd7 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.stderr +++ b/src/test/rustdoc-ui/invalid-html-tags.stderr @@ -94,5 +94,11 @@ error: unclosed HTML tag `dashed-tags` LL | /// Web Components style | ^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: unclosed HTML tag `a` + --> $DIR/invalid-html-tags.rs:121:19 + | +LL | /// backslashed \< + | ^^ + +error: aborting due to 16 previous errors