From d5aec64c12db44ddcfbf8682b9ec4e515a6f9953 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Jun 2021 14:37:10 +0200 Subject: [PATCH 01/23] Add proc_macro::Span::{before, after}. --- compiler/rustc_expand/src/proc_macro_server.rs | 6 ++++++ library/proc_macro/src/bridge/mod.rs | 2 ++ library/proc_macro/src/lib.rs | 12 ++++++++++++ 3 files changed, 20 insertions(+) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 92315c4d4f6c7..2507ad44307fd 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -738,6 +738,12 @@ impl server::Span for Rustc<'_> { let loc = self.sess.source_map().lookup_char_pos(span.hi()); LineColumn { line: loc.line, column: loc.col.to_usize() } } + fn before(&mut self, span: Self::Span) -> Self::Span { + span.shrink_to_lo() + } + fn after(&mut self, span: Self::Span) -> Self::Span { + span.shrink_to_hi() + } fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { let self_loc = self.sess.source_map().lookup_char_pos(first.lo()); let other_loc = self.sess.source_map().lookup_char_pos(second.lo()); diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index a2953b68564a8..d46b8b52df43a 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -160,6 +160,8 @@ macro_rules! with_api { fn source($self: $S::Span) -> $S::Span; fn start($self: $S::Span) -> LineColumn; fn end($self: $S::Span) -> LineColumn; + fn before($self: $S::Span) -> $S::Span; + fn after($self: $S::Span) -> $S::Span; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; fn source_text($self: $S::Span) -> Option; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 3990826ce42e0..b8ed3372aff8b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -358,6 +358,18 @@ impl Span { self.0.end() } + /// Creates an empty span pointing to directly before this span. + #[unstable(feature = "proc_macro_span_shrink", issue = "none")] + pub fn before(&self) -> Span { + Span(self.0.before()) + } + + /// Creates an empty span pointing to directly after this span. + #[unstable(feature = "proc_macro_span_shrink", issue = "none")] + pub fn after(&self) -> Span { + Span(self.0.after()) + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. From f9be6cd8988a48a532c99a9f5b887a6d354e5b2f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 28 Jul 2021 16:34:45 +0200 Subject: [PATCH 02/23] Add tracking issue number to proc_macro_span_shrink. --- library/proc_macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index b8ed3372aff8b..6de61497021ab 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -359,13 +359,13 @@ impl Span { } /// Creates an empty span pointing to directly before this span. - #[unstable(feature = "proc_macro_span_shrink", issue = "none")] + #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] pub fn before(&self) -> Span { Span(self.0.before()) } /// Creates an empty span pointing to directly after this span. - #[unstable(feature = "proc_macro_span_shrink", issue = "none")] + #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] pub fn after(&self) -> Span { Span(self.0.after()) } From f56034ec3e9728881a343683040a97b1386ec34a Mon Sep 17 00:00:00 2001 From: ibraheemdev Date: Sat, 24 Jul 2021 17:34:58 -0400 Subject: [PATCH 03/23] emit suggestion byte literal is passed to `format!` --- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_builtin_macros/src/format.rs | 16 +++++++----- compiler/rustc_expand/src/base.rs | 29 ++++++++++++++++----- src/test/ui/issues/issue-86865.rs | 11 ++++++++ src/test/ui/issues/issue-86865.stderr | 18 +++++++++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/issues/issue-86865.rs create mode 100644 src/test/ui/issues/issue-86865.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index e6afc81d0396a..4500e8c6d1b94 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -412,7 +412,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P template_part, Err(err) => { - if let Some(mut err) = err { + if let Some((mut err, _)) = err { err.emit(); } return DummyResult::raw_expr(sp, true); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 7e88b58c0e29d..215dcabf74c0b 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -946,17 +946,19 @@ pub fn expand_preparsed_format_args( } Ok(fmt) => fmt, Err(err) => { - if let Some(mut err) = err { + if let Some((mut err, suggested)) = err { let sugg_fmt = match args.len() { 0 => "{}".to_string(), _ => format!("{}{{}}", "{} ".repeat(args.len())), }; - err.span_suggestion( - fmt_sp.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{}\", ", sugg_fmt), - Applicability::MaybeIncorrect, - ); + if !suggested { + err.span_suggestion( + fmt_sp.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{}\", ", sugg_fmt), + Applicability::MaybeIncorrect, + ); + } err.emit(); } return DummyResult::raw_expr(sp, true); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index a2035ee3c6ec9..43b94e239eb9f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -9,7 +9,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{DiagnosticBuilder, ErrorReported}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; @@ -1133,13 +1133,15 @@ impl<'a> ExtCtxt<'a> { } /// Extracts a string literal from the macro expanded version of `expr`, -/// emitting `err_msg` if `expr` is not a string literal. This does not stop -/// compilation on error, merely emits a non-fatal error and returns `None`. +/// returning a diagnostic error of `err_msg` if `expr` is not a string literal. +/// The returned bool indicates whether an applicable suggestion has already been +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` +/// indicates that an ast error was encountered. pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P, err_msg: &str, -) -> Result<(Symbol, ast::StrStyle, Span), Option>> { +) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); @@ -1147,14 +1149,27 @@ pub fn expr_to_spanned_string<'a>( Err(match expr.kind { ast::ExprKind::Lit(ref l) => match l.kind { ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), + ast::LitKind::ByteStr(_) => { + let mut err = cx.struct_span_err(l.span, err_msg); + err.span_suggestion( + expr.span.shrink_to_lo(), + "consider removing the leading `b`", + String::new(), + Applicability::MaybeIncorrect, + ); + Some((err, true)) + } ast::LitKind::Err(_) => None, - _ => Some(cx.struct_span_err(l.span, err_msg)), + _ => Some((cx.struct_span_err(l.span, err_msg), false)), }, ast::ExprKind::Err => None, - _ => Some(cx.struct_span_err(expr.span, err_msg)), + _ => Some((cx.struct_span_err(expr.span, err_msg), false)), }) } +/// Extracts a string literal from the macro expanded version of `expr`, +/// emitting `err_msg` if `expr` is not a string literal. This does not stop +/// compilation on error, merely emits a non-fatal error and returns `None`. pub fn expr_to_string( cx: &mut ExtCtxt<'_>, expr: P, @@ -1162,7 +1177,7 @@ pub fn expr_to_string( ) -> Option<(Symbol, ast::StrStyle)> { expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| { - err.map(|mut err| { + err.map(|(mut err, _)| { err.emit(); }) }) diff --git a/src/test/ui/issues/issue-86865.rs b/src/test/ui/issues/issue-86865.rs new file mode 100644 index 0000000000000..01e0a20a5115c --- /dev/null +++ b/src/test/ui/issues/issue-86865.rs @@ -0,0 +1,11 @@ +use std::fmt::Write; + +fn main() { + println!(b"foo"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` + let mut s = String::new(); + write!(s, b"foo{}", "bar"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` +} diff --git a/src/test/ui/issues/issue-86865.stderr b/src/test/ui/issues/issue-86865.stderr new file mode 100644 index 0000000000000..eed755366311b --- /dev/null +++ b/src/test/ui/issues/issue-86865.stderr @@ -0,0 +1,18 @@ +error: format argument must be a string literal + --> $DIR/issue-86865.rs:4:14 + | +LL | println!(b"foo"); + | -^^^^^ + | | + | help: consider removing the leading `b` + +error: format argument must be a string literal + --> $DIR/issue-86865.rs:8:15 + | +LL | write!(s, b"foo{}", "bar"); + | -^^^^^^^ + | | + | help: consider removing the leading `b` + +error: aborting due to 2 previous errors + From 733bdd079a3c09aa3baa47ad65ae134f07b9dbcd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 1 Sep 2021 20:07:56 -0700 Subject: [PATCH 04/23] fix(rustc): suggest `items` be borrowed in `for i in items[x..]` Fixes #87994 --- .../src/traits/error_reporting/suggestions.rs | 17 +++++++-- src/test/ui/suggestions/slice-issue-87994.rs | 7 ++++ .../ui/suggestions/slice-issue-87994.stderr | 37 +++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/suggestions/slice-issue-87994.rs create mode 100644 src/test/ui/suggestions/slice-issue-87994.stderr 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 db3432b01422f..608add1d91c9f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::fmt; @@ -680,7 +680,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { points_at_arg: bool, has_custom_message: bool, ) -> bool { - if !points_at_arg { + let span = obligation.cause.span; + let points_at_for_iter = matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + + if !points_at_arg && !points_at_for_iter { return false; } @@ -695,7 +701,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::send_trait).unwrap()); - let span = obligation.cause.span; let param_env = obligation.param_env; let trait_ref = trait_ref.skip_binder(); @@ -754,7 +759,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); // This if is to prevent a special edge-case - if !span.from_expansion() { + if matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Root + | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ) { // We don't want a borrowing suggestion on the fields in structs, // ``` // struct Foo { diff --git a/src/test/ui/suggestions/slice-issue-87994.rs b/src/test/ui/suggestions/slice-issue-87994.rs new file mode 100644 index 0000000000000..98a936ab2fdd5 --- /dev/null +++ b/src/test/ui/suggestions/slice-issue-87994.rs @@ -0,0 +1,7 @@ +fn main() { + let v = vec![1i32, 2, 3]; + for _ in v[1..] { + //~^ ERROR [i32]` is not an iterator [E0277] + //~^^ ERROR known at compilation time + } +} diff --git a/src/test/ui/suggestions/slice-issue-87994.stderr b/src/test/ui/suggestions/slice-issue-87994.stderr new file mode 100644 index 0000000000000..0c69bec22109b --- /dev/null +++ b/src/test/ui/suggestions/slice-issue-87994.stderr @@ -0,0 +1,37 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/slice-issue-87994.rs:3:12 + | +LL | for _ in v[1..] { + | ^^^^^^ + | | + | expected an implementor of trait `IntoIterator` + | help: consider borrowing here: `&v[1..]` + | + = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `[i32]` is not an iterator + --> $DIR/slice-issue-87994.rs:3:12 + | +LL | for _ in v[1..] { + | ^^^^^^ + | | + | expected an implementor of trait `IntoIterator` + | help: consider borrowing here: `&v[1..]` + | + = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From f23003dff12fdb6c3ba09a55b1323cd2692e50d1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 1 Sep 2021 20:39:11 -0700 Subject: [PATCH 05/23] fix(test): update with `&mut` suggestion --- src/test/ui/issues/issue-20605.stderr | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 25a90df45613b..ce3ab6b599864 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -2,9 +2,12 @@ error[E0277]: the size for values of type `dyn Iterator` cann --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } - | ^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^ + | | + | expected an implementor of trait `IntoIterator` + | help: consider mutably borrowing here: `&mut *things` | - = help: the trait `Sized` is not implemented for `dyn Iterator` + = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator` note: required by `into_iter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL From 208a5fd322c6271c1d98b7a80d0d3f9b634494ae Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 3 Sep 2021 17:10:52 -0700 Subject: [PATCH 06/23] Use `summary_opts()` for Markdown summaries It was accidentally changed to use `opts()` in #86451. I also renamed `opts()` to `main_body_opts()` to make this kind of accidental change less likely. --- src/librustdoc/html/markdown.rs | 17 +++++++++-------- src/librustdoc/passes/bare_urls.rs | 4 ++-- src/librustdoc/passes/html_tags.rs | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index aa3723eddfcce..ae2a5ac440357 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -48,7 +48,7 @@ use pulldown_cmark::{ mod tests; /// Options for rendering Markdown in the main body of documentation. -pub(crate) fn opts() -> Options { +pub(crate) fn main_body_opts() -> Options { Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH @@ -56,7 +56,7 @@ pub(crate) fn opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } -/// A subset of [`opts()`] used for rendering summaries. +/// A subset of [`main_body_opts()`] used for rendering summaries. pub(crate) fn summary_opts() -> Options { Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES } @@ -975,7 +975,7 @@ impl Markdown<'_> { } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer)); let p = p.into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -994,7 +994,7 @@ impl MarkdownWithToc<'_> { crate fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -1019,7 +1019,7 @@ impl MarkdownHtml<'_> { if md.is_empty() { return String::new(); } - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { @@ -1093,7 +1093,7 @@ fn markdown_summary_with_limit( } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); let mut p = LinkReplacer::new(p, link_names); let mut buf = HtmlWithLimit::new(length_limit); @@ -1240,7 +1240,8 @@ crate fn markdown_links(md: &str) -> Vec { }); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)).into_offset_iter(); + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) + .into_offset_iter(); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -1279,7 +1280,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec DocFolder for BareUrlsLinter<'a, 'tcx> { }); }; - let mut p = Parser::new_ext(&dox, opts()).into_offset_iter(); + let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); while let Some((event, range)) = p.next() { match event { diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index f29d38e3e078a..a0144a5298eba 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -2,7 +2,7 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::opts; +use crate::html::markdown::main_body_opts; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use std::iter::Peekable; @@ -192,7 +192,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { let mut is_in_comment = None; let mut in_code_block = false; - let p = Parser::new_ext(&dox, opts()).into_offset_iter(); + let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); for (event, range) in p { match event { From 2cc7b7c5f243713c72114168890ba46dd0c6e4ce Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 3 Sep 2021 17:17:24 -0700 Subject: [PATCH 07/23] Enable all main body Markdown options for summaries This fixes odd renderings when these features are used in the first paragraph of documentation for an item. This is an extension of #87270. --- src/librustdoc/html/markdown.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ae2a5ac440357..a5938149c1f9d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -56,9 +56,13 @@ pub(crate) fn main_body_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } -/// A subset of [`main_body_opts()`] used for rendering summaries. +/// Options for rendering Markdown in summaries (e.g., in search results). pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES + Options::ENABLE_TABLES + | Options::ENABLE_FOOTNOTES + | Options::ENABLE_STRIKETHROUGH + | Options::ENABLE_TASKLISTS + | Options::ENABLE_SMART_PUNCTUATION } /// When `to_string` is called, this struct will emit the HTML corresponding to From bfb2b02d61a36489d03664636c6a4b3585e29fd5 Mon Sep 17 00:00:00 2001 From: kraktus <56031107+kraktus@users.noreply.github.com> Date: Sun, 5 Sep 2021 17:23:58 +0200 Subject: [PATCH 08/23] Tweak `write_fmt` doc. Previous version wrongly used `but` while the two parts of the sentence are not contradicting but completing with each other. --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e8466fa06b899..4a35d36a9def7 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1611,7 +1611,7 @@ pub trait Write { /// encountered. /// /// This method is primarily used to interface with the - /// [`format_args!()`] macro, but it is rare that this should + /// [`format_args!()`] macro, and it is rare that this should /// explicitly be called. The [`write!()`] macro should be favored to /// invoke this method instead. /// From 4a915ac8d9f33567b77b23e90557f92860aa6db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gardstr=C3=B6m?= Date: Sat, 4 Sep 2021 13:26:07 +0200 Subject: [PATCH 09/23] fix ICE on hidden tuple variant fields this also renders them as `_`, which rustdoc previously did not. --- src/librustdoc/html/render/print_item.rs | 51 +++++++++++++----------- src/test/rustdoc/issue-88600.rs | 34 ++++++++++++++++ 2 files changed, 61 insertions(+), 24 deletions(-) create mode 100644 src/test/rustdoc/issue-88600.rs diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 39ef641a3ace2..023e47719778b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -942,15 +942,15 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni } fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) { - for (i, ty) in s - .iter() - .map(|f| if let clean::StructFieldItem(ref ty) = *f.kind { ty } else { unreachable!() }) - .enumerate() - { + for (i, ty) in s.iter().enumerate() { if i > 0 { w.write_str(", "); } - write!(w, "{}", ty.print(cx)); + match *ty.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"), + clean::StructFieldItem(ref ty) => write!(w, "{}", ty.print(cx)), + _ => unreachable!(), + } } } @@ -1066,24 +1066,27 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum name = variant.name.as_ref().unwrap(), ); for field in fields { - use crate::clean::StructFieldItem; - if let StructFieldItem(ref ty) = *field.kind { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.as_ref().unwrap(), - field.name.as_ref().unwrap() - )); - write!( - w, - "\ - \ - {f}: {t}\ - ", - id = id, - f = field.name.as_ref().unwrap(), - t = ty.print(cx) - ); - document(w, cx, field, Some(variant)); + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.as_ref().unwrap(), + field.name.as_ref().unwrap() + )); + write!( + w, + "\ + \ + {f}: {t}\ + ", + id = id, + f = field.name.as_ref().unwrap(), + t = ty.print(cx) + ); + document(w, cx, field, Some(variant)); + } + _ => unreachable!(), } } w.write_str(""); diff --git a/src/test/rustdoc/issue-88600.rs b/src/test/rustdoc/issue-88600.rs new file mode 100644 index 0000000000000..3761805b48b71 --- /dev/null +++ b/src/test/rustdoc/issue-88600.rs @@ -0,0 +1,34 @@ +// This test ensure that #[doc(hidden)] is applied correctly in enum variant fields. + +// Denotes a field which should be hidden. +pub struct H; + +// Denotes a field which should not be hidden (shown). +pub struct S; + +// @has issue_88600/enum.FooEnum.html +pub enum FooEnum { + // @has - '//*[@id="variant.HiddenTupleItem"]//code' 'HiddenTupleItem(_)' + // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0 + HiddenTupleItem(#[doc(hidden)] H), + // @has - '//*[@id="variant.MultipleHidden"]//code' 'MultipleHidden(_, _)' + // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0 + // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0 + MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H), + // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)' + // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0 + // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S' + MixedHiddenFirst(#[doc(hidden)] H, S), + // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)' + // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S' + // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0 + MixedHiddenLast(S, #[doc(hidden)] H), + // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct' + // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0 + // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S' + HiddenStruct { + #[doc(hidden)] + h: H, + s: S, + }, +} From d6ff916c2fe6a47f52fc14e4f6d85e92d07e5e76 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 7 Sep 2021 00:49:43 -0700 Subject: [PATCH 10/23] test: add case for mutating iterator Note that this incorrectly suggests a shared borrow, but at least we know it's happening. --- src/test/ui/suggestions/slice-issue-87994.rs | 9 +++++ .../ui/suggestions/slice-issue-87994.stderr | 36 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/test/ui/suggestions/slice-issue-87994.rs b/src/test/ui/suggestions/slice-issue-87994.rs index 98a936ab2fdd5..ecb7f54ea250a 100644 --- a/src/test/ui/suggestions/slice-issue-87994.rs +++ b/src/test/ui/suggestions/slice-issue-87994.rs @@ -4,4 +4,13 @@ fn main() { //~^ ERROR [i32]` is not an iterator [E0277] //~^^ ERROR known at compilation time } + struct K { + n: i32, + } + let mut v2 = vec![K { n: 1 }, K { n: 1 }, K { n: 1 }]; + for i2 in v2[1..] { + //~^ ERROR [K]` is not an iterator [E0277] + //~^^ ERROR known at compilation time + i2.n = 2; + } } diff --git a/src/test/ui/suggestions/slice-issue-87994.stderr b/src/test/ui/suggestions/slice-issue-87994.stderr index 0c69bec22109b..018f62e783daf 100644 --- a/src/test/ui/suggestions/slice-issue-87994.stderr +++ b/src/test/ui/suggestions/slice-issue-87994.stderr @@ -32,6 +32,40 @@ note: required by `into_iter` LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0277]: the size for values of type `[K]` cannot be known at compilation time + --> $DIR/slice-issue-87994.rs:11:13 + | +LL | for i2 in v2[1..] { + | ^^^^^^^ + | | + | expected an implementor of trait `IntoIterator` + | help: consider borrowing here: `&v2[1..]` + | + = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[K]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `[K]` is not an iterator + --> $DIR/slice-issue-87994.rs:11:13 + | +LL | for i2 in v2[1..] { + | ^^^^^^^ + | | + | expected an implementor of trait `IntoIterator` + | help: consider borrowing here: `&v2[1..]` + | + = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[K]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From 532bb80f7fd22bbc9896d9233f2a9ed79071716c Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 7 Sep 2021 14:49:03 -0400 Subject: [PATCH 11/23] RustWrapper: avoid deleted unclear attribute methods These were deleted in https://reviews.llvm.org/D108614, and in C++ I definitely see the argument for their removal. I didn't try and propagate the changes up into higher layers of rustc in this change because my initial goal was to get rustc working against LLVM HEAD promptly, but I'm happy to follow up with some refactoring to make the API on the Rust side match the LLVM API more directly (though the way the enum works in Rust makes the API less scary IMO). r? @nagisa cc @nikic --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 88 +++++++++++++++---- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 4f07a0c67c13f..b3143f14d29cc 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -203,20 +203,59 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { report_fatal_error("bad AttributeKind"); } +template static inline void AddAttribute(T *t, unsigned Index, Attribute Attr) { +#if LLVM_VERSION_LT(14, 0) + t->addAttribute(Index, Attr); +#else + // TODO(durin42): we should probably surface the explicit functions to Rust + // instead of this switch statement? + switch (Index) { + case AttributeList::ReturnIndex: + t->addRetAttr(Attr); + break; + case AttributeList::FunctionIndex: + t->addFnAttr(Attr); + break; + default: + t->addParamAttr(Index-AttributeList::FirstArgIndex, Attr); + } +#endif +} + extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index, LLVMRustAttribute RustAttr) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr)); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index, const char *Name) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::get(Call->getContext(), Name); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } +static inline void AddCallAttributes(CallBase *Call, unsigned Index, const AttrBuilder& B) { + AttributeList Attrs = Call->getAttributes(); +#if LLVM_VERSION_LT(14, 0) + Attrs = Attrs.addAttributes(Call->getContext(), Index, B); +#else + // TODO(durin42): we should probably surface the explicit functions to Rust + // instead of this switch statement? + switch (Index) { + case AttributeList::ReturnIndex: + Attrs = Attrs.addRetAttributes(Call->getContext(), B); + break; + case AttributeList::FunctionIndex: + Attrs = Attrs.addFnAttributes(Call->getContext(), B); + break; + default: + Attrs = Attrs.addParamAttributes(Call->getContext(), Index-AttributeList::FirstArgIndex, B); + } +#endif + Call->setAttributes(Attrs); +} extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, unsigned Index, @@ -224,8 +263,7 @@ extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, CallBase *Call = unwrap(Instr); AttrBuilder B; B.addAlignmentAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + AddCallAttributes(Call, Index, B); } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, @@ -234,8 +272,7 @@ extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, CallBase *Call = unwrap(Instr); AttrBuilder B; B.addDereferenceableAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + AddCallAttributes(Call, Index, B); } extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, @@ -244,15 +281,14 @@ extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, CallBase *Call = unwrap(Instr); AttrBuilder B; B.addDereferenceableOrNullAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + AddCallAttributes(Call, Index, B); } extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, LLVMTypeRef Ty) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty)); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index, @@ -263,28 +299,28 @@ extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned In #else Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet); #endif - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, LLVMRustAttribute RustAttr) { Function *A = unwrap(Fn); Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr)); - A->addAttribute(Index, Attr); + AddAttribute(A, Index, Attr); } extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn, unsigned Index, uint32_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithAlignment( + AddAttribute(A, Index, Attribute::getWithAlignment( A->getContext(), llvm::Align(Bytes))); } extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, uint64_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(), + AddAttribute(A, Index, Attribute::getWithDereferenceableBytes(A->getContext(), Bytes)); } @@ -292,7 +328,7 @@ extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn, unsigned Index, uint64_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes( + AddAttribute(A, Index, Attribute::getWithDereferenceableOrNullBytes( A->getContext(), Bytes)); } @@ -300,7 +336,7 @@ extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index, LLVMTypeRef Ty) { Function *F = unwrap(Fn); Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty)); - F->addAttribute(Index, Attr); + AddAttribute(F, Index, Attr); } extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index, @@ -311,7 +347,7 @@ extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index, #else Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet); #endif - F->addAttribute(Index, Attr); + AddAttribute(F, Index, Attr); } extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, @@ -319,7 +355,7 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, const char *Name, const char *Value) { Function *F = unwrap(Fn); - F->addAttribute(Index, Attribute::get( + AddAttribute(F, Index, Attribute::get( F->getContext(), StringRef(Name), StringRef(Value))); } @@ -330,7 +366,23 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); AttrBuilder B(Attr); auto PAL = F->getAttributes(); - auto PALNew = PAL.removeAttributes(F->getContext(), Index, B); + AttributeList PALNew; +#if LLVM_VERSION_LT(14, 0) + PALNew = PAL.removeAttributes(F->getContext(), Index, B); +#else + // TODO(durin42): we should probably surface the explicit functions to Rust + // instead of this switch statement? + switch (Index) { + case AttributeList::ReturnIndex: + PALNew = PAL.removeRetAttributes(F->getContext(), B); + break; + case AttributeList::FunctionIndex: + PALNew = PAL.removeFnAttributes(F->getContext(), B); + break; + default: + PALNew = PAL.removeParamAttributes(F->getContext(), Index-AttributeList::FirstArgIndex, B); + } +#endif F->setAttributes(PALNew); } From 484b79b950b1077d1bbfe6c4edf3bfe070d820b4 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 7 Sep 2021 16:15:02 -0400 Subject: [PATCH 12/23] RustWrapper: just use the *AtIndex funcs directly Otherwise we're kind of reimplementing the inverse of the well-named methods, and that's not a direction we want to go. --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 39 ++----------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b3143f14d29cc..3a7af73c87de3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -207,18 +207,7 @@ template static inline void AddAttribute(T *t, unsigned Index, Attri #if LLVM_VERSION_LT(14, 0) t->addAttribute(Index, Attr); #else - // TODO(durin42): we should probably surface the explicit functions to Rust - // instead of this switch statement? - switch (Index) { - case AttributeList::ReturnIndex: - t->addRetAttr(Attr); - break; - case AttributeList::FunctionIndex: - t->addFnAttr(Attr); - break; - default: - t->addParamAttr(Index-AttributeList::FirstArgIndex, Attr); - } + t->addAttributeAtIndex(Index, Attr); #endif } @@ -241,18 +230,7 @@ static inline void AddCallAttributes(CallBase *Call, unsigned Index, const AttrB #if LLVM_VERSION_LT(14, 0) Attrs = Attrs.addAttributes(Call->getContext(), Index, B); #else - // TODO(durin42): we should probably surface the explicit functions to Rust - // instead of this switch statement? - switch (Index) { - case AttributeList::ReturnIndex: - Attrs = Attrs.addRetAttributes(Call->getContext(), B); - break; - case AttributeList::FunctionIndex: - Attrs = Attrs.addFnAttributes(Call->getContext(), B); - break; - default: - Attrs = Attrs.addParamAttributes(Call->getContext(), Index-AttributeList::FirstArgIndex, B); - } + Attrs = Attrs.addAttributesAtIndex(Call->getContext(), Index, B); #endif Call->setAttributes(Attrs); } @@ -370,18 +348,7 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, #if LLVM_VERSION_LT(14, 0) PALNew = PAL.removeAttributes(F->getContext(), Index, B); #else - // TODO(durin42): we should probably surface the explicit functions to Rust - // instead of this switch statement? - switch (Index) { - case AttributeList::ReturnIndex: - PALNew = PAL.removeRetAttributes(F->getContext(), B); - break; - case AttributeList::FunctionIndex: - PALNew = PAL.removeFnAttributes(F->getContext(), B); - break; - default: - PALNew = PAL.removeParamAttributes(F->getContext(), Index-AttributeList::FirstArgIndex, B); - } + PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B); #endif F->setAttributes(PALNew); } From 32188d77ed8671f280722f72555c34d1bd096a86 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Sep 2021 15:08:11 +0200 Subject: [PATCH 13/23] Wrap elements into
to prevent breaking layout and width --- src/librustdoc/html/markdown.rs | 43 +++++++++++++++++++++- src/librustdoc/html/render/print_item.rs | 3 +- src/librustdoc/html/static/css/rustdoc.css | 5 +++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index aa3723eddfcce..bb2bc5008e340 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -441,6 +441,42 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } } +/// Wrap HTML tables into `
` to prevent having the doc blocks width being too big. +struct TableWrapper<'a, I: Iterator>> { + inner: I, + stored_events: VecDeque>, +} + +impl<'a, I: Iterator>> TableWrapper<'a, I> { + fn new(iter: I) -> Self { + Self { inner: iter, stored_events: VecDeque::new() } + } +} + +impl<'a, I: Iterator>> Iterator for TableWrapper<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option { + if let Some(first) = self.stored_events.pop_front() { + return Some(first); + } + + let event = self.inner.next()?; + + Some(match event { + Event::Start(Tag::Table(t)) => { + self.stored_events.push_back(Event::Start(Tag::Table(t))); + Event::Html(CowStr::Borrowed("
")) + } + Event::End(Tag::Table(t)) => { + self.stored_events.push_back(Event::Html(CowStr::Borrowed("
"))); + Event::End(Tag::Table(t)) + } + e => e, + }) + } +} + type SpannedEvent<'a> = (Event<'a>, Range); /// Make headings links with anchor IDs and build up TOC. @@ -983,6 +1019,7 @@ impl Markdown<'_> { let p = HeadingLinks::new(p, None, &mut ids); let p = Footnotes::new(p); let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); + let p = TableWrapper::new(p); let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); @@ -1003,7 +1040,8 @@ impl MarkdownWithToc<'_> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); + let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); } @@ -1031,7 +1069,8 @@ impl MarkdownHtml<'_> { let p = HeadingLinks::new(p, None, &mut ids); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); + let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); s diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 39ef641a3ace2..6da60533b1ccd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -273,7 +273,8 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl write!( w, "

\ - {name}

\n{}", + {name}\ + \n{}", ITEM_TABLE_OPEN, id = cx.derive_id(short.to_owned()), name = name diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 23ca6eeaf3bb9..2d4bfc62af68e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -522,6 +522,11 @@ nav.sub { position: relative; } +.docblock > * { + max-width: 100%; + overflow-x: auto; +} + .content .out-of-band { flex-grow: 0; text-align: right; From 021b8ff8bd3d351f098847c3507ffb2c6c722aa3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Sep 2021 15:09:47 +0200 Subject: [PATCH 14/23] Add tests to ensure that
don't break doc blocks width anymore --- .../rustdoc-gui/docblock-table-overflow.goml | 8 ++++++++ src/test/rustdoc-gui/src/lib2/lib.rs | 9 +++++++++ src/test/rustdoc/table-in-docblock.rs | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 src/test/rustdoc/table-in-docblock.rs diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml index 9ab7cd0fa07b0..10f516d2dae06 100644 --- a/src/test/rustdoc-gui/docblock-table-overflow.goml +++ b/src/test/rustdoc-gui/docblock-table-overflow.goml @@ -7,3 +7,11 @@ compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["sc assert-property: (".top-doc .docblock", {"scrollWidth": "816"}) // However, since there is overflow in the
, its scroll width is bigger. assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"}) + +// Checking it works on other doc blocks as well... + +// Logically, the ".docblock" and the "

" should have the same scroll width. +compare-elements-property: ("#implementations + details .docblock", "#implementations + details .docblock > p", ["scrollWidth"]) +assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"}) +// However, since there is overflow in the

, its scroll width is bigger. +assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"}) diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index cb63a9f600227..d5835b78d2fcf 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -67,6 +67,15 @@ pub mod long_table { /// /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq pub struct Foo; + + /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | + /// | ----------- | ----------- | ----------- | ----------- | + /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | + /// + /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq + impl Foo { + pub fn foo(&self) {} + } } pub mod summary_table { diff --git a/src/test/rustdoc/table-in-docblock.rs b/src/test/rustdoc/table-in-docblock.rs new file mode 100644 index 0000000000000..858b589196e72 --- /dev/null +++ b/src/test/rustdoc/table-in-docblock.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @count - '//*[@class="docblock"]/div/table' 2 +// @!has - '//*[@class="docblock"]/table' +/// | hello | hello2 | +/// | ----- | ------ | +/// | data | data2 | +pub struct Foo; + +impl Foo { + /// | hello | hello2 | + /// | ----- | ------ | + /// | data | data2 | + pub fn foo(&self) {} +} From 4d045406d1ee4c011e476fbeae81976c8012e886 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 8 Sep 2021 10:47:41 -0400 Subject: [PATCH 15/23] RustWrapper: remove some uses of AttrBuilder Turns out we can also use Attribute::get*() methods here, and avoid the AttrBuilder and an extra helper method here. --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3a7af73c87de3..9850f395a0f65 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -225,41 +225,28 @@ extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index AddAttribute(Call, Index, Attr); } -static inline void AddCallAttributes(CallBase *Call, unsigned Index, const AttrBuilder& B) { - AttributeList Attrs = Call->getAttributes(); -#if LLVM_VERSION_LT(14, 0) - Attrs = Attrs.addAttributes(Call->getContext(), Index, B); -#else - Attrs = Attrs.addAttributesAtIndex(Call->getContext(), Index, B); -#endif - Call->setAttributes(Attrs); -} - extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint32_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addAlignmentAttr(Bytes); - AddCallAttributes(Call, Index, B); + Attribute Attr = Attribute::getWithAlignment(Call->getContext(), Align(Bytes)); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addDereferenceableAttr(Bytes); - AddCallAttributes(Call, Index, B); + Attribute Attr = Attribute::getWithDereferenceableBytes(Call->getContext(), Bytes); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addDereferenceableOrNullAttr(Bytes); - AddCallAttributes(Call, Index, B); + Attribute Attr = Attribute::getWithDereferenceableOrNullBytes(Call->getContext(), Bytes); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, From 0bf16af5f331079b1da91849ed0eb083b9b8e5f2 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Thu, 9 Sep 2021 15:11:02 +0200 Subject: [PATCH 16/23] Workaround blink/chromium grid layout limitation of 1000 rows See https://github.com/rust-lang/rust/issues/88545 for more details --- src/librustdoc/html/render/print_item.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 470749ef7b338..431bc2b51256a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -256,6 +256,10 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl debug!("{:?}", indices); let mut curty = None; + // See: https://github.com/rust-lang/rust/issues/88545 + let item_table_block_size = 900usize; + let mut item_table_nth_element = 0usize; + for &idx in &indices { let myitem = &items[idx]; if myitem.is_stripped() { @@ -280,6 +284,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl id = cx.derive_id(short.to_owned()), name = name ); + item_table_nth_element = 0; } match *myitem.kind { @@ -386,6 +391,13 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl ); } } + + item_table_nth_element += 1; + if item_table_nth_element > item_table_block_size { + w.write_str(ITEM_TABLE_CLOSE); + w.write_str(ITEM_TABLE_OPEN); + item_table_nth_element = 0; + } } if curty.is_some() { From b21425de3c6be4264b875e68c8a28b424c27b8c4 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Mon, 16 Aug 2021 15:22:36 +0200 Subject: [PATCH 17/23] Emit proper errors on missing closure braces This commit focuses on emitting clean errors for the following syntax error: ``` Some(42).map(|a| dbg!(a); a ); ``` Previous implementation tried to recover after parsing the closure body (the `dbg` expression) by replacing the next `;` with a `,`, which made the next expression belong to the next function argument. As such, the following errors were emitted (among others): - the semicolon token was not expected, - a is not in scope, - Option::map is supposed to take one argument, not two. This commit allows us to gracefully handle this situation by adding giving the parser the ability to remember when it has just parsed a closure body inside a function call. When this happens, we can treat the unexpected `;` specifically and try to parse as much statements as possible in order to eat the whole block. When we can't parse statements anymore, we generate a clean error indicating that the braces are missing, and return an ExprKind::Err. --- compiler/rustc_parse/src/parser/expr.rs | 30 ++++- compiler/rustc_parse/src/parser/mod.rs | 103 +++++++++++++++++- .../missing_braces_around_block.fixed | 19 ++++ .../missing_braces_around_block.rs | 19 ++++ .../missing_braces_around_block.stderr | 38 +++++++ .../malformed_closure/ruby_style_closure.rs | 16 +++ .../ruby_style_closure.stderr | 18 +++ 7 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed create mode 100644 src/test/ui/expr/malformed_closure/missing_braces_around_block.rs create mode 100644 src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr create mode 100644 src/test/ui/expr/malformed_closure/ruby_style_closure.rs create mode 100644 src/test/ui/expr/malformed_closure/ruby_style_closure.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 05156745105a1..dc80dab8c6c5f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,9 +1,12 @@ use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; -use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType}; +use super::{ + AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType, +}; use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken}; use crate::maybe_recover_from_interpolated_ty_qpath; +use ast::token::DelimToken; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::Spacing; @@ -91,6 +94,8 @@ impl<'a> Parser<'a> { /// Parses an expression. #[inline] pub fn parse_expr(&mut self) -> PResult<'a, P> { + self.current_closure.take(); + self.parse_expr_res(Restrictions::empty(), None) } @@ -1736,7 +1741,7 @@ impl<'a> Parser<'a> { let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; - let body = match decl.output { + let mut body = match decl.output { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR; self.parse_expr_res(restrictions, None)? @@ -1753,11 +1758,28 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - Ok(self.mk_expr( + if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren + { + // It is likely that the closure body is a block but where the + // braces have been removed. We will recover and eat the next + // statements later in the parsing process. + body = self.mk_expr_err(body.span); + } + + let body_span = body.span; + + let closure = self.mk_expr( lo.to(body.span), ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), attrs, - )) + ); + + // Disable recovery for closure body + let spans = + ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span }; + self.current_closure = Some(spans); + + Ok(closure) } /// Parses an optional `move` prefix to a closure-like construct. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c4419e995edac..5c701fefd17de 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -142,6 +142,17 @@ pub struct Parser<'a> { /// If present, this `Parser` is not parsing Rust code but rather a macro call. subparser_name: Option<&'static str>, capture_state: CaptureState, + /// This allows us to recover when the user forget to add braces around + /// multiple statements in the closure body. + pub current_closure: Option, +} + +/// Stores span informations about a closure. +#[derive(Clone)] +pub struct ClosureSpans { + pub whole_closure: Span, + pub closing_pipe: Span, + pub body: Span, } /// Indicates a range of tokens that should be replaced by @@ -440,6 +451,7 @@ impl<'a> Parser<'a> { replace_ranges: Vec::new(), inner_attr_ranges: Default::default(), }, + current_closure: None, }; // Make parser point to the first token. @@ -761,8 +773,11 @@ impl<'a> Parser<'a> { first = false; } else { match self.expect(t) { - Ok(false) => {} + Ok(false) => { + self.current_closure.take(); + } Ok(true) => { + self.current_closure.take(); recovered = true; break; } @@ -770,10 +785,29 @@ impl<'a> Parser<'a> { let sp = self.prev_token.span.shrink_to_hi(); let token_str = pprust::token_kind_to_string(t); - // Attempt to keep parsing if it was a similar separator. - if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token.kind) && !unclosed_delims { - self.bump(); + match self.current_closure.take() { + Some(closure_spans) if self.token.kind == TokenKind::Semi => { + // Finding a semicolon instead of a comma + // after a closure body indicates that the + // closure body may be a block but the user + // forgot to put braces around its + // statements. + + self.recover_missing_braces_around_closure_body( + closure_spans, + expect_err, + )?; + + continue; + } + + _ => { + // Attempt to keep parsing if it was a similar separator. + if let Some(ref tokens) = t.similar_tokens() { + if tokens.contains(&self.token.kind) && !unclosed_delims { + self.bump(); + } + } } } @@ -839,6 +873,65 @@ impl<'a> Parser<'a> { Ok((v, trailing, recovered)) } + fn recover_missing_braces_around_closure_body( + &mut self, + closure_spans: ClosureSpans, + mut expect_err: DiagnosticBuilder<'_>, + ) -> PResult<'a, ()> { + let initial_semicolon = self.token.span; + + while self.eat(&TokenKind::Semi) { + let _ = self.parse_stmt(ForceCollect::Yes)?; + } + + expect_err.set_primary_message( + "closure bodies that contain statements must be surrounded by braces", + ); + + let preceding_pipe_span = closure_spans.closing_pipe; + let following_token_span = self.token.span; + + let mut first_note = MultiSpan::from(vec![initial_semicolon]); + first_note.push_span_label( + initial_semicolon, + "this `;` turns the preceding closure into a statement".to_string(), + ); + first_note.push_span_label( + closure_spans.body, + "this expression is a statement because of the trailing semicolon".to_string(), + ); + expect_err.span_note(first_note, "statement found outside of a block"); + + let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]); + second_note.push_span_label( + closure_spans.whole_closure, + "this is the parsed closure...".to_string(), + ); + second_note.push_span_label( + following_token_span, + "...but likely you meant the closure to end here".to_string(), + ); + expect_err.span_note(second_note, "the closure body may be incorrectly delimited"); + + expect_err.set_span(vec![preceding_pipe_span, following_token_span]); + + let opening_suggestion_str = " {".to_string(); + let closing_suggestion_str = "}".to_string(); + + expect_err.multipart_suggestion( + "try adding braces", + vec![ + (preceding_pipe_span.shrink_to_hi(), opening_suggestion_str), + (following_token_span.shrink_to_lo(), closing_suggestion_str), + ], + Applicability::MaybeIncorrect, + ); + + expect_err.emit(); + + Ok(()) + } + /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. diff --git a/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed b/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed new file mode 100644 index 0000000000000..c50b9a12b6d44 --- /dev/null +++ b/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed @@ -0,0 +1,19 @@ +// This snippet ensures that no attempt to recover on a semicolon instead of +// comma is made next to a closure body. +// +// If this recovery happens, then plenty of errors are emitted. Here, we expect +// only one error. +// +// This is part of issue #88065: +// https://github.com/rust-lang/rust/issues/88065 + +// run-rustfix + +fn main() { + let num = 5; + (1..num).reduce(|a, b| { + //~^ ERROR: closure bodies that contain statements must be surrounded by braces + println!("{}", a); + a * b + }).unwrap(); +} diff --git a/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs b/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs new file mode 100644 index 0000000000000..58c81f3a6e2a9 --- /dev/null +++ b/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs @@ -0,0 +1,19 @@ +// This snippet ensures that no attempt to recover on a semicolon instead of +// comma is made next to a closure body. +// +// If this recovery happens, then plenty of errors are emitted. Here, we expect +// only one error. +// +// This is part of issue #88065: +// https://github.com/rust-lang/rust/issues/88065 + +// run-rustfix + +fn main() { + let num = 5; + (1..num).reduce(|a, b| + //~^ ERROR: closure bodies that contain statements must be surrounded by braces + println!("{}", a); + a * b + ).unwrap(); +} diff --git a/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr b/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr new file mode 100644 index 0000000000000..dac9a8cfc69d4 --- /dev/null +++ b/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr @@ -0,0 +1,38 @@ +error: closure bodies that contain statements must be surrounded by braces + --> $DIR/missing_braces_around_block.rs:14:26 + | +LL | (1..num).reduce(|a, b| + | ^ +... +LL | ).unwrap(); + | ^ + | +note: statement found outside of a block + --> $DIR/missing_braces_around_block.rs:16:26 + | +LL | println!("{}", a); + | -----------------^ this `;` turns the preceding closure into a statement + | | + | this expression is a statement because of the trailing semicolon +note: the closure body may be incorrectly delimited + --> $DIR/missing_braces_around_block.rs:14:21 + | +LL | (1..num).reduce(|a, b| + | _____________________^ +LL | | +LL | | println!("{}", a); + | |_________________________^ this is the parsed closure... +LL | a * b +LL | ).unwrap(); + | - ...but likely you meant the closure to end here +help: try adding braces + | +LL ~ (1..num).reduce(|a, b| { +LL | +LL | println!("{}", a); +LL | a * b +LL ~ }).unwrap(); + | + +error: aborting due to previous error + diff --git a/src/test/ui/expr/malformed_closure/ruby_style_closure.rs b/src/test/ui/expr/malformed_closure/ruby_style_closure.rs new file mode 100644 index 0000000000000..e4341e196877b --- /dev/null +++ b/src/test/ui/expr/malformed_closure/ruby_style_closure.rs @@ -0,0 +1,16 @@ +// Part of issue #27300. +// The problem here is that ruby-style closures are parsed as blocks whose +// first statement is a closure. See the issue for more details: +// https://github.com/rust-lang/rust/issues/27300 + +// Note: this test represents what the compiler currently emits. The error +// message will be improved later. + +fn main() { + let p = Some(45).and_then({ + //~^ expected a `FnOnce<({integer},)>` closure, found `Option<_>` + |x| println!("doubling {}", x); + Some(x * 2) + //~^ ERROR: cannot find value `x` in this scope + }); +} diff --git a/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr new file mode 100644 index 0000000000000..99df0632b4c33 --- /dev/null +++ b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/ruby_style_closure.rs:13:14 + | +LL | Some(x * 2) + | ^ not found in this scope + +error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<_>` + --> $DIR/ruby_style_closure.rs:10:22 + | +LL | let p = Some(45).and_then({ + | ^^^^^^^^ expected an `FnOnce<({integer},)>` closure, found `Option<_>` + | + = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. From 79adda930f9b607ecb4819ed7abcf1cd285e938a Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Fri, 21 May 2021 19:35:49 +0200 Subject: [PATCH 18/23] Ignore automatically derived impls of `Clone` and `Debug` in dead code analysis --- compiler/rustc_feature/src/accepted.rs | 1 - compiler/rustc_feature/src/active.rs | 1 - compiler/rustc_feature/src/builtin_attrs.rs | 3 + compiler/rustc_feature/src/lib.rs | 1 - compiler/rustc_feature/src/removed.rs | 2 - .../rustc_middle/src/hir/map/collector.rs | 7 --- compiler/rustc_middle/src/ich/hcx.rs | 2 - .../rustc_mir_build/src/build/matches/mod.rs | 3 - .../src/build/matches/simplify.rs | 13 ++-- compiler/rustc_mir_build/src/build/scope.rs | 4 -- .../rustc_mir_transform/src/coverage/mod.rs | 2 +- compiler/rustc_passes/src/dead.rs | 62 +++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/clone.rs | 1 + library/core/src/fmt/mod.rs | 1 + library/core/tests/fmt/builders.rs | 1 + library/std/src/io/buffered/tests.rs | 4 -- library/test/src/term/terminfo/mod.rs | 1 + src/librustdoc/clean/inline.rs | 2 - src/librustdoc/clean/mod.rs | 1 - src/librustdoc/clean/types.rs | 1 - src/librustdoc/html/render/mod.rs | 2 - .../ui/array-slice-vec/slice_binary_search.rs | 1 + .../ui/borrowck/borrowck-unused-mut-locals.rs | 1 + .../diagnostics/liveness.rs | 1 + .../diagnostics/liveness.stderr | 14 ++--- .../liveness_unintentional_copy.rs | 1 + .../liveness_unintentional_copy.stderr | 6 +- .../struct-pattern-matching-with-methods.rs | 1 + .../run_pass/unsafe_ptr.rs | 2 + src/test/ui/const-generics/broken-mir-2.rs | 3 + src/test/ui/derives/clone-debug-dead-code.rs | 45 ++++++++++++++ .../ui/derives/clone-debug-dead-code.stderr | 38 ++++++++++++ .../deriving/deriving-clone-generic-struct.rs | 2 + src/test/ui/deriving/deriving-clone-struct.rs | 2 + .../deriving/deriving-clone-tuple-struct.rs | 2 + src/test/ui/deriving/deriving-in-fn.rs | 3 + src/test/ui/issues/issue-19358.rs | 3 + src/test/ui/issues/issue-3794.rs | 1 + src/test/ui/monomorphize-abi-alignment.rs | 1 + src/test/ui/moves/move-1-unique.rs | 1 + src/test/ui/moves/move-3-unique.rs | 1 + .../overloaded/overloaded-autoderef-order.rs | 2 + src/test/ui/self/ufcs-explicit-self.rs | 1 + .../class-cast-to-trait-multiple-types.rs | 1 + .../structs-enums/class-implement-traits.rs | 1 + .../ui/structs-enums/functional-struct-upd.rs | 3 + src/test/ui/structs-enums/tag-align-shape.rs | 1 + .../clippy/clippy_lints/src/macro_use.rs | 29 +++------ src/tools/clippy/clippy_lints/src/regex.rs | 8 +-- .../tests/ui/default_trait_access.fixed | 2 +- .../clippy/tests/ui/default_trait_access.rs | 2 +- src/tools/rustfmt/src/macros.rs | 35 ++--------- src/tools/rustfmt/src/modules.rs | 2 - 54 files changed, 225 insertions(+), 107 deletions(-) create mode 100644 src/test/ui/derives/clone-debug-dead-code.rs create mode 100644 src/test/ui/derives/clone-debug-dead-code.stderr diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 725f8b8763af1..61e27d2e4cd41 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -16,7 +16,6 @@ macro_rules! declare_features { since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index a3807a2bb9fde..366ed715434ed 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -37,7 +37,6 @@ macro_rules! declare_features { since: $ver, issue: to_nonzero($issue), edition: $edition, - description: concat!($($doc,)*), } ),+]; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e2aa54a59b202..f74ea0e0c4d27 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -453,6 +453,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Enumerates "identity-like" conversion methods to suggest on type mismatch. rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE), + // Prevents field reads in the marked trait or method to be considered + // during dead code analysis. + rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Const related: diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index cf102aa16e057..b25aab21e491a 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -51,7 +51,6 @@ pub struct Feature { pub since: &'static str, issue: Option, pub edition: Option, - description: &'static str, } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index efab0200ff502..7b9b68268eacd 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -16,7 +16,6 @@ macro_rules! declare_features { since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; @@ -34,7 +33,6 @@ macro_rules! declare_features { since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 1351b4950f143..082948eba416d 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -62,13 +62,6 @@ fn hash_body( stable_hasher.finish() } -/// Represents an entry and its parent `HirId`. -#[derive(Copy, Clone, Debug)] -pub struct Entry<'hir> { - parent: HirId, - node: Node<'hir>, -} - impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn root( sess: &'a Session, diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index 32ccdafaeb48c..1c7e022673d95 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -28,7 +28,6 @@ fn compute_ignored_attr_names() -> FxHashSet { /// things (e.g., each `DefId`/`DefPath` is only hashed once). #[derive(Clone)] pub struct StableHashingContext<'a> { - sess: &'a Session, definitions: &'a Definitions, cstore: &'a dyn CrateStore, pub(super) body_resolver: BodyResolver<'a>, @@ -78,7 +77,6 @@ impl<'a> StableHashingContext<'a> { !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; StableHashingContext { - sess, body_resolver: BodyResolver(krate), definitions, cstore, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ba94e15444a19..0ff3fc60995bf 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -900,10 +900,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( struct Binding<'tcx> { span: Span, source: Place<'tcx>, - name: Symbol, var_id: HirId, - var_ty: Ty<'tcx>, - mutability: Mutability, binding_mode: BindingMode, } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 1feb8b0d7a06d..4ce26cc8dff46 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -176,17 +176,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => { + PatKind::Binding { + name: _, + mutability: _, + mode, + var, + ty: _, + ref subpattern, + is_primary: _, + } => { if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) { candidate.bindings.push(Binding { - name, - mutability, span: match_pair.pattern.span, source: place_resolved.into_place(self.tcx, self.typeck_results), var_id: var, - var_ty: ty, binding_mode: mode, }); } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index bd8d14fcd012c..b74208edafea6 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -118,9 +118,6 @@ struct Scope { /// the region span of this scope within source code. region_scope: region::Scope, - /// the span of that region_scope - region_scope_span: Span, - /// set of places to drop when exiting this scope. This starts /// out empty but grows as variables are declared during the /// building process. This is a stack, so we always drop from the @@ -420,7 +417,6 @@ impl<'tcx> Scopes<'tcx> { self.scopes.push(Scope { source_scope: vis_scope, region_scope: region_scope.0, - region_scope_span: region_scope.1.span, drops: vec![], moved_locals: vec![], cached_unwind_block: None, diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 6043606c37957..b9e3c058ad7ec 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { } if let Err(e) = result { - bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e) + bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) }; // Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 25ad00aaf1f75..0a3093757166a 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -239,7 +239,69 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + /// Automatically generated items marked with `rustc_trivial_field_reads` + /// will be ignored for the purposes of dead code analysis (see PR #85200 + /// for discussion). + fn should_ignore_item(&self, def_id: DefId) -> bool { + if !self.tcx.has_attr(def_id, sym::automatically_derived) + && !self + .tcx + .impl_of_method(def_id) + .map_or(false, |impl_id| self.tcx.has_attr(impl_id, sym::automatically_derived)) + { + return false; + } + + let has_attr = |def_id| self.tcx.has_attr(def_id, sym::rustc_trivial_field_reads); + + if has_attr(def_id) { + return true; + } + + if let Some(impl_of) = self.tcx.impl_of_method(def_id) { + if has_attr(impl_of) { + return true; + } + + if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) { + if has_attr(trait_of) { + return true; + } + + if let Some(method_ident) = self.tcx.opt_item_name(def_id) { + if let Some(trait_method) = self + .tcx + .associated_items(trait_of) + .find_by_name_and_kind(self.tcx, method_ident, ty::AssocKind::Fn, trait_of) + { + if has_attr(trait_method.def_id) { + return true; + } + } + } + } + } else if let Some(trait_of) = self.tcx.trait_of_item(def_id) { + if has_attr(trait_of) { + return true; + } + } + + return false; + } + fn visit_node(&mut self, node: Node<'tcx>) { + if let Some(item_def_id) = match node { + Node::Item(hir::Item { def_id, .. }) + | Node::ForeignItem(hir::ForeignItem { def_id, .. }) + | Node::TraitItem(hir::TraitItem { def_id, .. }) + | Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()), + _ => None, + } { + if self.should_ignore_item(item_def_id) { + return; + } + } + let had_repr_c = self.repr_has_repr_c; let had_inherited_pub_visibility = self.inherited_pub_visibility; let had_pub_visibility = self.pub_visibility; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 24023163cc30e..c816d06045681 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1134,6 +1134,7 @@ symbols! { rustc_synthetic, rustc_test_marker, rustc_then_this_would_need, + rustc_trivial_field_reads, rustc_unsafe_specialization_marker, rustc_variance, rustdoc, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 19faf9cddac6f..b02333b028850 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -105,6 +105,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] #[rustc_diagnostic_item = "Clone"] +#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Clone: Sized { /// Returns a copy of the value. /// diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0a29843c9cf27..166a8e3f28a41 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -582,6 +582,7 @@ impl Display for Arguments<'_> { )] #[doc(alias = "{:?}")] #[rustc_diagnostic_item = "debug_trait"] +#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Debug { /// Formats the value using the given formatter. /// diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs index 7580010a28b4a..9567479c8137b 100644 --- a/library/core/tests/fmt/builders.rs +++ b/library/core/tests/fmt/builders.rs @@ -653,6 +653,7 @@ mod debug_list { fn test_formatting_parameters_are_forwarded() { use std::collections::{BTreeMap, BTreeSet}; #[derive(Debug)] + #[allow(dead_code)] struct Foo { bar: u32, baz: u32, diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index f6c2b499567ab..d290c3c466035 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -468,9 +468,6 @@ struct ProgrammableSink { // Writes append to this slice pub buffer: Vec, - // Flush sets this flag - pub flushed: bool, - // If true, writes will always be an error pub always_write_error: bool, @@ -520,7 +517,6 @@ impl Write for ProgrammableSink { if self.always_flush_error { Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) } else { - self.flushed = true; Ok(()) } } diff --git a/library/test/src/term/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index f4c5a05d1e2ce..694473f52c1a7 100644 --- a/library/test/src/term/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -16,6 +16,7 @@ use parser::compiled::{msys_terminfo, parse}; use searcher::get_dbpath_for_term; /// A parsed terminfo database entry. +#[allow(unused)] #[derive(Debug)] pub(crate) struct TermInfo { /// Names for the terminal diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0c81a55843013..78e4e4ec116da 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -557,7 +557,6 @@ fn build_macro( name: Symbol, import_def_id: Option, ) -> clean::ItemKind { - let imported_from = cx.tcx.crate_name(def_id.krate); match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { LoadedMacro::MacroDef(item_def, _) => { if let ast::ItemKind::MacroDef(ref def) = item_def.kind { @@ -569,7 +568,6 @@ fn build_macro( def_id, cx.tcx.visibility(import_def_id.unwrap_or(def_id)), ), - imported_from: Some(imported_from), }) } else { unreachable!() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2ad21bba21b7..7ece2acac7a40 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1859,7 +1859,6 @@ impl Clean> for (&hir::Item<'_>, Option) { } ItemKind::Macro(ref macro_def) => MacroItem(Macro { source: display_macro_source(cx, name, ¯o_def, def_id, &item.vis), - imported_from: None, }), ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5eff56a2200e1..5f09e6ced96d4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2202,7 +2202,6 @@ crate struct ImportSource { #[derive(Clone, Debug)] crate struct Macro { crate source: String, - crate imported_from: Option, } #[derive(Clone, Debug)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 172fe5d164b7a..f71660c4b2ab2 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -224,7 +224,6 @@ struct AllTypes { opaque_tys: FxHashSet, statics: FxHashSet, constants: FxHashSet, - keywords: FxHashSet, attributes: FxHashSet, derives: FxHashSet, trait_aliases: FxHashSet, @@ -245,7 +244,6 @@ impl AllTypes { opaque_tys: new_set(100), statics: new_set(100), constants: new_set(100), - keywords: new_set(100), attributes: new_set(100), derives: new_set(100), trait_aliases: new_set(100), diff --git a/src/test/ui/array-slice-vec/slice_binary_search.rs b/src/test/ui/array-slice-vec/slice_binary_search.rs index 12236960179e9..4d8022ecba73c 100644 --- a/src/test/ui/array-slice-vec/slice_binary_search.rs +++ b/src/test/ui/array-slice-vec/slice_binary_search.rs @@ -2,6 +2,7 @@ // Test binary_search_by_key lifetime. Issue #34683 +#[allow(dead_code)] #[derive(Debug)] struct Assignment { topic: String, diff --git a/src/test/ui/borrowck/borrowck-unused-mut-locals.rs b/src/test/ui/borrowck/borrowck-unused-mut-locals.rs index fd0e346e2b42d..23ef975cbbca1 100644 --- a/src/test/ui/borrowck/borrowck-unused-mut-locals.rs +++ b/src/test/ui/borrowck/borrowck-unused-mut-locals.rs @@ -1,4 +1,5 @@ // run-pass +#![allow(dead_code)] #![deny(unused_mut)] #[derive(Debug)] diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs index 1cc22fac35282..3399bc0018e54 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs @@ -3,6 +3,7 @@ // check-pass #![allow(unreachable_code)] #![warn(unused)] +#![allow(dead_code)] #[derive(Debug)] struct Point { diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr index 4eac5a2d282b0..74109772724a4 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr @@ -1,5 +1,5 @@ warning: value captured by `a` is never read - --> $DIR/liveness.rs:23:9 + --> $DIR/liveness.rs:24:9 | LL | a = 1; | ^ @@ -13,7 +13,7 @@ LL | #![warn(unused)] = help: did you mean to capture by reference instead? warning: unused variable: `a` - --> $DIR/liveness.rs:32:9 + --> $DIR/liveness.rs:33:9 | LL | a += 1; | ^ @@ -27,7 +27,7 @@ LL | #![warn(unused)] = help: did you mean to capture by reference instead? warning: value assigned to `a` is never read - --> $DIR/liveness.rs:52:9 + --> $DIR/liveness.rs:53:9 | LL | a += 1; | ^ @@ -35,7 +35,7 @@ LL | a += 1; = help: maybe it is overwritten before being read? warning: value assigned to `a` is never read - --> $DIR/liveness.rs:76:13 + --> $DIR/liveness.rs:77:13 | LL | a = Some("d1"); | ^ @@ -43,7 +43,7 @@ LL | a = Some("d1"); = help: maybe it is overwritten before being read? warning: value assigned to `b` is never read - --> $DIR/liveness.rs:84:13 + --> $DIR/liveness.rs:85:13 | LL | b = Some("e1"); | ^ @@ -51,7 +51,7 @@ LL | b = Some("e1"); = help: maybe it is overwritten before being read? warning: value assigned to `b` is never read - --> $DIR/liveness.rs:86:13 + --> $DIR/liveness.rs:87:13 | LL | b = Some("e2"); | ^ @@ -59,7 +59,7 @@ LL | b = Some("e2"); = help: maybe it is overwritten before being read? warning: unused variable: `b` - --> $DIR/liveness.rs:84:13 + --> $DIR/liveness.rs:85:13 | LL | b = Some("e1"); | ^ diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs index 10a7d07a1df99..465c9476ba65b 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs @@ -2,6 +2,7 @@ // check-pass #![warn(unused)] +#![allow(dead_code)] #[derive(Debug)] struct MyStruct { diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr index f74303e3dd682..11a440554f759 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr @@ -1,5 +1,5 @@ warning: value assigned to `a` is never read - --> $DIR/liveness_unintentional_copy.rs:19:9 + --> $DIR/liveness_unintentional_copy.rs:20:9 | LL | a = s; | ^ @@ -13,7 +13,7 @@ LL | #![warn(unused)] = help: maybe it is overwritten before being read? warning: unused variable: `a` - --> $DIR/liveness_unintentional_copy.rs:19:9 + --> $DIR/liveness_unintentional_copy.rs:20:9 | LL | a = s; | ^ @@ -27,7 +27,7 @@ LL | #![warn(unused)] = help: did you mean to capture by reference instead? warning: unused variable: `a` - --> $DIR/liveness_unintentional_copy.rs:35:9 + --> $DIR/liveness_unintentional_copy.rs:36:9 | LL | a += x; | ^ diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs index 045fe78040a92..ed222b3148f41 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs @@ -1,6 +1,7 @@ // edition:2021 //check-pass #![warn(unused)] +#![allow(dead_code)] #![feature(rustc_attrs)] #[derive(Debug, Clone, Copy)] diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs index 8e4f91c27e224..3f7ddf93f0697 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs @@ -3,6 +3,8 @@ // Test that we can use raw ptrs when using `capture_disjoint_fields`. +#![allow(dead_code)] + #[derive(Debug)] struct S { s: String, diff --git a/src/test/ui/const-generics/broken-mir-2.rs b/src/test/ui/const-generics/broken-mir-2.rs index f9e03151374a2..9d62281178c48 100644 --- a/src/test/ui/const-generics/broken-mir-2.rs +++ b/src/test/ui/const-generics/broken-mir-2.rs @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + use std::fmt::Debug; #[derive(Debug)] diff --git a/src/test/ui/derives/clone-debug-dead-code.rs b/src/test/ui/derives/clone-debug-dead-code.rs new file mode 100644 index 0000000000000..80e9132093944 --- /dev/null +++ b/src/test/ui/derives/clone-debug-dead-code.rs @@ -0,0 +1,45 @@ +// Checks that derived implementations of Clone and Debug do not +// contribute to dead code analysis (issue #84647). + +#![forbid(dead_code)] + +struct A { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Clone)] +struct B { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Debug)] +struct C { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Debug,Clone)] +struct D { f: () } +//~^ ERROR: field is never read: `f` + +struct E { f: () } +//~^ ERROR: field is never read: `f` +// Custom impl, still doesn't read f +impl Clone for E { + fn clone(&self) -> Self { + Self { f: () } + } +} + +struct F { f: () } +// Custom impl that actually reads f +impl Clone for F { + fn clone(&self) -> Self { + Self { f: self.f } + } +} + +fn main() { + let _ = A { f: () }; + let _ = B { f: () }; + let _ = C { f: () }; + let _ = D { f: () }; + let _ = E { f: () }; + let _ = F { f: () }; +} diff --git a/src/test/ui/derives/clone-debug-dead-code.stderr b/src/test/ui/derives/clone-debug-dead-code.stderr new file mode 100644 index 0000000000000..226007f3647b1 --- /dev/null +++ b/src/test/ui/derives/clone-debug-dead-code.stderr @@ -0,0 +1,38 @@ +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:6:12 + | +LL | struct A { f: () } + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/clone-debug-dead-code.rs:4:11 + | +LL | #![forbid(dead_code)] + | ^^^^^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:10:12 + | +LL | struct B { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:14:12 + | +LL | struct C { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:18:12 + | +LL | struct D { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:21:12 + | +LL | struct E { f: () } + | ^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/deriving/deriving-clone-generic-struct.rs b/src/test/ui/deriving/deriving-clone-generic-struct.rs index f6e105555fd9d..4374d1594e465 100644 --- a/src/test/ui/deriving/deriving-clone-generic-struct.rs +++ b/src/test/ui/deriving/deriving-clone-generic-struct.rs @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S { foo: (), diff --git a/src/test/ui/deriving/deriving-clone-struct.rs b/src/test/ui/deriving/deriving-clone-struct.rs index 7b0a1d20260d4..b93cbe5f8b6fd 100644 --- a/src/test/ui/deriving/deriving-clone-struct.rs +++ b/src/test/ui/deriving/deriving-clone-struct.rs @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S { _int: isize, diff --git a/src/test/ui/deriving/deriving-clone-tuple-struct.rs b/src/test/ui/deriving/deriving-clone-tuple-struct.rs index 166f1be55e02a..7ad3f03471324 100644 --- a/src/test/ui/deriving/deriving-clone-tuple-struct.rs +++ b/src/test/ui/deriving/deriving-clone-tuple-struct.rs @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S((), ()); diff --git a/src/test/ui/deriving/deriving-in-fn.rs b/src/test/ui/deriving/deriving-in-fn.rs index 8931e94a4f8d2..07f91d0597356 100644 --- a/src/test/ui/deriving/deriving-in-fn.rs +++ b/src/test/ui/deriving/deriving-in-fn.rs @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + pub fn main() { #[derive(Debug)] struct Foo { diff --git a/src/test/ui/issues/issue-19358.rs b/src/test/ui/issues/issue-19358.rs index f66e0a1c07841..3970a4155e95c 100644 --- a/src/test/ui/issues/issue-19358.rs +++ b/src/test/ui/issues/issue-19358.rs @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + trait Trait { fn dummy(&self) { } } #[derive(Debug)] diff --git a/src/test/ui/issues/issue-3794.rs b/src/test/ui/issues/issue-3794.rs index 408d8d866d862..1809e822c5421 100644 --- a/src/test/ui/issues/issue-3794.rs +++ b/src/test/ui/issues/issue-3794.rs @@ -1,5 +1,6 @@ // run-pass #![feature(box_syntax)] +#![allow(dead_code)] trait T { fn print(&self); diff --git a/src/test/ui/monomorphize-abi-alignment.rs b/src/test/ui/monomorphize-abi-alignment.rs index 637b09fc04e5f..a8d8bd1d5fd00 100644 --- a/src/test/ui/monomorphize-abi-alignment.rs +++ b/src/test/ui/monomorphize-abi-alignment.rs @@ -1,6 +1,7 @@ // run-pass #![allow(non_upper_case_globals)] +#![allow(dead_code)] /*! * On x86_64-linux-gnu and possibly other platforms, structs get 8-byte "preferred" alignment, * but their "ABI" alignment (i.e., what actually matters for data layout) is the largest alignment diff --git a/src/test/ui/moves/move-1-unique.rs b/src/test/ui/moves/move-1-unique.rs index 48baead074ac7..7d3987f656087 100644 --- a/src/test/ui/moves/move-1-unique.rs +++ b/src/test/ui/moves/move-1-unique.rs @@ -1,5 +1,6 @@ // run-pass #![allow(unused_mut)] +#![allow(dead_code)] #![feature(box_syntax)] #[derive(Clone)] diff --git a/src/test/ui/moves/move-3-unique.rs b/src/test/ui/moves/move-3-unique.rs index 55b10e057d88c..d23a852433f4f 100644 --- a/src/test/ui/moves/move-3-unique.rs +++ b/src/test/ui/moves/move-3-unique.rs @@ -1,5 +1,6 @@ // run-pass #![allow(unused_mut)] +#![allow(dead_code)] #![feature(box_syntax)] #[derive(Clone)] diff --git a/src/test/ui/overloaded/overloaded-autoderef-order.rs b/src/test/ui/overloaded/overloaded-autoderef-order.rs index 1ae16d2a7fc66..f48bae55f5f1e 100644 --- a/src/test/ui/overloaded/overloaded-autoderef-order.rs +++ b/src/test/ui/overloaded/overloaded-autoderef-order.rs @@ -1,5 +1,7 @@ // run-pass +#![allow(dead_code)] + use std::rc::Rc; use std::ops::Deref; diff --git a/src/test/ui/self/ufcs-explicit-self.rs b/src/test/ui/self/ufcs-explicit-self.rs index 4e2405504f0cb..0aaaa7d47c3c1 100644 --- a/src/test/ui/self/ufcs-explicit-self.rs +++ b/src/test/ui/self/ufcs-explicit-self.rs @@ -1,5 +1,6 @@ // run-pass #![feature(box_syntax)] +#![allow(dead_code)] #[derive(Copy, Clone)] struct Foo { diff --git a/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs b/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs index 55975cbdb5342..ca35a615d2147 100644 --- a/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs +++ b/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] trait noisy { fn speak(&mut self) -> isize; diff --git a/src/test/ui/structs-enums/class-implement-traits.rs b/src/test/ui/structs-enums/class-implement-traits.rs index c9e98e21b9eb4..732aa146ce446 100644 --- a/src/test/ui/structs-enums/class-implement-traits.rs +++ b/src/test/ui/structs-enums/class-implement-traits.rs @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] trait noisy { fn speak(&mut self); diff --git a/src/test/ui/structs-enums/functional-struct-upd.rs b/src/test/ui/structs-enums/functional-struct-upd.rs index 51c6b6d7e4ffe..68ff73a080592 100644 --- a/src/test/ui/structs-enums/functional-struct-upd.rs +++ b/src/test/ui/structs-enums/functional-struct-upd.rs @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + #[derive(Debug)] struct Foo { x: isize, diff --git a/src/test/ui/structs-enums/tag-align-shape.rs b/src/test/ui/structs-enums/tag-align-shape.rs index 87282ddbcca52..ce59958237817 100644 --- a/src/test/ui/structs-enums/tag-align-shape.rs +++ b/src/test/ui/structs-enums/tag-align-shape.rs @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] #[derive(Debug)] enum a_tag { diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 7627e0fb28956..41e6ad12d0589 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -29,36 +29,21 @@ declare_clippy_lint! { "#[macro_use] is no longer needed" } -const BRACKETS: &[char] = &['<', '>']; - #[derive(Clone, Debug, PartialEq, Eq)] struct PathAndSpan { path: String, span: Span, } -/// `MacroRefData` includes the name of the macro -/// and the path from `SourceMap::span_to_filename`. +/// `MacroRefData` includes the name of the macro. #[derive(Debug, Clone)] pub struct MacroRefData { name: String, - path: String, } impl MacroRefData { - pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self { - let sm = cx.sess().source_map(); - let mut path = sm.filename_for_diagnostics(&sm.span_to_filename(callee)).to_string(); - - // std lib paths are <::std::module::file type> - // so remove brackets, space and type. - if path.contains('<') { - path = path.replace(BRACKETS, ""); - } - if path.contains(' ') { - path = path.split(' ').next().unwrap().to_string(); - } - Self { name, path } + pub fn new(name: String) -> Self { + Self { name } } } @@ -78,7 +63,7 @@ impl MacroUseImports { fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) { let call_site = span.source_callsite(); let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); - if let Some(callee) = span.source_callee() { + if let Some(_callee) = span.source_callee() { if !self.collected.contains(&call_site) { let name = if name.contains("::") { name.split("::").last().unwrap().to_string() @@ -86,7 +71,7 @@ impl MacroUseImports { name.to_string() }; - self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx)); + self.mac_refs.push(MacroRefData::new(name)); self.collected.insert(call_site); } } @@ -95,10 +80,10 @@ impl MacroUseImports { fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) { let call_site = span.source_callsite(); let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); - if let Some(callee) = span.source_callee() { + if let Some(_callee) = span.source_callee() { if !self.collected.contains(&call_site) { self.mac_refs - .push(MacroRefData::new(name.to_string(), callee.def_site, cx)); + .push(MacroRefData::new(name.to_string())); self.collected.insert(call_site); } } diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index eab097337306b..89be7bf844f3a 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -3,8 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId}; +use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, Span}; @@ -53,10 +52,7 @@ declare_clippy_lint! { } #[derive(Clone, Default)] -pub struct Regex { - spans: FxHashSet, - last: Option, -} +pub struct Regex {} impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index 4c80cabc72305..f1f9c123dc842 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports,dead_code)] #![deny(clippy::default_trait_access)] use std::default; diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index a68b6455c0416..7f3dfc7f01366 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports,dead_code)] #![deny(clippy::default_trait_access)] use std::default; diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index a9bc89544d820..779a1149f413e 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -762,7 +762,6 @@ impl MacroArgKind { #[derive(Debug, Clone)] struct ParsedMacroArg { kind: MacroArgKind, - span: Span, } impl ParsedMacroArg { @@ -780,14 +779,10 @@ impl ParsedMacroArg { struct MacroArgParser { /// Either a name of the next metavariable, a separator, or junk. buf: String, - /// The start position on the current buffer. - lo: BytePos, /// The first token of the current buffer. start_tok: Token, /// `true` if we are parsing a metavariable or a repeat. is_meta_var: bool, - /// The position of the last token. - hi: BytePos, /// The last token parsed. last_tok: Token, /// Holds the parsed arguments. @@ -807,8 +802,6 @@ fn last_tok(tt: &TokenTree) -> Token { impl MacroArgParser { fn new() -> MacroArgParser { MacroArgParser { - lo: BytePos(0), - hi: BytePos(0), buf: String::new(), is_meta_var: false, last_tok: Token { @@ -824,7 +817,6 @@ impl MacroArgParser { } fn set_last_tok(&mut self, tok: &TokenTree) { - self.hi = tok.span().hi(); self.last_tok = last_tok(tok); } @@ -836,7 +828,6 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { kind: MacroArgKind::Separator(self.buf.clone(), prefix), - span: mk_sp(self.lo, self.hi), }); self.buf.clear(); } @@ -849,7 +840,6 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { kind: MacroArgKind::Other(self.buf.clone(), prefix), - span: mk_sp(self.lo, self.hi), }); self.buf.clear(); } @@ -858,11 +848,10 @@ impl MacroArgParser { match iter.next() { Some(TokenTree::Token(Token { kind: TokenKind::Ident(name, _), - span, + .. })) => { self.result.push(ParsedMacroArg { kind: MacroArgKind::MetaVariable(name, self.buf.clone()), - span: mk_sp(self.lo, span.hi()), }); self.buf.clear(); @@ -873,10 +862,9 @@ impl MacroArgParser { } } - fn add_delimited(&mut self, inner: Vec, delim: DelimToken, span: Span) { + fn add_delimited(&mut self, inner: Vec, delim: DelimToken) { self.result.push(ParsedMacroArg { kind: MacroArgKind::Delimited(delim, inner), - span, }); } @@ -886,19 +874,15 @@ impl MacroArgParser { inner: Vec, delim: DelimToken, iter: &mut Cursor, - span: Span, ) -> Option<()> { let mut buffer = String::new(); let mut first = true; - let mut lo = span.lo(); - let mut hi = span.hi(); // Parse '*', '+' or '?. for tok in iter { self.set_last_tok(&tok); if first { first = false; - lo = tok.span().lo(); } match tok { @@ -918,7 +902,6 @@ impl MacroArgParser { } TokenTree::Token(ref t) => { buffer.push_str(&pprust::token_to_string(&t)); - hi = t.span.hi(); } _ => return None, } @@ -930,20 +913,17 @@ impl MacroArgParser { } else { Some(Box::new(ParsedMacroArg { kind: MacroArgKind::Other(buffer, "".to_owned()), - span: mk_sp(lo, hi), })) }; self.result.push(ParsedMacroArg { kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()), - span: mk_sp(self.lo, self.hi), }); Some(()) } fn update_buffer(&mut self, t: &Token) { if self.buf.is_empty() { - self.lo = t.span.lo(); self.start_tok = t.clone(); } else { let needs_space = match next_space(&self.last_tok.kind) { @@ -999,7 +979,6 @@ impl MacroArgParser { // Start keeping the name of this metavariable in the buffer. self.is_meta_var = true; - self.lo = span.lo(); self.start_tok = Token { kind: TokenKind::Dollar, span, @@ -1012,7 +991,7 @@ impl MacroArgParser { self.add_meta_variable(&mut iter)?; } TokenTree::Token(ref t) => self.update_buffer(t), - TokenTree::Delimited(delimited_span, delimited, ref tts) => { + TokenTree::Delimited(_delimited_span, delimited, ref tts) => { if !self.buf.is_empty() { if next_space(&self.last_tok.kind) == SpaceState::Always { self.add_separator(); @@ -1022,16 +1001,14 @@ impl MacroArgParser { } // Parse the stuff inside delimiters. - let mut parser = MacroArgParser::new(); - parser.lo = delimited_span.open.lo(); + let parser = MacroArgParser::new(); let delimited_arg = parser.parse(tts.clone())?; - let span = delimited_span.entire(); if self.is_meta_var { - self.add_repeat(delimited_arg, delimited, &mut iter, span)?; + self.add_repeat(delimited_arg, delimited, &mut iter)?; self.is_meta_var = false; } else { - self.add_delimited(delimited_arg, delimited, span); + self.add_delimited(delimited_arg, delimited); } } } diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 5de0575b5cd66..ded34d9032f91 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -27,7 +27,6 @@ type FileModMap<'ast> = BTreeMap>; pub(crate) struct Module<'a> { ast_mod_kind: Option>, pub(crate) items: Cow<'a, Vec>>, - attrs: Cow<'a, Vec>, inner_attr: Vec, pub(crate) span: Span, } @@ -46,7 +45,6 @@ impl<'a> Module<'a> { .collect(); Module { items: mod_items, - attrs: mod_attrs, inner_attr, span: mod_span, ast_mod_kind, From 57fcb2e2d63306e762943b9edffa4454e89ef665 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Mon, 12 Jul 2021 18:08:14 +0200 Subject: [PATCH 19/23] Fix two uses of `span_note` when the source is not available --- .../src/diagnostics/conflict_errors.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ce1e7c14b1ff6..f4cbbb60b053a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -218,7 +218,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); if self.fn_self_span_reported.insert(fn_span) { err.span_note( - self_arg.span, + // Check whether the source is accessible + if self + .infcx + .tcx + .sess + .source_map() + .span_to_snippet(self_arg.span) + .is_ok() + { + self_arg.span + } else { + fn_call_span + }, "calling this operator moves the left-hand side", ); } @@ -429,7 +441,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { deref_target_ty )); - err.span_note(deref_target, "deref defined here"); + // Check first whether the source is accessible (issue #87060) + if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + err.span_note(deref_target, "deref defined here"); + } } if let Some((_, mut old_err)) = From 81ff53fd3e552fab8c56910c28e86e8b2f524bec Mon Sep 17 00:00:00 2001 From: Jesse Ruderman Date: Thu, 9 Sep 2021 19:21:56 -0700 Subject: [PATCH 20/23] Fix typo in docs for iterators --- library/std/src/collections/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 130bb5cb2b3c2..71645aadb1d88 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -239,7 +239,7 @@ //! Iterators also provide a series of *adapter* methods for performing common //! threads to sequences. Among the adapters are functional favorites like `map`, //! `fold`, `skip` and `take`. Of particular interest to collections is the -//! `rev` adapter, that reverses any iterator that supports this operation. Most +//! `rev` adapter, which reverses any iterator that supports this operation. Most //! collections provide reversible iterators as the way to iterate over them in //! reverse order. //! From 5d4d3bdc74dd7449421cc5208cffb73c75e40283 Mon Sep 17 00:00:00 2001 From: Gerd Zellweger Date: Fri, 10 Sep 2021 00:36:35 -0700 Subject: [PATCH 21/23] Fix typo `option` -> `options`. --- src/doc/unstable-book/src/library-features/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index a10928a747177..444b1cbf3cc45 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -375,7 +375,7 @@ Any reuse of a named label, local or otherwise, can result in a assembler or lin As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions. -Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `option(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. +Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. ```rust,allow_fail #![feature(asm)] From 64344cce14f835f4f670d2aac9bd63cf520cc4f9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Sep 2021 16:26:49 +0200 Subject: [PATCH 22/23] Don't require documentation for fields in an enum tuple variant or for tuple struct fields. --- .../passes/calculate_doc_coverage.rs | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 92e678e4c024b..721af3313d27f 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -4,8 +4,10 @@ use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; +use rustc_hir as hir; use rustc_lint::builtin::MISSING_DOCS; use rustc_middle::lint::LintLevelSource; +use rustc_middle::ty::DefIdTree; use rustc_session::lint; use rustc_span::FileName; use serde::Serialize; @@ -221,10 +223,42 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { .hir() .local_def_id_to_hir_id(i.def_id.expect_def_id().expect_local()); let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); + + // In case we have: + // + // ``` + // enum Foo { Bar(u32) } + // // or: + // struct Bar(u32); + // ``` + // + // there is no need to require documentation on the fields of tuple variants and + // tuple structs. + let should_be_ignored = i + .def_id + .as_def_id() + .and_then(|def_id| self.ctx.tcx.parent(def_id)) + .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id)) + .map(|node| { + matches!( + node, + hir::Node::Variant(hir::Variant { + data: hir::VariantData::Tuple(_, _), + .. + }) | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(hir::VariantData::Tuple(_, _), _), + .. + }) + ) + }) + .unwrap_or(false); + // `missing_docs` is allow-by-default, so don't treat this as ignoring the item - // unless the user had an explicit `allow` - let should_have_docs = - level != lint::Level::Allow || matches!(source, LintLevelSource::Default); + // unless the user had an explicit `allow`. + // + let should_have_docs = !should_be_ignored + && (level != lint::Level::Allow || matches!(source, LintLevelSource::Default)); + debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename); self.items.entry(filename).or_default().count_item( has_docs, From eda4cfb13268e6344139dcbf57ef36962d9dc12d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Sep 2021 16:27:09 +0200 Subject: [PATCH 23/23] Add test for enum tuple variants and tuple struct doc count --- .../coverage/enum-tuple-documented.rs | 37 +++++++++++++++++++ .../coverage/enum-tuple-documented.stdout | 7 ++++ src/test/rustdoc-ui/coverage/enum-tuple.rs | 18 +++++++++ .../rustdoc-ui/coverage/enum-tuple.stdout | 7 ++++ src/test/rustdoc-ui/coverage/enums.stdout | 4 +- 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-ui/coverage/enum-tuple-documented.rs create mode 100644 src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout create mode 100644 src/test/rustdoc-ui/coverage/enum-tuple.rs create mode 100644 src/test/rustdoc-ui/coverage/enum-tuple.stdout diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs new file mode 100644 index 0000000000000..e9c165b1916e2 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs @@ -0,0 +1,37 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +// The point of this test is to ensure that the number of "documented" items +// is higher than in `enum-tuple.rs`. + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// VarOne. + VarOne( + /// hello! + String, + ), + /// Var Two. + VarTwo( + /// Hello + String, + /// Bis repetita. + String, + ), +} + +/// Struct. +pub struct ThisStruct( + /// hello + u32, +); + +/// Struct. +pub struct ThisStruct2( + /// hello + u32, + /// Bis repetita. + u8, +); diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout new file mode 100644 index 0000000000000..82c98f43f3dd0 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...overage/enum-tuple-documented.rs | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.rs b/src/test/rustdoc-ui/coverage/enum-tuple.rs new file mode 100644 index 0000000000000..5fb205450755b --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple.rs @@ -0,0 +1,18 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// No need to document the field if there is only one in a tuple variant! + VarOne(String), + /// But if there is more than one... still fine! + VarTwo(String, String), +} + +/// Struct. +pub struct ThisStruct(u32); + +/// Struct. +pub struct ThisStruct2(u32, u8); diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.stdout b/src/test/rustdoc-ui/coverage/enum-tuple.stdout new file mode 100644 index 0000000000000..a3377d59c073a --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...ustdoc-ui/coverage/enum-tuple.rs | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout index 414d60c86d308..64c012c1f66e3 100644 --- a/src/test/rustdoc-ui/coverage/enums.stdout +++ b/src/test/rustdoc-ui/coverage/enums.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/enums.rs | 6 | 66.7% | 0 | 0.0% | +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 6 | 66.7% | 0 | 0.0% | +| Total | 6 | 75.0% | 0 | 0.0% | +-------------------------------------+------------+------------+------------+------------+