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 b0cfeec2931cfb3bc9f8b11510684fb2fedee731 Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Fri, 26 Aug 2022 16:06:27 +0200 Subject: [PATCH 2/9] translations(rustc_session): migrates session.rs and config.rs --- compiler/rustc_session/src/config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8bb3878fbbb47..0018346c72c49 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,6 +1,7 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. +use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -898,7 +899,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.emit_fatal(err); + sess.emit_fatal(TargetDataLayoutParseError { err }); }); let mut ret = CrateConfig::default(); From 329d5014b6a773d819e6cd56d5930a204bed7983 Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Thu, 1 Sep 2022 08:03:47 +0200 Subject: [PATCH 3/9] translations(rustc_session): migrate output.rs --- .../locales/en-US/session.ftl | 10 ++++ compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_session/src/config.rs | 3 +- compiler/rustc_session/src/errors.rs | 51 ++++++++++++++++++- compiler/rustc_session/src/lib.rs | 2 + compiler/rustc_session/src/output.rs | 35 ++++--------- compiler/rustc_session/src/session.rs | 44 ++++++++++++++++ 7 files changed, 119 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index d2a2958f62436..76cae3c81e451 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -56,3 +56,13 @@ session_target_invalid_bits_size = {$err} session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform + +session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions + +session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}` + +session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen + +session_crate_name_empty = crate name must not be empty + +session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 4d207fd17fb2d..c36ca11fad6f2 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -13,9 +13,9 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_target = { path = "../rustc_target" } rustc_hir = { path = "../rustc_hir" } rustc_lint_defs = { path = "../rustc_lint_defs" } -rustc_target = { path = "../rustc_target" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0018346c72c49..8bb3878fbbb47 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,7 +1,6 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. -use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -899,7 +898,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.emit_fatal(TargetDataLayoutParseError { err }); + sess.emit_fatal(err); }); let mut ret = CrateConfig::default(); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 3c93cfab183d2..c6596ff249899 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU32; use crate::cgu_reuse_tracker::CguReuse; use crate::{self as rustc_session, SessionDiagnostic}; -use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan}; +use rustc_errors::{fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, MultiSpan}; use rustc_macros::SessionDiagnostic; use rustc_span::{Span, Symbol}; use rustc_target::abi::TargetDataLayoutErrors; @@ -170,3 +170,52 @@ pub struct StackProtectorNotSupportedForTarget<'a> { pub struct SplitDebugInfoUnstablePlatform { pub debuginfo: SplitDebuginfo, } + +#[derive(SessionDiagnostic)] +#[diag(session::file_is_not_writeable)] +pub struct FileIsNotWriteable<'a> { + pub file: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_does_not_match)] +pub struct CrateNameDoesNotMatch<'a> { + #[primary_span] + pub span: Span, + pub s: &'a str, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_invalid)] +pub struct CrateNameInvalid<'a> { + pub s: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_empty)] +pub struct CrateNameEmpty { + #[primary_span] + pub span: Option, +} + +pub struct InvalidCharacterInCrateName<'a> { + pub span: Option, + pub character: char, + pub crate_name: &'a str, +} + +impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> { + fn into_diagnostic( + self, + sess: &Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name); + if let Some(sp) = self.span { + diag.set_span(sp); + } + diag.set_arg("character", self.character); + diag.set_arg("crate_name", self.crate_name); + diag + } +} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 02d5d33c8d5ba..b9b243f6f0840 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -9,6 +9,8 @@ #![feature(map_many_mut)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index e5e6579d75b10..2511bee46afeb 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,5 +1,9 @@ //! Related to out filenames of compilation (e.g. save analysis, binaries). use crate::config::{CrateType, Input, OutputFilenames, OutputType}; +use crate::errors::{ + CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + InvalidCharacterInCrateName, +}; use crate::Session; use rustc_ast as ast; use rustc_span::symbol::sym; @@ -30,11 +34,7 @@ pub fn out_filename( /// read-only file. We should be consistent. pub fn check_file_is_writeable(file: &Path, sess: &Session) { if !is_writeable(file) { - sess.fatal(&format!( - "output file {} is not writeable -- check its \ - permissions", - file.display() - )); + sess.emit_fatal(FileIsNotWriteable { file }); } } @@ -61,11 +61,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { if name.as_str() != s { - let msg = format!( - "`--crate-name` and `#[crate_name]` are \ - required to match, but `{s}` != `{name}`" - ); - sess.span_err(attr.span, &msg); + sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name }); } } return validate(s.clone(), None); @@ -77,11 +73,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Input::File(ref path) = *input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { if s.starts_with('-') { - let msg = format!( - "crate names cannot start with a `-`, but \ - `{s}` has a leading hyphen" - ); - sess.err(&msg); + sess.emit_err(CrateNameInvalid { s }); } else { return validate(s.replace('-', "_"), None); } @@ -94,15 +86,9 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { let mut err_count = 0; { - let mut say = |s: &str| { - match sp { - Some(sp) => sess.span_err(sp, s), - None => sess.err(s), - }; - err_count += 1; - }; if s.is_empty() { - say("crate name must not be empty"); + err_count += 1; + sess.emit_err(CrateNameEmpty { span: sp }); } for c in s.chars() { if c.is_alphanumeric() { @@ -111,7 +97,8 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { if c == '_' { continue; } - say(&format!("invalid character `{c}` in crate name: `{s}`")); + err_count += 1; + sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s }); } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index caf9d582ab099..b1b4101af9e64 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -297,6 +297,8 @@ impl Session { } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn>( &self, sp: S, @@ -305,6 +307,8 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_expectation>( &self, sp: S, @@ -314,6 +318,8 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -323,10 +329,14 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_expectation( &self, msg: impl Into, @@ -335,6 +345,8 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_allow>( &self, sp: S, @@ -343,10 +355,14 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_expect( &self, msg: impl Into, @@ -355,6 +371,8 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err>( &self, sp: S, @@ -363,6 +381,8 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err_with_code>( &self, sp: S, @@ -373,6 +393,8 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err( &self, msg: impl Into, @@ -380,6 +402,8 @@ impl Session { self.parse_sess.struct_err(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err_with_code( &self, msg: impl Into, @@ -388,6 +412,8 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_code( &self, msg: impl Into, @@ -396,6 +422,8 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal>( &self, sp: S, @@ -404,6 +432,8 @@ impl Session { self.diagnostic().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal_with_code>( &self, sp: S, @@ -413,15 +443,21 @@ impl Session { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { self.diagnostic().span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal_with_code>( &self, sp: S, @@ -431,10 +467,14 @@ impl Session { self.diagnostic().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn fatal(&self, msg: impl Into) -> ! { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_or_warn>( &self, is_warning: bool, @@ -448,6 +488,8 @@ impl Session { } } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err>( &self, sp: S, @@ -456,6 +498,8 @@ impl Session { self.diagnostic().span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_with_code>( &self, sp: S, From 2126622887e5447610e5d14803e52aa51bc9dd44 Mon Sep 17 00:00:00 2001 From: winxpqq955 Date: Sun, 11 Sep 2022 15:09:39 +0800 Subject: [PATCH 4/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 bd5484659012f986ac85ffddef260a423331f574 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 11 Sep 2022 19:19:07 +0000 Subject: [PATCH 5/9] A SubstitutionPart is not a deletion if it replaces nothing with nothing --- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_errors/src/lib.rs | 19 +++++----- .../dyn-keyword/dyn-2018-edition-lint.stderr | 35 ++++++++----------- .../dyn-keyword/dyn-2021-edition-error.stderr | 10 +++--- .../ui/dyn-keyword/dyn-angle-brackets.stderr | 5 ++- ...plicit-hrtb-without-dyn.edition2021.stderr | 5 ++- src/test/ui/issues/issue-86756.stderr | 5 ++- .../allowed-group-warn-by-default-lint.stderr | 15 ++++---- .../ui/lint/force-warn/cap-lints-allow.stderr | 15 ++++---- ...up-allowed-cli-warn-by-default-lint.stderr | 15 ++++---- .../lint-group-allowed-lint-group.stderr | 15 ++++---- ...-group-allowed-warn-by-default-lint.stderr | 15 ++++---- src/test/ui/parser/increment-notfixed.stderr | 30 +++++++--------- .../parser/trait-object-trait-parens.stderr | 15 ++++---- .../reserved-prefixes-migration.stderr | 15 +++----- .../ui/rust-2021/reserved-prefixes.stderr | 27 +++++--------- src/test/ui/suggestions/issue-61963.stderr | 35 ++++++++----------- .../suggest-blanket-impl-local-trait.stderr | 35 ++++++++----------- ...ping-self-ty-and-trait-edition-2021.stderr | 5 ++- .../suggest-swapping-self-ty-and-trait.stderr | 5 ++- .../ui/traits/bound/not-on-bare-trait.stderr | 5 ++- 21 files changed, 130 insertions(+), 198 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e79ce11a6fc07..6de749eaa5781 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1704,7 +1704,7 @@ impl EmitterWriter { { notice_capitalization |= only_capitalization; - let has_deletion = parts.iter().any(|p| p.is_deletion()); + let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); let is_multiline = complete.lines().count() > 1; if let Some(span) = span.primary_span() { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3e02d2ebb7e3e..1c77b4d515322 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -151,21 +151,20 @@ pub struct SubstitutionHighlight { impl SubstitutionPart { pub fn is_addition(&self, sm: &SourceMap) -> bool { - !self.snippet.is_empty() - && sm - .span_to_snippet(self.span) - .map_or(self.span.is_empty(), |snippet| snippet.trim().is_empty()) + !self.snippet.is_empty() && !self.replaces_meaningful_content(sm) } - pub fn is_deletion(&self) -> bool { - self.snippet.trim().is_empty() + pub fn is_deletion(&self, sm: &SourceMap) -> bool { + self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm) } pub fn is_replacement(&self, sm: &SourceMap) -> bool { - !self.snippet.is_empty() - && sm - .span_to_snippet(self.span) - .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) + !self.snippet.is_empty() && self.replaces_meaningful_content(sm) + } + + fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool { + sm.span_to_snippet(self.span) + .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) } } diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr index 34699bb26582e..e7db68693c068 100644 --- a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr +++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr @@ -13,9 +13,8 @@ LL | #[deny(bare_trait_objects)] = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &dyn SomeTrait, y: Box) { - | +LL | fn function(x: &dyn SomeTrait, y: Box) { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:4:35 @@ -27,9 +26,8 @@ LL | fn function(x: &SomeTrait, y: Box) { = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &SomeTrait, y: Box) { - | +LL | fn function(x: &SomeTrait, y: Box) { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:17:14 @@ -41,9 +39,8 @@ LL | let _x: &SomeTrait = todo!(); = note: for more information, see help: use `dyn` | -LL - let _x: &SomeTrait = todo!(); -LL + let _x: &dyn SomeTrait = todo!(); - | +LL | let _x: &dyn SomeTrait = todo!(); + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:4:17 @@ -55,9 +52,8 @@ LL | fn function(x: &SomeTrait, y: Box) { = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &dyn SomeTrait, y: Box) { - | +LL | fn function(x: &dyn SomeTrait, y: Box) { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:4:17 @@ -69,9 +65,8 @@ LL | fn function(x: &SomeTrait, y: Box) { = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &dyn SomeTrait, y: Box) { - | +LL | fn function(x: &dyn SomeTrait, y: Box) { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:4:35 @@ -83,9 +78,8 @@ LL | fn function(x: &SomeTrait, y: Box) { = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &SomeTrait, y: Box) { - | +LL | fn function(x: &SomeTrait, y: Box) { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/dyn-2018-edition-lint.rs:4:35 @@ -97,9 +91,8 @@ LL | fn function(x: &SomeTrait, y: Box) { = note: for more information, see help: use `dyn` | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &SomeTrait, y: Box) { - | +LL | fn function(x: &SomeTrait, y: Box) { + | +++ error: aborting due to 7 previous errors diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr index 9e212c77dc77c..08ee77116f0b8 100644 --- a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr +++ b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr @@ -6,9 +6,8 @@ LL | fn function(x: &SomeTrait, y: Box) { | help: add `dyn` keyword before this trait | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &dyn SomeTrait, y: Box) { - | +LL | fn function(x: &dyn SomeTrait, y: Box) { + | +++ error[E0782]: trait objects must include the `dyn` keyword --> $DIR/dyn-2021-edition-error.rs:3:35 @@ -18,9 +17,8 @@ LL | fn function(x: &SomeTrait, y: Box) { | help: add `dyn` keyword before this trait | -LL - fn function(x: &SomeTrait, y: Box) { -LL + fn function(x: &SomeTrait, y: Box) { - | +LL | fn function(x: &SomeTrait, y: Box) { + | +++ error: aborting due to 2 previous errors diff --git a/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr b/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr index 9bc603fba5466..261c2d5742f40 100644 --- a/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr +++ b/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr @@ -13,9 +13,8 @@ LL | #![deny(bare_trait_objects)] = note: for more information, see help: use `dyn` | -LL - ::fmt(self, f) -LL + ::fmt(self, f) - | +LL | ::fmt(self, f) + | +++ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr index c01c33a893124..8f40922732486 100644 --- a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr +++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr @@ -6,9 +6,8 @@ LL | fn ice() -> impl AsRef { | help: add `dyn` keyword before this trait | -LL - fn ice() -> impl AsRef { -LL + fn ice() -> impl AsRef { - | +LL | fn ice() -> impl AsRef { + | +++ error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 diff --git a/src/test/ui/issues/issue-86756.stderr b/src/test/ui/issues/issue-86756.stderr index 399c940ca195c..b26c1834d84a3 100644 --- a/src/test/ui/issues/issue-86756.stderr +++ b/src/test/ui/issues/issue-86756.stderr @@ -25,9 +25,8 @@ LL | eq:: = note: for more information, see help: use `dyn` | -LL - eq:: -LL + eq:: - | +LL | eq:: + | +++ error[E0107]: missing generics for trait `Foo` --> $DIR/issue-86756.rs:5:15 diff --git a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr index 8d826bd145762..94d81c3aa71b5 100644 --- a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr @@ -9,9 +9,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/allowed-group-warn-by-default-lint.rs:10:25 @@ -23,9 +22,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/allowed-group-warn-by-default-lint.rs:10:25 @@ -37,9 +35,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: 3 warnings emitted diff --git a/src/test/ui/lint/force-warn/cap-lints-allow.stderr b/src/test/ui/lint/force-warn/cap-lints-allow.stderr index 978270872c45c..7f0fd8530e2cc 100644 --- a/src/test/ui/lint/force-warn/cap-lints-allow.stderr +++ b/src/test/ui/lint/force-warn/cap-lints-allow.stderr @@ -9,9 +9,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/cap-lints-allow.rs:8:25 @@ -23,9 +22,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/cap-lints-allow.rs:8:25 @@ -37,9 +35,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: 3 warnings emitted diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr index 6e67ebf274733..eb2bca7b84d71 100644 --- a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr @@ -9,9 +9,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25 @@ -23,9 +22,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25 @@ -37,9 +35,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: 3 warnings emitted diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr index c5dea84b8f358..ed01937a57b15 100644 --- a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr +++ b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr @@ -9,9 +9,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-lint-group.rs:10:25 @@ -23,9 +22,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-lint-group.rs:10:25 @@ -37,9 +35,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: 3 warnings emitted diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr index acd0c503d9c02..8db7c12757b03 100644 --- a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr @@ -9,9 +9,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25 @@ -23,9 +22,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25 @@ -37,9 +35,8 @@ LL | pub fn function(_x: Box) {} = note: for more information, see help: use `dyn` | -LL - pub fn function(_x: Box) {} -LL + pub fn function(_x: Box) {} - | +LL | pub fn function(_x: Box) {} + | +++ warning: 3 warnings emitted diff --git a/src/test/ui/parser/increment-notfixed.stderr b/src/test/ui/parser/increment-notfixed.stderr index 352d98cf82ec7..ae55ae0671431 100644 --- a/src/test/ui/parser/increment-notfixed.stderr +++ b/src/test/ui/parser/increment-notfixed.stderr @@ -8,9 +8,8 @@ help: use `+= 1` instead | LL | { let tmp = i; i += 1; tmp }; | +++++++++++ ~~~~~~~~~~~~~~~ -LL - i++; -LL + i += 1; - | +LL | i += 1; + | ~~~~ error: Rust has no postfix increment operator --> $DIR/increment-notfixed.rs:17:12 @@ -24,9 +23,8 @@ help: use `+= 1` instead | LL | while { let tmp = i; i += 1; tmp } < 5 { | +++++++++++ ~~~~~~~~~~~~~~~ -LL - while i++ < 5 { -LL + while i += 1 < 5 { - | +LL | while i += 1 < 5 { + | ~~~~ error: Rust has no postfix increment operator --> $DIR/increment-notfixed.rs:25:8 @@ -38,9 +36,8 @@ help: use `+= 1` instead | LL | { let tmp_ = tmp; tmp += 1; tmp_ }; | ++++++++++++ ~~~~~~~~~~~~~~~~~~ -LL - tmp++; -LL + tmp += 1; - | +LL | tmp += 1; + | ~~~~ error: Rust has no postfix increment operator --> $DIR/increment-notfixed.rs:31:14 @@ -54,9 +51,8 @@ help: use `+= 1` instead | LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { | ++++++++++++ ~~~~~~~~~~~~~~~~~~ -LL - while tmp++ < 5 { -LL + while tmp += 1 < 5 { - | +LL | while tmp += 1 < 5 { + | ~~~~ error: Rust has no postfix increment operator --> $DIR/increment-notfixed.rs:39:16 @@ -68,9 +64,8 @@ help: use `+= 1` instead | LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp }; | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ -LL - foo.bar.qux++; -LL + foo.bar.qux += 1; - | +LL | foo.bar.qux += 1; + | ~~~~ error: Rust has no postfix increment operator --> $DIR/increment-notfixed.rs:49:10 @@ -82,9 +77,8 @@ help: use `+= 1` instead | LL | { let tmp = s.tmp; s.tmp += 1; tmp }; | +++++++++++ ~~~~~~~~~~~~~~~~~~~ -LL - s.tmp++; -LL + s.tmp += 1; - | +LL | s.tmp += 1; + | ~~~~ error: Rust has no prefix increment operator --> $DIR/increment-notfixed.rs:56:5 diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index 7ee965bd2babd..823f75bfac86f 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -27,9 +27,8 @@ LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; = note: for more information, see help: use `dyn` | -LL - let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; -LL + let _: Box Trait<'a>)>; - | +LL | let _: Box Trait<'a>)>; + | +++ error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-object-trait-parens.rs:8:35 @@ -52,9 +51,8 @@ LL | let _: Box Trait<'a>) + (Obj)>; = note: for more information, see help: use `dyn` | -LL - let _: Box Trait<'a>) + (Obj)>; -LL + let _: Box Trait<'a>) + (Obj)>; - | +LL | let _: Box Trait<'a>) + (Obj)>; + | +++ error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-object-trait-parens.rs:13:47 @@ -77,9 +75,8 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; = note: for more information, see help: use `dyn` | -LL - let _: Box Trait<'a> + (Obj) + (?Sized)>; -LL + let _: Box Trait<'a> + (Obj) + (?Sized)>; - | +LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; + | +++ error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-object-trait-parens.rs:18:36 diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr index 647a9f3931254..94f9bb57cc813 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr @@ -13,8 +13,7 @@ LL | #![warn(rust_2021_prefixes_incompatible_syntax)] = note: for more information, see help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | -LL - m2!(z"hey"); -LL + m2!(z "hey"); +LL | m2!(z "hey"); | warning: prefix `prefix` is unknown @@ -27,8 +26,7 @@ LL | m2!(prefix"hey"); = note: for more information, see help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | -LL - m2!(prefix"hey"); -LL + m2!(prefix "hey"); +LL | m2!(prefix "hey"); | warning: prefix `hey` is unknown @@ -41,8 +39,7 @@ LL | m3!(hey#123); = note: for more information, see help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | -LL - m3!(hey#123); -LL + m3!(hey #123); +LL | m3!(hey #123); | warning: prefix `hey` is unknown @@ -55,8 +52,7 @@ LL | m3!(hey#hey); = note: for more information, see help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | -LL - m3!(hey#hey); -LL + m3!(hey #hey); +LL | m3!(hey #hey); | warning: prefix `kind` is unknown @@ -69,8 +65,7 @@ LL | #name = #kind#value = note: for more information, see help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | -LL - #name = #kind#value -LL + #name = #kind #value +LL | #name = #kind #value | warning: 5 warnings emitted diff --git a/src/test/ui/rust-2021/reserved-prefixes.stderr b/src/test/ui/rust-2021/reserved-prefixes.stderr index df31aee66fea7..fcda5fcac5b3b 100644 --- a/src/test/ui/rust-2021/reserved-prefixes.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes.stderr @@ -7,8 +7,7 @@ LL | demo3!(foo#bar); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo3!(foo#bar); -LL + demo3!(foo #bar); +LL | demo3!(foo #bar); | error: prefix `foo` is unknown @@ -20,8 +19,7 @@ LL | demo2!(foo"bar"); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo2!(foo"bar"); -LL + demo2!(foo "bar"); +LL | demo2!(foo "bar"); | error: prefix `foo` is unknown @@ -33,8 +31,7 @@ LL | demo2!(foo'b'); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo2!(foo'b'); -LL + demo2!(foo 'b'); +LL | demo2!(foo 'b'); | error: prefix `foo` is unknown @@ -46,8 +43,7 @@ LL | demo2!(foo'b); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo2!(foo'b); -LL + demo2!(foo 'b); +LL | demo2!(foo 'b); | error: prefix `foo` is unknown @@ -59,8 +55,7 @@ LL | demo3!(foo# bar); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo3!(foo# bar); -LL + demo3!(foo # bar); +LL | demo3!(foo # bar); | error: prefix `foo` is unknown @@ -72,8 +67,7 @@ LL | demo4!(foo#! bar); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo4!(foo#! bar); -LL + demo4!(foo #! bar); +LL | demo4!(foo #! bar); | error: prefix `foo` is unknown @@ -85,8 +79,7 @@ LL | demo4!(foo## bar); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo4!(foo## bar); -LL + demo4!(foo ## bar); +LL | demo4!(foo ## bar); | error: prefix `foo` is unknown @@ -98,8 +91,7 @@ LL | demo4!(foo#bar#); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo4!(foo#bar#); -LL + demo4!(foo #bar#); +LL | demo4!(foo #bar#); | error: prefix `bar` is unknown @@ -111,8 +103,7 @@ LL | demo4!(foo#bar#); = note: prefixed identifiers and literals are reserved since Rust 2021 help: consider inserting whitespace here | -LL - demo4!(foo#bar#); -LL + demo4!(foo#bar #); +LL | demo4!(foo#bar #); | error: aborting due to 9 previous errors diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr index c0d776e59ab8d..a788cab6e4e8e 100644 --- a/src/test/ui/suggestions/issue-61963.stderr +++ b/src/test/ui/suggestions/issue-61963.stderr @@ -13,9 +13,8 @@ LL | #![deny(bare_trait_objects)] = note: for more information, see help: use `dyn` | -LL - bar: Box, -LL + bar: Box, - | +LL | bar: Box, + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:18:1 @@ -27,9 +26,8 @@ LL | pub struct Foo { = note: for more information, see help: use `dyn` | -LL - pub struct Foo { -LL + dyn pub struct Foo { - | +LL | dyn pub struct Foo { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:28:14 @@ -41,9 +39,8 @@ LL | bar: Box, = note: for more information, see help: use `dyn` | -LL - bar: Box, -LL + bar: Box, - | +LL | bar: Box, + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:28:14 @@ -55,9 +52,8 @@ LL | bar: Box, = note: for more information, see help: use `dyn` | -LL - bar: Box, -LL + bar: Box, - | +LL | bar: Box, + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:18:1 @@ -69,9 +65,8 @@ LL | pub struct Foo { = note: for more information, see help: use `dyn` | -LL - pub struct Foo { -LL + dyn pub struct Foo { - | +LL | dyn pub struct Foo { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:18:1 @@ -83,9 +78,8 @@ LL | pub struct Foo { = note: for more information, see help: use `dyn` | -LL - pub struct Foo { -LL + dyn pub struct Foo { - | +LL | dyn pub struct Foo { + | +++ error: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-61963.rs:18:1 @@ -97,9 +91,8 @@ LL | pub struct Foo { = note: for more information, see help: use `dyn` | -LL - pub struct Foo { -LL + dyn pub struct Foo { - | +LL | dyn pub struct Foo { + | +++ error: aborting due to 7 previous errors diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr index d739a8272f152..398caa98b84db 100644 --- a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr +++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr @@ -6,9 +6,8 @@ LL | impl LocalTraitTwo for LocalTraitOne {} | help: add `dyn` keyword before this trait | -LL - impl LocalTraitTwo for LocalTraitOne {} -LL + impl LocalTraitTwo for dyn LocalTraitOne {} - | +LL | impl LocalTraitTwo for dyn LocalTraitOne {} + | +++ help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne` | LL | impl LocalTraitTwo for T {} @@ -22,9 +21,8 @@ LL | impl fmt::Display for LocalTraitOne { | help: add `dyn` keyword before this trait | -LL - impl fmt::Display for LocalTraitOne { -LL + impl fmt::Display for dyn LocalTraitOne { - | +LL | impl fmt::Display for dyn LocalTraitOne { + | +++ error[E0782]: trait objects must include the `dyn` keyword --> $DIR/suggest-blanket-impl-local-trait.rs:26:23 @@ -34,9 +32,8 @@ LL | impl fmt::Display for LocalTraitTwo + Send { | help: add `dyn` keyword before this trait | -LL - impl fmt::Display for LocalTraitTwo + Send { -LL + impl fmt::Display for dyn LocalTraitTwo + Send { - | +LL | impl fmt::Display for dyn LocalTraitTwo + Send { + | +++ error[E0782]: trait objects must include the `dyn` keyword --> $DIR/suggest-blanket-impl-local-trait.rs:34:24 @@ -46,9 +43,8 @@ LL | impl LocalTraitOne for fmt::Display {} | help: add `dyn` keyword before this trait | -LL - impl LocalTraitOne for fmt::Display {} -LL + impl LocalTraitOne for dyn fmt::Display {} - | +LL | impl LocalTraitOne for dyn fmt::Display {} + | +++ help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display` | LL | impl LocalTraitOne for T {} @@ -62,9 +58,8 @@ LL | impl LocalTraitOne for fmt::Display + Send {} | help: add `dyn` keyword before this trait | -LL - impl LocalTraitOne for fmt::Display + Send {} -LL + impl LocalTraitOne for dyn fmt::Display + Send {} - | +LL | impl LocalTraitOne for dyn fmt::Display + Send {} + | +++ help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send` | LL | impl LocalTraitOne for T {} @@ -78,9 +73,8 @@ LL | impl GenericTrait for LocalTraitOne {} | help: add `dyn` keyword before this trait | -LL - impl GenericTrait for LocalTraitOne {} -LL + impl GenericTrait for dyn LocalTraitOne {} - | +LL | impl GenericTrait for dyn LocalTraitOne {} + | +++ help: alternatively use a blanket implementation to implement `GenericTrait` for all types that also implement `LocalTraitOne` | LL | impl GenericTrait for T {} @@ -94,9 +88,8 @@ LL | impl GenericTraitTwo for GenericTrait {} | help: add `dyn` keyword before this trait | -LL - impl GenericTraitTwo for GenericTrait {} -LL + impl GenericTraitTwo for dyn GenericTrait {} - | +LL | impl GenericTraitTwo for dyn GenericTrait {} + | +++ help: alternatively use a blanket implementation to implement `GenericTraitTwo` for all types that also implement `GenericTrait` | LL | impl> GenericTraitTwo for U {} diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr index fc880d6b86a71..87e7164362091 100644 --- a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr +++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr @@ -39,9 +39,8 @@ LL | impl<'a, T> Struct for Trait<'a, T> {} | help: add `dyn` keyword before this trait | -LL - impl<'a, T> Struct for Trait<'a, T> {} -LL + impl<'a, T> Struct for dyn Trait<'a, T> {} - | +LL | impl<'a, T> Struct for dyn Trait<'a, T> {} + | +++ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr index f5143762da8e5..f716e6c17e22d 100644 --- a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr +++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr @@ -42,9 +42,8 @@ LL | impl<'a, T> Struct for Trait<'a, T> {} = note: for more information, see help: use `dyn` | -LL - impl<'a, T> Struct for Trait<'a, T> {} -LL + impl<'a, T> Struct for dyn Trait<'a, T> {} - | +LL | impl<'a, T> Struct for dyn Trait<'a, T> {} + | +++ error: aborting due to 3 previous errors; 1 warning emitted diff --git a/src/test/ui/traits/bound/not-on-bare-trait.stderr b/src/test/ui/traits/bound/not-on-bare-trait.stderr index 8a92dd11872c4..1c52629daa483 100644 --- a/src/test/ui/traits/bound/not-on-bare-trait.stderr +++ b/src/test/ui/traits/bound/not-on-bare-trait.stderr @@ -9,9 +9,8 @@ LL | fn foo(_x: Foo + Send) { = note: for more information, see help: use `dyn` | -LL - fn foo(_x: Foo + Send) { -LL + fn foo(_x: dyn Foo + Send) { - | +LL | fn foo(_x: dyn Foo + Send) { + | +++ error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time --> $DIR/not-on-bare-trait.rs:7:8 From 3bf33c3aefdf412e1eba91b306b19a0a4c131d4b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 11 Sep 2022 20:02:33 +0000 Subject: [PATCH 6/9] Don't trim substitution if it's only whitespace --- compiler/rustc_errors/src/emitter.rs | 28 +++++++++++++------ .../reserved-prefixes-migration.stderr | 10 +++---- .../ui/rust-2021/reserved-prefixes.stderr | 18 ++++++------ 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 6de749eaa5781..459bcdb113453 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -268,7 +268,10 @@ pub trait Emitter: Translate { SuggestionStyle::ShowAlways, ].contains(&sugg.style) { - let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); + // Don't trim the substitution if it's only whitespace changes + let substitution = &sugg.substitutions[0].parts[0].snippet; + let substitution = + if substitution.trim().is_empty() { substitution } else { substitution.trim() }; let msg = if substitution.is_empty() || sugg.style.hide_inline() { // This substitution is only removal OR we explicitly don't want to show the // code inline (`hide_inline`). Therefore, we don't show the substitution. @@ -1880,16 +1883,23 @@ impl EmitterWriter { let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; + // If this addition is _only_ whitespace, then don't trim it, + // or else we're just not rendering anything. + let is_whitespace_addition = part.snippet.trim().is_empty(); + // Do not underline the leading... - let start = part.snippet.len().saturating_sub(part.snippet.trim_start().len()); + let start = if is_whitespace_addition { + 0 + } else { + part.snippet.len().saturating_sub(part.snippet.trim_start().len()) + }; // ...or trailing spaces. Account for substitutions containing unicode // characters. - let sub_len: usize = part - .snippet - .trim() - .chars() - .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) - .sum(); + let sub_len: usize = + if is_whitespace_addition { &part.snippet } else { part.snippet.trim() } + .chars() + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum(); let offset: isize = offsets .iter() @@ -2130,7 +2140,7 @@ impl EmitterWriter { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum DisplaySuggestion { Underline, Diff, diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr index 94f9bb57cc813..c6bc082cf18db 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr @@ -14,7 +14,7 @@ LL | #![warn(rust_2021_prefixes_incompatible_syntax)] help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | LL | m2!(z "hey"); - | + | + warning: prefix `prefix` is unknown --> $DIR/reserved-prefixes-migration.rs:19:9 @@ -27,7 +27,7 @@ LL | m2!(prefix"hey"); help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | LL | m2!(prefix "hey"); - | + | + warning: prefix `hey` is unknown --> $DIR/reserved-prefixes-migration.rs:22:9 @@ -40,7 +40,7 @@ LL | m3!(hey#123); help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | LL | m3!(hey #123); - | + | + warning: prefix `hey` is unknown --> $DIR/reserved-prefixes-migration.rs:25:9 @@ -53,7 +53,7 @@ LL | m3!(hey#hey); help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | LL | m3!(hey #hey); - | + | + warning: prefix `kind` is unknown --> $DIR/reserved-prefixes-migration.rs:35:14 @@ -66,7 +66,7 @@ LL | #name = #kind#value help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | LL | #name = #kind #value - | + | + warning: 5 warnings emitted diff --git a/src/test/ui/rust-2021/reserved-prefixes.stderr b/src/test/ui/rust-2021/reserved-prefixes.stderr index fcda5fcac5b3b..807d6d98bd3c3 100644 --- a/src/test/ui/rust-2021/reserved-prefixes.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes.stderr @@ -8,7 +8,7 @@ LL | demo3!(foo#bar); help: consider inserting whitespace here | LL | demo3!(foo #bar); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:17:12 @@ -20,7 +20,7 @@ LL | demo2!(foo"bar"); help: consider inserting whitespace here | LL | demo2!(foo "bar"); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:18:12 @@ -32,7 +32,7 @@ LL | demo2!(foo'b'); help: consider inserting whitespace here | LL | demo2!(foo 'b'); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:20:12 @@ -44,7 +44,7 @@ LL | demo2!(foo'b); help: consider inserting whitespace here | LL | demo2!(foo 'b); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:21:12 @@ -56,7 +56,7 @@ LL | demo3!(foo# bar); help: consider inserting whitespace here | LL | demo3!(foo # bar); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:22:12 @@ -68,7 +68,7 @@ LL | demo4!(foo#! bar); help: consider inserting whitespace here | LL | demo4!(foo #! bar); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:23:12 @@ -80,7 +80,7 @@ LL | demo4!(foo## bar); help: consider inserting whitespace here | LL | demo4!(foo ## bar); - | + | + error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:25:12 @@ -92,7 +92,7 @@ LL | demo4!(foo#bar#); help: consider inserting whitespace here | LL | demo4!(foo #bar#); - | + | + error: prefix `bar` is unknown --> $DIR/reserved-prefixes.rs:25:16 @@ -104,7 +104,7 @@ LL | demo4!(foo#bar#); help: consider inserting whitespace here | LL | demo4!(foo#bar #); - | + | + error: aborting due to 9 previous errors From cb02b647dc0441cfe152fa037ee14f4606c477cb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 9 Aug 2022 03:20:15 +0400 Subject: [PATCH 7/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 91398912d083c0531c37c65de6452fabafe587da Mon Sep 17 00:00:00 2001 From: fee1-dead Date: Mon, 12 Sep 2022 23:04:32 +0800 Subject: [PATCH 8/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 84ca399465be4eced934733ef3dc0b48005ba6af Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 12 Sep 2022 11:11:37 -0700 Subject: [PATCH 9/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