From db8ddbf570fa7d8df5d71b19b44a771c80c689ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 Dec 2020 17:31:31 +0100 Subject: [PATCH 01/22] Move tooltips messages to CSS instead of inside HTML --- src/librustdoc/html/highlight.rs | 15 +++-- src/librustdoc/html/markdown.rs | 61 +++++---------------- src/librustdoc/html/static/rustdoc.css | 24 +++++--- src/librustdoc/html/static/themes/ayu.css | 4 +- src/librustdoc/html/static/themes/dark.css | 4 +- src/librustdoc/html/static/themes/light.css | 4 +- 6 files changed, 47 insertions(+), 65 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1cbfbf50dd745..47d2707e40dfc 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -11,6 +11,7 @@ use std::fmt::{Display, Write}; use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; +use rustc_span::edition::Edition; use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; @@ -19,16 +20,20 @@ crate fn render_with_highlighting( src: String, class: Option<&str>, playground_button: Option<&str>, - tooltip: Option<(&str, &str)>, + tooltip: Option<(Option, &str)>, ) -> String { debug!("highlighting: ================\n{}\n==============", src); let mut out = String::with_capacity(src.len()); - if let Some((tooltip, class)) = tooltip { + if let Some((edition_info, class)) = tooltip { write!( out, - "
{}
", - class, tooltip + "
", + class, + if let Some(edition_info) = edition_info { + format!(" edition=\"{}\"", edition_info) + } else { + String::new() + }, ) .unwrap(); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ce686c65502f..6229a479b4d09 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -286,60 +286,27 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { }); let tooltip = if ignore != Ignore::None { - Some(("This example is not tested".to_owned(), "ignore")) + Some((None, "ignore")) } else if compile_fail { - Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) + Some((None, "compile_fail")) } else if should_panic { - Some(("This example panics".to_owned(), "should_panic")) + Some((None, "should_panic")) } else if explicit_edition { - Some((format!("This code runs with edition {}", edition), "edition")) + Some((Some(edition), "edition")) } else { None }; - if let Some((s1, s2)) = tooltip { - s.push_str(&highlight::render_with_highlighting( - text, - Some(&format!( - "rust-example-rendered{}", - if ignore != Ignore::None { - " ignore" - } else if compile_fail { - " compile_fail" - } else if should_panic { - " should_panic" - } else if explicit_edition { - " edition " - } else { - "" - } - )), - playground_button.as_deref(), - Some((s1.as_str(), s2)), - )); - Some(Event::Html(s.into())) - } else { - s.push_str(&highlight::render_with_highlighting( - text, - Some(&format!( - "rust-example-rendered{}", - if ignore != Ignore::None { - " ignore" - } else if compile_fail { - " compile_fail" - } else if should_panic { - " should_panic" - } else if explicit_edition { - " edition " - } else { - "" - } - )), - playground_button.as_deref(), - None, - )); - Some(Event::Html(s.into())) - } + s.push_str(&highlight::render_with_highlighting( + text, + Some(&format!( + "rust-example-rendered{}", + if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() } + )), + playground_button.as_deref(), + tooltip, + )); + Some(Event::Html(s.into())) } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8eef65a231d0b..afc4308b68f93 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1079,20 +1079,29 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { cursor: pointer; } -.tooltip .tooltiptext { - width: 120px; +.tooltip::after { display: none; text-align: center; padding: 5px 3px 3px 3px; border-radius: 6px; margin-left: 5px; - top: -5px; - left: 105%; - z-index: 10; font-size: 16px; } -.tooltip .tooltiptext::after { +.tooltip.ignore::after { + content: "This example is not tested"; +} +.tooltip.compile_fail::after { + content: "This example deliberately fails to compile"; +} +.tooltip.should_panic::after { + content: "This example panics"; +} +.tooltip.edition::after { + content: "This code runs with edition " attr(edition); +} + +.tooltip::before { content: " "; position: absolute; top: 50%; @@ -1100,9 +1109,10 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { margin-top: -5px; border-width: 5px; border-style: solid; + display: none; } -.tooltip:hover .tooltiptext { +.tooltip:hover::before, .tooltip:hover::after { display: inline; } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index c1f796f09e804..9c71fbb7f03a4 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -388,13 +388,13 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #39AFD7; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #314559; color: #c5c5c5; border: 1px solid #5c6773; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent #314559 transparent transparent; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 946ca0a40c9dc..eb25272ea3bbc 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,13 +337,13 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #0089ff; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #000; color: #fff; border-color: #000; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent black transparent transparent; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index e0b9a04921a80..20e3c0a40929a 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -329,12 +329,12 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #0089ff; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #000; color: #fff; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent black transparent transparent; } From 9b6293692801f703e694c4c7f61b165b939cea8d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 Dec 2020 17:31:39 +0100 Subject: [PATCH 02/22] Update tests --- src/test/rustdoc/codeblock-title.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs index b59b21111b009..1327fd67d316b 100644 --- a/src/test/rustdoc/codeblock-title.rs +++ b/src/test/rustdoc/codeblock-title.rs @@ -1,10 +1,9 @@ #![crate_name = "foo"] -// ignore-tidy-linelength - -// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile" -// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested" -// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics" +// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ" +// @has foo/fn.bar.html '//*[@edition="2018"]' "ⓘ" /// foo /// @@ -20,7 +19,7 @@ /// hoo(); /// ``` /// -/// ``` +/// ```edition2018 /// let x = 0; /// ``` pub fn bar() -> usize { 2 } From b66eb696af9ef1952f2582b2b8ec07156868b2f6 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Sun, 13 Dec 2020 04:14:08 +0000 Subject: [PATCH 03/22] Refactored verbose print into a function Also handle Tuple and Array separately, which was not explicitly checked. Fixes #79799. --- compiler/rustc_mir/src/util/pretty.rs | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index cd60602b088f2..9b81629400a66 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,8 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -408,6 +409,33 @@ impl ExtraComments<'tcx> { } } +fn use_verbose(ty: &&TyS<'tcx>) -> bool { + match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, + // Unit type + ty::Tuple(g_args) if g_args.is_empty() => false, + ty::Tuple(g_args) => { + // could have used `try_fold` here but it seems a bit silly that + // the accumulator is useless + let mut should_be_verbose = false; + for g_arg in g_args.iter() { + if match g_arg.unpack() { + GenericArgKind::Type(ty) => use_verbose(&ty), + GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), + _ => false, + } { + should_be_verbose = true; + break; + } + } + should_be_verbose + } + ty::Array(ty, _) => use_verbose(ty), + ty::FnDef(..) => false, + _ => true, + } +} + impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); @@ -430,16 +458,10 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} - // Unit type - ty::Tuple(tys) if tys.is_empty() => {} - ty::FnDef(..) => {} - _ => { - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); - } + if use_verbose(ty) { + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); } } From 0e0ae47af9843cddb5f67cc060cc163871da6943 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Tue, 15 Dec 2020 19:22:23 +0100 Subject: [PATCH 04/22] Add a new lint to rustdoc for invalid codeblocks This will make rustdoc behave properly when -Dwarnings is given --- compiler/rustc_lint/src/lib.rs | 3 +- compiler/rustc_lint_defs/src/builtin.rs | 13 ++++ src/doc/rustdoc/src/lints.md | 35 +++++++++ src/librustdoc/core.rs | 2 + .../passes/check_code_block_syntax.rs | 71 +++++++++++++------ src/test/rustdoc-ui/invalid-syntax.stderr | 1 + 6 files changed, 102 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 80ef855c3859e..d1a9d518fae87 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -70,7 +70,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS, - MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS, + INVALID_RUST_CODEBLOCK, MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS, }; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -320,6 +320,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_RUST_CODEBLOCK, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, INVALID_HTML_TAGS diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index fa82dce0ae2ed..90c5348c6ea6e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1847,6 +1847,18 @@ declare_lint! { "codeblock attribute looks a lot like a known one" } +declare_lint! { + /// The `invalid_rust_codeblock` lint detects Rust code blocks in + /// documentation examples that are invalid (e.g. empty, not parsable as + /// Rust code). This is a `rustdoc` only lint, see the documentation in the + /// [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblock + pub INVALID_RUST_CODEBLOCK, + Warn, + "codeblock could not be parsed as valid Rust or is empty" +} + declare_lint! { /// The `missing_crate_level_docs` lint detects if documentation is /// missing at the crate root. This is a `rustdoc` only lint, see the @@ -2803,6 +2815,7 @@ declare_lint_pass! { BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_RUST_CODEBLOCK, MISSING_CRATE_LEVEL_DOCS, MISSING_DOC_CODE_EXAMPLES, INVALID_HTML_TAGS, diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 41292b3d83841..94e0cbe223a95 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -285,6 +285,41 @@ warning: unclosed HTML tag `h1` warning: 2 warnings emitted ``` + +## invalid_rust_codeblock + +This lint **warns by default**. It detects Rust code blocks in documentation +examples that are invalid (e.g. empty, not parsable as Rust). For example: + +```rust +/// Empty code block, with and without Rust: +/// +/// ```rust +/// ``` +/// +/// Unclosed code block: +/// +/// ```rust +fn main() {} +``` + +Which will give: + +```text +warning: Rust code block is empty + --> src/lib.rs:3:5 + | +3 | /// ```rust + | _____^ +4 | | /// ``` + | |_______^ + +warning: Rust code block is empty + --> src/lib.rs:8:5 + | +8 | /// ```rust + | ^^^^^^^ +``` ## non_autolinks diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9c693c290e7f4..438ac63f0da41 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -322,6 +322,7 @@ crate fn run_core( let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let invalid_rust_codeblock = rustc_lint::builtin::INVALID_RUST_CODEBLOCK.name; let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name; let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name; @@ -337,6 +338,7 @@ crate fn run_core( private_doc_tests.to_owned(), no_crate_level_docs.to_owned(), invalid_codeblock_attributes_name.to_owned(), + invalid_rust_codeblock.to_owned(), invalid_html_tags.to_owned(), renamed_and_removed_lints.to_owned(), unknown_lints.to_owned(), diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 0c76dc571beee..323b140847148 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,6 +1,8 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; +use rustc_middle::lint::LintDiagnosticBuilder; use rustc_parse::parse_stream_from_source_str; +use rustc_session::lint; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan}; @@ -47,51 +49,76 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { .unwrap_or(false); let buffer = buffer.borrow(); - if buffer.has_errors || is_empty { - let mut diag = if let Some(sp) = - super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) - { - let warning_message = if buffer.has_errors { + if !(buffer.has_errors || is_empty) { + // No errors in a non-empty program. + return; + } + + let local_id = match item.def_id.as_local() { + Some(id) => id, + // We don't need to check the syntax for other crates so returning + // without doing anything should not be a problem. + None => return, + }; + + let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); + let mark_with_text = code_block.syntax.is_none() && code_block.is_fenced; + + // The span and whether it is precise or not. + let (sp, precise_span) = match super::source_span_for_markdown_range( + self.cx, + &dox, + &code_block.range, + &item.attrs, + ) { + Some(sp) => (sp, true), + None => (super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), false), + }; + + // lambda that will use the lint to start a new diagnostic and add + // a suggestion to it when needed. + let diag_builder = |lint: LintDiagnosticBuilder<'_>| { + let mut diag = if precise_span { + let msg = if buffer.has_errors { "could not parse code block as Rust code" } else { "Rust code block is empty" }; - let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); - - if code_block.syntax.is_none() && code_block.is_fenced { - let sp = sp.from_inner(InnerSpan::new(0, 3)); + let mut diag = lint.build(msg); + if mark_with_text { diag.span_suggestion( - sp, + sp.from_inner(InnerSpan::new(0, 3)), "mark blocks that do not contain Rust code as text", String::from("```text"), Applicability::MachineApplicable, ); } - diag } else { - // We couldn't calculate the span of the markdown block that had the error, so our - // diagnostics are going to be a bit lacking. - let mut diag = self.cx.sess().struct_span_warn( - super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), - "doc comment contains an invalid Rust code block", - ); - - if code_block.syntax.is_none() && code_block.is_fenced { + let mut diag = lint.build("doc comment contains an invalid Rust code block"); + if mark_with_text { diag.help("mark blocks that do not contain Rust code as text: ```text"); } diag }; - // FIXME(#67563): Provide more context for these errors by displaying the spans inline. for message in buffer.messages.iter() { diag.note(&message); } - diag.emit(); - } + }; + + // Finally build and emit the completed diagnostic. + // All points of divergence have been handled earlier so this can be + // done the same way whether the span is precise or not. + self.cx.tcx.struct_span_lint_hir( + lint::builtin::INVALID_RUST_CODEBLOCK, + hir_id, + sp, + diag_builder, + ); } } diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 9a7a4d2101362..a55a0b1d90e24 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -7,6 +7,7 @@ LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->si LL | | /// ``` | |_______^ | + = note: `#[warn(invalid_rust_codeblock)]` on by default = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ From 830ceaa41908bd428e36b1a804dd93c9a257aea8 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Sun, 6 Dec 2020 13:57:37 +0100 Subject: [PATCH 05/22] Remap instrument-coverage line numbers in doctests This uses the `SourceMap::doctest_offset_line` method to re-map line numbers from doctests. Remapping columns is not yet done. Part of issue #79417. --- .../rustc_mir/src/transform/coverage/mod.rs | 6 +- compiler/rustc_span/src/lib.rs | 2 +- src/librustdoc/doctest.rs | 75 +++++--- src/librustdoc/doctest/tests.rs | 69 +++++-- src/librustdoc/html/markdown.rs | 2 +- .../coverage-reports/Makefile | 22 ++- .../expected_show_coverage.doctest.txt | 79 ++++++++ .../expected_show_coverage.uses_crate.txt | 4 +- .../coverage-reports/normalize_paths.py | 10 + ...est.main.-------.InstrumentCoverage.0.html | 127 +++++++++++++ ...doctests.-------.InstrumentCoverage.0.html | 173 ++++++++++++++++++ .../coverage/compiletest-ignore-dir | 4 +- .../coverage/coverage_tools.mk | 4 +- .../run-make-fulldeps/coverage/doctest.rs | 66 +++++++ .../coverage/lib/doctest_crate.rs | 9 + 15 files changed, 596 insertions(+), 56 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/doctest.rs create mode 100644 src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 4590d37c182e4..93133e9b7f063 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -30,6 +30,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; +use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol}; /// A simple error message wrapper for `coverage::Error`s. @@ -311,7 +312,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body, counter_kind, self.bcb_leader_bb(bcb), - Some(make_code_region(file_name, &self.source_file, span, body_span)), + Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), ); } } @@ -489,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co /// Convert the Span into its file name, start line and column, and end line and column fn make_code_region( + source_map: &SourceMap, file_name: Symbol, source_file: &Lrc, span: Span, @@ -508,6 +510,8 @@ fn make_code_region( } else { source_file.lookup_file_pos(span.hi()) }; + let start_line = source_map.doctest_offset_line(&source_file.name, start_line); + let end_line = source_map.doctest_offset_line(&source_file.name, end_line); CodeRegion { file_name, start_line: start_line as u32, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f63a73acbf4ba..fbef4d06709ec 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -182,7 +182,7 @@ impl std::fmt::Display for FileName { use FileName::*; match *self { Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()), - // FIXME: might be nice to display both compoments of Devirtualized. + // FIXME: might be nice to display both components of Devirtualized. // But for now (to backport fix for issue #70924), best to not // perturb diagnostics so its obvious test suite still works. Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 37fe13c32ce74..a08ded926402f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -247,9 +247,10 @@ fn run_test( edition: Edition, outdir: DirState, path: PathBuf, + test_id: &str, ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = - make_test(test, Some(cratename), as_test_harness, opts, edition); + make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id)); let output_file = outdir.path().join("rust_out"); @@ -387,6 +388,7 @@ crate fn make_test( dont_insert_main: bool, opts: &TestOptions, edition: Edition, + test_id: Option<&str>, ) -> (String, usize, bool) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); @@ -542,16 +544,40 @@ crate fn make_test( prog.push_str(everything_else); } else { let returns_result = everything_else.trim_end().ends_with("(())"); + // Give each doctest main function a unique name. + // This is for example needed for the tooling around `-Z instrument-coverage`. + let inner_fn_name = if let Some(test_id) = test_id { + format!("_doctest_main_{}", test_id) + } else { + "_inner".into() + }; let (main_pre, main_post) = if returns_result { ( - "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {", - "}\n_inner().unwrap() }", + format!( + "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n", + inner_fn_name + ), + format!("\n}}; {}().unwrap() }}", inner_fn_name), + ) + } else if test_id.is_some() { + ( + format!("fn main() {{ fn {}() {{\n", inner_fn_name), + format!("\n}}; {}() }}", inner_fn_name), ) } else { - ("fn main() {\n", "\n}") + ("fn main() {\n".into(), "\n}".into()) }; - prog.extend([main_pre, everything_else, main_post].iter().cloned()); + // Note on newlines: We insert a line/newline *before*, and *after* + // the doctest and adjust the `line_offset` accordingly. + // In the case of `-Z instrument-coverage`, this means that the generated + // inner `main` function spans from the doctest opening codeblock to the + // closing one. For example + // /// ``` <- start of the inner main + // /// <- code under doctest + // /// ``` <- end of the inner main line_offset += 1; + + prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); } debug!("final doctest:\n{}", prog); @@ -749,28 +775,24 @@ impl Tester for Collector { _ => PathBuf::from(r"doctest.rs"), }; + // For example `module/file.rs` would become `module_file_rs` + let file = filename + .to_string() + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }) + .collect::(); + let test_id = format!( + "{file}_{line}_{number}", + file = file, + line = line, + number = { + // Increases the current test number, if this file already + // exists or it creates a new entry with a test number of 0. + self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0) + }, + ); let outdir = if let Some(mut path) = options.persist_doctests.clone() { - // For example `module/file.rs` would become `module_file_rs` - let folder_name = filename - .to_string() - .chars() - .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c }) - .collect::(); - - path.push(format!( - "{krate}_{file}_{line}_{number}", - krate = cratename, - file = folder_name, - line = line, - number = { - // Increases the current test number, if this file already - // exists or it creates a new entry with a test number of 0. - self.visited_tests - .entry((folder_name.clone(), line)) - .and_modify(|v| *v += 1) - .or_insert(0) - }, - )); + path.push(&test_id); std::fs::create_dir_all(&path) .expect("Couldn't create directory for doctest executables"); @@ -817,6 +839,7 @@ impl Tester for Collector { edition, outdir, path, + &test_id, ); if let Err(err) = res { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a024e9c72a43e..7c0df673c1b9e 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -11,7 +11,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -26,7 +26,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -44,7 +44,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -61,7 +61,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -79,7 +79,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -98,7 +98,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -115,7 +115,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -134,7 +134,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); // Adding more will also bump the returned line offset. @@ -147,7 +147,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 4)); } @@ -164,7 +164,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -180,7 +180,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -196,7 +196,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -210,7 +210,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -224,7 +224,7 @@ fn make_test_display_warnings() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -242,7 +242,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); let input = "extern crate hella_qwop; @@ -256,7 +256,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -274,6 +274,41 @@ test_wrapper! { }" .to_string(); - let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } + +#[test] +fn make_test_returns_result() { + // creates an inner function and unwraps it + let opts = TestOptions::default(); + let input = "use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(())"; + let expected = "#![allow(unused)] +fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> { +use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(()) +}; _inner().unwrap() }" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_named_wrapper() { + // creates an inner function with a specific name + let opts = TestOptions::default(); + let input = "assert_eq!(2+2, 4);"; + let expected = "#![allow(unused)] +fn main() { fn _doctest_main_some_unique_name() { +assert_eq!(2+2, 4); +}; _doctest_main_some_unique_name() }" + .to_string(); + let (output, len, _) = + make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name")); + assert_eq!((output, len), (expected, 2)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 22096203d4ce6..f911a2ce3fc78 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -248,7 +248,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .join("\n"); let krate = krate.as_ref().map(|s| &**s); let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition); + doctest::make_test(&test, krate, false, &Default::default(), edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 5c24f909130c0..c4700b317efa0 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -98,7 +98,7 @@ endif # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ $(call RUN,$@) || \ ( \ status=$$?; \ @@ -108,9 +108,16 @@ endif ) \ ) + # Run it through rustdoc as well to cover doctests + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ + $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \ + -L "$(TMPDIR)" -Zinstrument-coverage \ + -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@ + # Postprocess the profiling data so it can be used by the llvm-cov tool "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/$@.profraw \ + "$(TMPDIR)"/$@-*.profraw \ -o "$(TMPDIR)"/$@.profdata # Generate a coverage report using `llvm-cov show`. @@ -121,8 +128,15 @@ endif --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ $(call BIN,"$(TMPDIR)"/$@) \ - > "$(TMPDIR)"/actual_show_coverage.$@.txt \ - 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \ + $$( \ + for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \ + do \ + [[ -x $$file ]] && printf "%s %s " -object $$file; \ + done \ + ) \ + 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \ + | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \ + > "$(TMPDIR)"/actual_show_coverage.$@.txt || \ ( status=$$? ; \ >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \ exit $$status \ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt new file mode 100644 index 0000000000000..e1731c7223c5d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -0,0 +1,79 @@ +../coverage/doctest.rs: + 1| |//! This test ensures that code from doctests is properly re-mapped. + 2| |//! See for more info. + 3| |//! + 4| |//! Just some random code: + 5| 1|//! ``` + 6| 1|//! if true { + 7| |//! // this is executed! + 8| 1|//! assert_eq!(1, 1); + 9| |//! } else { + 10| |//! // this is not! + 11| |//! assert_eq!(1, 2); + 12| |//! } + 13| 1|//! ``` + 14| |//! + 15| |//! doctest testing external code: + 16| |//! ``` + 17| 1|//! extern crate doctest_crate; + 18| 1|//! doctest_crate::fn_run_in_doctests(1); + 19| 1|//! ``` + 20| |//! + 21| |//! doctest returning a result: + 22| 1|//! ``` + 23| 1|//! #[derive(Debug)] + 24| 1|//! struct SomeError; + 25| 1|//! let mut res = Err(SomeError); + 26| 1|//! if res.is_ok() { + 27| 0|//! res?; + 28| 1|//! } else { + 29| 1|//! res = Ok(0); + 30| 1|//! } + 31| |//! // need to be explicit because rustdoc cant infer the return type + 32| 1|//! Ok::<(), SomeError>(()) + 33| 1|//! ``` + 34| |//! + 35| |//! doctest with custom main: + 36| |//! ``` + 37| |//! #[derive(Debug)] + 38| |//! struct SomeError; + 39| |//! + 40| |//! extern crate doctest_crate; + 41| |//! + 42| 1|//! fn doctest_main() -> Result<(), SomeError> { + 43| 1|//! doctest_crate::fn_run_in_doctests(2); + 44| 1|//! Ok(()) + 45| 1|//! } + 46| |//! + 47| |//! // this `main` is not shown as covered, as it clashes with all the other + 48| |//! // `main` functions that were automatically generated for doctests + 49| |//! fn main() -> Result<(), SomeError> { + 50| |//! doctest_main() + 51| |//! } + 52| |//! ``` + 53| | + 54| |/// doctest attached to fn testing external code: + 55| |/// ``` + 56| 1|/// extern crate doctest_crate; + 57| 1|/// doctest_crate::fn_run_in_doctests(3); + 58| 1|/// ``` + 59| |/// + 60| 1|fn main() { + 61| 1| if true { + 62| 1| assert_eq!(1, 1); + 63| | } else { + 64| | assert_eq!(1, 2); + 65| | } + 66| 1|} + +../coverage/lib/doctest_crate.rs: + 1| |/// A function run only from within doctests + 2| 3|pub fn fn_run_in_doctests(conditional: usize) { + 3| 3| match conditional { + 4| 1| 1 => assert_eq!(1, 1), // this is run, + 5| 1| 2 => assert_eq!(1, 1), // this, + 6| 1| 3 => assert_eq!(1, 1), // and this too + 7| 0| _ => assert_eq!(1, 2), // however this is not + 8| | } + 9| 3|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index e14e733fff6d4..4c03e950af029 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py new file mode 100644 index 0000000000000..05fb412cdb635 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import sys + +# Normalize file paths in output +for line in sys.stdin: + if line.startswith("..") and line.rstrip().endswith(".rs:"): + print(line.replace("\\", "/"), end='') + else: + print(line, end='') diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..8d074558aae20 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,127 @@ + + + + +doctest.main - Coverage Spans + + + +
@0⦊fn main() ⦉@0{ + if @0⦊true⦉@0 { + @5⦊@4,6,7,8,9⦊assert_eq!(1, 1);⦉@4,6,7,8,9⦉@5 + } else { + @11⦊@10,12,13,14,15⦊assert_eq!(1, 2);⦉@10,12,13,14,15⦉@11 + } +}@16⦊⦉@16
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ae119d9ca9f2e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html @@ -0,0 +1,173 @@ + + + + +doctest_crate.fn_run_in_doctests - Coverage Spans + + + +
@0⦊pub fn fn_run_in_doctests(conditional: usize) ⦉@0{ + match @0⦊conditional⦉@0 { + 1 => @7⦊@6,8,9,10,11⦊assert_eq!(1, 1)⦉@6,8,9,10,11⦉@7, // this is run, + 2 => @14⦊@13,15,16,17,18⦊assert_eq!(1, 1)⦉@13,15,16,17,18⦉@14, // this, + 3 => @21⦊@20,22,23,24,25⦊assert_eq!(1, 1)⦉@20,22,23,24,25⦉@21, // and this too + _ => @27⦊@26,28,29,30,31⦊assert_eq!(1, 2)⦉@26,28,29,30,31⦉@27, // however this is not + } +}@32⦊⦉@32
+ + diff --git a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir index abf8df8fdc9e6..d1824d189e382 100644 --- a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir +++ b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir @@ -1,3 +1,3 @@ -# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* +# Directory "coverage" supports the tests at prefix ../coverage-* -# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. +# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 7dc485cd94d66..4d340d4b1dadd 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -1,7 +1,7 @@ -# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this +# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this # file with the line: # -# -include ../instrument-coverage/coverage_tools.mk +# -include ../coverage/coverage_tools.mk -include ../tools.mk diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make-fulldeps/coverage/doctest.rs new file mode 100644 index 0000000000000..e41d669bf0c76 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/doctest.rs @@ -0,0 +1,66 @@ +//! This test ensures that code from doctests is properly re-mapped. +//! See for more info. +//! +//! Just some random code: +//! ``` +//! if true { +//! // this is executed! +//! assert_eq!(1, 1); +//! } else { +//! // this is not! +//! assert_eq!(1, 2); +//! } +//! ``` +//! +//! doctest testing external code: +//! ``` +//! extern crate doctest_crate; +//! doctest_crate::fn_run_in_doctests(1); +//! ``` +//! +//! doctest returning a result: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! let mut res = Err(SomeError); +//! if res.is_ok() { +//! res?; +//! } else { +//! res = Ok(0); +//! } +//! // need to be explicit because rustdoc cant infer the return type +//! Ok::<(), SomeError>(()) +//! ``` +//! +//! doctest with custom main: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! +//! extern crate doctest_crate; +//! +//! fn doctest_main() -> Result<(), SomeError> { +//! doctest_crate::fn_run_in_doctests(2); +//! Ok(()) +//! } +//! +//! // this `main` is not shown as covered, as it clashes with all the other +//! // `main` functions that were automatically generated for doctests +//! fn main() -> Result<(), SomeError> { +//! doctest_main() +//! } +//! ``` + +/// doctest attached to fn testing external code: +/// ``` +/// extern crate doctest_crate; +/// doctest_crate::fn_run_in_doctests(3); +/// ``` +/// +fn main() { + if true { + assert_eq!(1, 1); + } else { + assert_eq!(1, 2); + } +} diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs new file mode 100644 index 0000000000000..c3210146d69b0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs @@ -0,0 +1,9 @@ +/// A function run only from within doctests +pub fn fn_run_in_doctests(conditional: usize) { + match conditional { + 1 => assert_eq!(1, 1), // this is run, + 2 => assert_eq!(1, 1), // this, + 3 => assert_eq!(1, 1), // and this too + _ => assert_eq!(1, 2), // however this is not + } +} From f9fa3fe65f561001535b069ed1f55c202758588c Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Sun, 20 Dec 2020 10:00:32 +0100 Subject: [PATCH 06/22] add an attribute to inner doctest fn --- src/librustdoc/doctest.rs | 7 ++++--- src/librustdoc/doctest/tests.rs | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a08ded926402f..7313c761eae8c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -551,17 +551,18 @@ crate fn make_test( } else { "_inner".into() }; + let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" }; let (main_pre, main_post) = if returns_result { ( format!( - "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n", - inner_fn_name + "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n", + inner_attr, inner_fn_name ), format!("\n}}; {}().unwrap() }}", inner_fn_name), ) } else if test_id.is_some() { ( - format!("fn main() {{ fn {}() {{\n", inner_fn_name), + format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name), format!("\n}}; {}() }}", inner_fn_name), ) } else { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 7c0df673c1b9e..1aea85e99708a 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -304,11 +304,11 @@ fn make_test_named_wrapper() { let opts = TestOptions::default(); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { fn _doctest_main_some_unique_name() { +fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); -}; _doctest_main_some_unique_name() }" +}; _doctest_main__some_unique_name() }" .to_string(); let (output, len, _) = - make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name")); + make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } From 087101e285895b8bce94a16a90f7e7a3d938c3da Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 21 Dec 2020 12:05:10 +0100 Subject: [PATCH 07/22] make path normalization compatible with mac python2 --- src/test/run-make-fulldeps/coverage-reports/normalize_paths.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py old mode 100644 new mode 100755 index 05fb412cdb635..e5777ad2512f1 --- a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import print_function + import sys # Normalize file paths in output From a272d621bc7a2ca61d704fbe531dc532d49ab402 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 18 Dec 2020 17:32:26 +0100 Subject: [PATCH 08/22] Implemented a compiler diagnostic for move async mistake Ran the tidy check Following the diagnostic guide better Diagnostic generation is now relegated to its own function in the diagnostics module. Added tests Fixed the ui test --- compiler/rustc_parse/src/parser/diagnostics.rs | 18 ++++++++++++++++++ compiler/rustc_parse/src/parser/expr.rs | 18 ++++++++++++++---- ...ncorrect-move-async-order-issue-79694.fixed | 8 ++++++++ .../incorrect-move-async-order-issue-79694.rs | 8 ++++++++ ...correct-move-async-order-issue-79694.stderr | 13 +++++++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.rs create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 350a372a684cc..98c7b9a63a55f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1912,4 +1912,22 @@ impl<'a> Parser<'a> { *self = snapshot; Err(err) } + + /// Get the diagnostics for the cases where `move async` is found. + /// + /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword + pub(super) fn incorrect_move_async_order_found( + &self, + move_async_span: Span, + ) -> DiagnosticBuilder<'a> { + let mut err = + self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); + err.span_suggestion_verbose( + move_async_span, + "try switching the order", + "async move".to_owned(), + Applicability::MaybeIncorrect, + ); + err + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c2c..7d0d4f30137ac 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - let capture_clause = self.parse_capture_clause(); + 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 { @@ -1626,8 +1626,18 @@ impl<'a> Parser<'a> { } /// Parses an optional `move` prefix to a closure-like construct. - fn parse_capture_clause(&mut self) -> CaptureBy { - if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref } + fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { + if self.eat_keyword(kw::Move) { + // Check for `move async` and recover + if self.check_keyword(kw::Async) { + let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.incorrect_move_async_order_found(move_async_span)) + } else { + Ok(CaptureBy::Value) + } + } else { + Ok(CaptureBy::Ref) + } } /// Parses the `|arg, arg|` header of a closure. @@ -2018,7 +2028,7 @@ impl<'a> Parser<'a> { fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect_keyword(kw::Async)?; - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 0000000000000..055800d23b6c6 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 0000000000000..e8be16516d6d3 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 0000000000000..2add9fb33c70e --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ^^^^^^^^^^ + +error: aborting due to previous error + From aec3575aa7d6903fbff2140b37b65961836d47dc Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:17:53 -0800 Subject: [PATCH 09/22] Rename rustc_middle::lint::LintSource Rename rustc_middle::lint::LintSource to rustc_middle::lint::LintLevelSource. --- compiler/rustc_lint/src/levels.rs | 20 ++++++------ compiler/rustc_middle/src/lint.rs | 32 +++++++++---------- compiler/rustc_middle/src/ty/context.rs | 4 +-- .../passes/calculate_doc_coverage.rs | 4 +-- src/librustdoc/passes/doc_test_lints.rs | 4 +-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 3e22eba15aaef..410bd06850e75 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,7 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; +use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; @@ -91,7 +91,7 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { self.check_gated_lint(id, DUMMY_SP); - let src = LintSource::CommandLine(lint_flag_val, orig_level); + let src = LintLevelSource::CommandLine(lint_flag_val, orig_level); specs.insert(id, (level, src)); } } @@ -128,19 +128,19 @@ impl<'s> LintLevelsBuilder<'s> { ); diag_builder.span_label(src.span(), "overruled by previous forbid"); match old_src { - LintSource::Default => { + LintLevelSource::Default => { diag_builder.note(&format!( "`forbid` lint level is the default for {}", id.to_string() )); } - LintSource::Node(_, forbid_source_span, reason) => { + LintLevelSource::Node(_, forbid_source_span, reason) => { diag_builder.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { diag_builder.note(&rationale.as_str()); } } - LintSource::CommandLine(_, _) => { + LintLevelSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } @@ -276,7 +276,7 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span(), reason); + let src = LintLevelSource::Node(name, li.span(), reason); for &id in ids { self.check_gated_lint(id, attr.span); self.insert_spec(&mut specs, id, (level, src)); @@ -287,7 +287,7 @@ impl<'s> LintLevelsBuilder<'s> { match result { Ok(ids) => { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(complete_name), li.span(), reason, @@ -324,7 +324,7 @@ impl<'s> LintLevelsBuilder<'s> { }, ); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(&new_lint_name), li.span(), reason, @@ -403,7 +403,7 @@ impl<'s> LintLevelsBuilder<'s> { } let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), + LintLevelSource::Node(name, span, _) => (name, span), _ => continue, }; @@ -460,7 +460,7 @@ impl<'s> LintLevelsBuilder<'s> { } /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) { + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { self.sets.get_lint_level(lint, self.cur, None, self.sess) } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index a61d37cc90eba..2dbb84970d106 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -13,7 +13,7 @@ use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { +pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. Default, @@ -27,25 +27,25 @@ pub enum LintSource { CommandLine(Symbol, Level), } -impl LintSource { +impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { - LintSource::Default => symbol::kw::Default, - LintSource::Node(name, _, _) => name, - LintSource::CommandLine(name, _) => name, + LintLevelSource::Default => symbol::kw::Default, + LintLevelSource::Node(name, _, _) => name, + LintLevelSource::CommandLine(name, _) => name, } } pub fn span(&self) -> Span { match *self { - LintSource::Default => DUMMY_SP, - LintSource::Node(_, span, _) => span, - LintSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::Default => DUMMY_SP, + LintLevelSource::Node(_, span, _) => span, + LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } } -pub type LevelSource = (Level, LintSource); +pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec, @@ -113,7 +113,7 @@ impl LintLevelSets { id: LintId, mut idx: u32, aux: Option<&FxHashMap>, - ) -> (Option, LintSource) { + ) -> (Option, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); @@ -125,7 +125,7 @@ impl LintLevelSets { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } - return (None, LintSource::Default); + return (None, LintLevelSource::Default); } LintSet::Node { ref specs, parent } => { if let Some(&(level, src)) = specs.get(&id) { @@ -213,7 +213,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, ) { @@ -223,7 +223,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: Box FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { @@ -274,14 +274,14 @@ pub fn struct_lint_level<'s, 'd>( let name = lint.name_lower(); match src { - LintSource::Default => { + LintLevelSource::Default => { sess.diag_note_once( &mut err, DiagnosticMessageId::from(lint), &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val, orig_level) => { + LintLevelSource::CommandLine(lint_flag_val, orig_level) => { let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", @@ -310,7 +310,7 @@ pub fn struct_lint_level<'s, 'd>( ); } } - LintSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(&rationale.as_str()); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4205e2ca5aa61..9b944f202a937 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -5,7 +5,7 @@ use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt}; use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -2559,7 +2559,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (Level, LintSource) { + ) -> (Level, LintLevelSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 52f6a97089bde..af5121d6b1be7 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -5,7 +5,7 @@ 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_lint::builtin::MISSING_DOCS; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -254,7 +254,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // `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, LintSource::Default); + 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, diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 1c1141e7c8122..17d2847913d4b 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -9,7 +9,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -77,7 +77,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); let (level, source) = cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); - level != lint::Level::Allow || matches!(source, LintSource::Default) + level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { From d3900d3775c665237b83ea87e01838da9cf0da87 Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:40:50 -0800 Subject: [PATCH 10/22] Document rustc_middle::lint::LevelSource This is to clarify the difference between `LevelSource` and `LintLevelSource`. Appease x.py fmt. --- compiler/rustc_lint/src/levels.rs | 4 +++- compiler/rustc_middle/src/lint.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 410bd06850e75..5cece569903c7 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,9 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; +use rustc_middle::lint::{ + struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, +}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 2dbb84970d106..d1a7e89734d2a 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -45,6 +45,7 @@ impl LintLevelSource { } } +/// A tuple of a lint level and its source. pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { From 163f5da322f7e62216532735c67813060eacc8de Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 17:18:48 -0800 Subject: [PATCH 11/22] Add installation commands to `x` tool README --- src/tools/x/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/x/README.md b/src/tools/x/README.md index 3b3cf2847c200..80bf02e8a0ef5 100644 --- a/src/tools/x/README.md +++ b/src/tools/x/README.md @@ -1,3 +1,10 @@ # x `x` invokes `x.py` from any subdirectory. + +To install, run the following commands: + +``` +$ cd rust/src/tools/x/ +$ cargo install --path . +``` From 9414f0b833734c344e795d590e9a845ce437c908 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:29:38 -0500 Subject: [PATCH 12/22] Revert "Remove missing_fragment_specifier lint" This reverts commit 5ba961018c482e050af908de60e4f8bd1a00f0ae. --- compiler/rustc_lint_defs/src/builtin.rs | 17 +++++++++++++++++ .../rustc/src/lints/listing/deny-by-default.md | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) delete mode 100644 src/doc/rustc/src/lints/listing/deny-by-default.md diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6a48b8f4dfbb2..de5253a84cc06 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1227,6 +1227,22 @@ declare_lint! { }; } +declare_lint! { + /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not + /// followed by a fragment specifier (e.g. `:expr`). + /// + /// This warning can always be fixed by removing the unused pattern in the + /// `macro_rules!` macro definition. + pub MISSING_FRAGMENT_SPECIFIER, + Deny, + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 ", + edition: None, + }; +} + declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. @@ -2827,6 +2843,7 @@ declare_lint_pass! { CONST_ITEM_MUTATION, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, + MISSING_FRAGMENT_SPECIFIER, LATE_BOUND_LIFETIME_ARGUMENTS, ORDER_DEPENDENT_TRAIT_OBJECTS, COHERENCE_LEAK_CHECK, diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md deleted file mode 100644 index 3c1452d64676c..0000000000000 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ /dev/null @@ -1,3 +0,0 @@ -# Deny-by-default lints - -This file is auto-generated by the lint-docs script. From f1eb88b28a84b0533ddd036a60bb5b8acbffabb2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:30:56 -0500 Subject: [PATCH 13/22] Revert "Promote missing_fragment_specifier to hard error" This reverts commit 02eae432e7476a0686633a8c2b7cb1d5aab1bd2c. --- compiler/rustc_expand/src/mbe.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 20 ++++++++++++++--- compiler/rustc_expand/src/mbe/macro_rules.rs | 15 +++++++------ compiler/rustc_expand/src/mbe/quoted.rs | 11 ++++++---- compiler/rustc_interface/src/passes.rs | 19 +++++++++++++++- compiler/rustc_session/src/parse.rs | 2 ++ src/test/ui/lint/expansion-time.rs | 4 ++++ src/test/ui/lint/expansion-time.stderr | 22 +++++++++++++++---- src/test/ui/macros/issue-39404.rs | 1 + src/test/ui/macros/issue-39404.stderr | 4 ++++ src/test/ui/macros/macro-match-nonterminal.rs | 1 + .../ui/macros/macro-match-nonterminal.stderr | 4 ++++ src/test/ui/parser/macro/issue-33569.rs | 1 - src/test/ui/parser/macro/issue-33569.stderr | 16 +++++--------- 14 files changed, 90 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index eb4aab116f00f..cbc4d14a65a1b 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -84,7 +84,7 @@ enum TokenTree { /// e.g., `$var` MetaVar(Span, Ident), /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. - MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind), + MetaVarDecl(Span, Ident /* name to bind */, Option), } impl TokenTree { diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3cf2d8f8ac1ef..0c44f5fe9e10a 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -378,6 +378,11 @@ fn nameize>( n_rec(sess, next_m, res.by_ref(), ret_val)?; } } + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Err((span, "missing fragment specifier".to_string())); + } + } TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val .entry(MacroRulesNormalizedIdent::new(bind_name)) { @@ -446,6 +451,7 @@ fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { /// /// A `ParseResult`. Note that matches are kept track of through the items generated. fn inner_parse_loop<'root, 'tt>( + sess: &ParseSess, cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, next_items: &mut Vec>, eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, @@ -563,9 +569,16 @@ fn inner_parse_loop<'root, 'tt>( }))); } + // We need to match a metavar (but the identifier is invalid)... this is an error + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Error(span, "missing fragment specifier".to_string()); + } + } + // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(span, _, kind) => { + TokenTree::MetaVarDecl(span, _, Some(kind)) => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. // @@ -640,6 +653,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. match inner_parse_loop( + parser.sess, &mut cur_items, &mut next_items, &mut eof_items, @@ -701,7 +715,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let nts = bb_items .iter() .map(|item| match item.top_elts.get_tt(item.idx) { - TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind), + TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind), _ => panic!(), }) .collect::>() @@ -731,7 +745,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na assert_eq!(bb_items.len(), 1); let mut item = bb_items.pop().unwrap(); - if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) { + if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 66463eeb90713..89d375b257da5 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -401,7 +401,7 @@ pub fn compile_declarative_macro( let diag = &sess.parse_sess.span_diagnostic; let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); - let tt_spec = NonterminalKind::TT; + let tt_spec = Some(NonterminalKind::TT); // Parse the macro_rules! invocation let (macro_rules, body) = match &def.kind { @@ -578,7 +578,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { TokenTree::Sequence(span, ref seq) => { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| match *seq_tt { - TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, TokenTree::Sequence(_, ref sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne @@ -961,7 +961,7 @@ fn check_matcher_core( // Now `last` holds the complete set of NT tokens that could // end the sequence before SUFFIX. Check that every one works with `suffix`. for token in &last.tokens { - if let TokenTree::MetaVarDecl(_, name, kind) = *token { + if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token { for next_token in &suffix_first.tokens { match is_in_follow(next_token, kind) { IsInFollow::Yes => {} @@ -1019,7 +1019,7 @@ fn check_matcher_core( } fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { - if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok { + if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok { frag_can_be_followed_by_any(kind) } else { // (Non NT's can always be followed by anything in matchers.) @@ -1123,7 +1123,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, - TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } @@ -1158,7 +1158,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { TokenTree::MetaVarDecl( _, _, - NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path, + Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path), ) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } @@ -1171,7 +1171,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match *tt { mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token), mbe::TokenTree::MetaVar(_, name) => format!("${}", name), - mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name), _ => panic!( "{}", "unexpected mbe::TokenTree::{Sequence or Delimited} \ diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 48db532c78f30..01b11bb979d68 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -3,7 +3,7 @@ use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream; -use rustc_ast::NodeId; +use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, Ident}; @@ -73,7 +73,7 @@ pub(super) fn parse( .emit(); token::NonterminalKind::Ident }); - result.push(TokenTree::MetaVarDecl(span, ident, kind)); + result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } _ => token.span, @@ -83,8 +83,11 @@ pub(super) fn parse( } tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), }; - sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit(); - continue; + if node_id != DUMMY_NODE_ID { + // Macros loaded from other crates have dummy node ids. + sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id); + } + result.push(TokenTree::MetaVarDecl(span, ident, None)); } // Not a metavar or no matchers allowed, so just return the tree diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c13d26c79d738..a8c8690b9e7fa 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -29,6 +29,7 @@ use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; +use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; @@ -306,11 +307,27 @@ fn configure_and_expand_inner<'a>( ecx.check_unused_macros(); }); + let mut missing_fragment_specifiers: Vec<_> = ecx + .sess + .parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .map(|(span, node_id)| (*span, *node_id)) + .collect(); + missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span); + + let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); + + for (span, node_id) in missing_fragment_specifiers { + let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; + let msg = "missing fragment specifier"; + resolver.lint_buffer().buffer_lint(lint, node_id, span, msg); + } if cfg!(windows) { env::set_var("PATH", &old_path); } - let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); if recursion_limit_hit { // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed // with a large AST diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 66c3738fb5b5a..b1a4834241730 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -119,6 +119,7 @@ pub struct ParseSess { pub unstable_features: UnstableFeatures, pub config: CrateConfig, pub edition: Edition, + pub missing_fragment_specifiers: Lock>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock>, /// Used to determine and report recursive module inclusions. @@ -152,6 +153,7 @@ impl ParseSess { unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, + missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), included_mod_stack: Lock::new(vec![]), source_map, diff --git a/src/test/ui/lint/expansion-time.rs b/src/test/ui/lint/expansion-time.rs index a9c7ac363b0b3..f23c7cb0dca14 100644 --- a/src/test/ui/lint/expansion-time.rs +++ b/src/test/ui/lint/expansion-time.rs @@ -5,6 +5,10 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } +#[warn(missing_fragment_specifier)] +macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier + //~| WARN this was previously accepted + #[warn(soft_unstable)] mod benches { #[bench] //~ WARN use of unstable library feature 'test' diff --git a/src/test/ui/lint/expansion-time.stderr b/src/test/ui/lint/expansion-time.stderr index 24e2733064e48..b0fc1f8e5eec7 100644 --- a/src/test/ui/lint/expansion-time.stderr +++ b/src/test/ui/lint/expansion-time.stderr @@ -12,14 +12,28 @@ note: the lint level is defined here LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ +warning: missing fragment specifier + --> $DIR/expansion-time.rs:9:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:8:8 + | +LL | #[warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable - --> $DIR/expansion-time.rs:10:7 + --> $DIR/expansion-time.rs:14:7 | LL | #[bench] | ^^^^^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 + --> $DIR/expansion-time.rs:12:8 | LL | #[warn(soft_unstable)] | ^^^^^^^^^^^^^ @@ -33,10 +47,10 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:25:8 + --> $DIR/expansion-time.rs:29:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/src/test/ui/macros/issue-39404.rs b/src/test/ui/macros/issue-39404.rs index 054958ba00b8d..2229f2c3900c3 100644 --- a/src/test/ui/macros/issue-39404.rs +++ b/src/test/ui/macros/issue-39404.rs @@ -2,5 +2,6 @@ macro_rules! m { ($i) => {} } //~^ ERROR missing fragment specifier +//~| WARN previously accepted fn main() {} diff --git a/src/test/ui/macros/issue-39404.stderr b/src/test/ui/macros/issue-39404.stderr index 645f06e59d817..d2f2a823c2a6b 100644 --- a/src/test/ui/macros/issue-39404.stderr +++ b/src/test/ui/macros/issue-39404.stderr @@ -3,6 +3,10 @@ error: missing fragment specifier | LL | macro_rules! m { ($i) => {} } | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to previous error diff --git a/src/test/ui/macros/macro-match-nonterminal.rs b/src/test/ui/macros/macro-match-nonterminal.rs index 6b023e4137274..b23e5c71c03f0 100644 --- a/src/test/ui/macros/macro-match-nonterminal.rs +++ b/src/test/ui/macros/macro-match-nonterminal.rs @@ -2,6 +2,7 @@ macro_rules! test { ($a, $b) => { //~^ ERROR missing fragment //~| ERROR missing fragment + //~| WARN this was previously accepted () }; } diff --git a/src/test/ui/macros/macro-match-nonterminal.stderr b/src/test/ui/macros/macro-match-nonterminal.stderr index 334d62812cdab..674ce3434aac6 100644 --- a/src/test/ui/macros/macro-match-nonterminal.stderr +++ b/src/test/ui/macros/macro-match-nonterminal.stderr @@ -9,6 +9,10 @@ error: missing fragment specifier | LL | ($a, $b) => { | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/issue-33569.rs b/src/test/ui/parser/macro/issue-33569.rs index cf81f0480a2a7..80e2d7c6545ba 100644 --- a/src/test/ui/parser/macro/issue-33569.rs +++ b/src/test/ui/parser/macro/issue-33569.rs @@ -2,7 +2,6 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` - //~^ ERROR attempted to repeat an expression containing no syntax variables } } diff --git a/src/test/ui/parser/macro/issue-33569.stderr b/src/test/ui/parser/macro/issue-33569.stderr index f54efaa6996f2..b4d38d3ce4806 100644 --- a/src/test/ui/parser/macro/issue-33569.stderr +++ b/src/test/ui/parser/macro/issue-33569.stderr @@ -4,23 +4,17 @@ error: expected identifier, found `+` LL | { $+ } => { | ^ -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 - | -LL | { $+ } => { - | ^ - error: expected one of: `*`, `+`, or `?` --> $DIR/issue-33569.rs:4:13 | LL | $(x)(y) | ^^^ -error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth - --> $DIR/issue-33569.rs:4:10 +error: missing fragment specifier + --> $DIR/issue-33569.rs:2:8 | -LL | $(x)(y) - | ^^^ +LL | { $+ } => { + | ^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 56154a11473da93da0f5d57f4692991ae4972695 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 20 Dec 2020 21:44:27 -0500 Subject: [PATCH 14/22] Add example to lint docs --- compiler/rustc_lint_defs/src/builtin.rs | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index de5253a84cc06..1c692d4f20762 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1228,12 +1228,40 @@ declare_lint! { } declare_lint! { - /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// The `missing_fragment_specifier` lint is issued when an unused pattern in a /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not /// followed by a fragment specifier (e.g. `:expr`). /// /// This warning can always be fixed by removing the unused pattern in the /// `macro_rules!` macro definition. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! foo { + /// () => {}; + /// ($name) => { }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: + /// + /// ```rust + /// macro_rules! foo { + /// () => {}; + /// } + /// fn main() { + /// foo!(); + /// } + /// ``` pub MISSING_FRAGMENT_SPECIFIER, Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", From a6d377d56560350976ccb46f33ae14ad65eb9372 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 22 Dec 2020 16:33:36 -0800 Subject: [PATCH 15/22] Include rustdoc in the compiler docs index. --- src/bootstrap/doc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8cacc2512eff1..30a8229036fd8 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -628,6 +628,8 @@ impl Step for Rustdoc { cargo.arg("-p").arg("rustdoc"); cargo.rustdocflag("--document-private-items"); + cargo.rustdocflag("--enable-index-page"); + cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } } From 732afd41cff1d562e03a6e1611ef7baf9d7f5962 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Sat, 19 Dec 2020 22:36:35 +1100 Subject: [PATCH 16/22] Exclude unnecessary info from CodegenResults `foreign_module` and `wasm_import_module` are not needed for linking, and hence can be removed from CodegenResults. --- compiler/rustc_codegen_ssa/src/back/link.rs | 5 +++-- compiler/rustc_codegen_ssa/src/base.rs | 5 +++-- compiler/rustc_codegen_ssa/src/lib.rs | 21 ++++++++++++++++++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ccd4d103ddb7f..a3a2ef0417568 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{EncodedMetadata, LibSource}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet}; @@ -22,7 +22,8 @@ use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; use crate::{ - looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME, + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, + METADATA_FILENAME, }; use cc::windows_registry; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 21138f967a273..18132a2c7a3c0 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -766,7 +766,7 @@ impl CrateInfo { profiler_runtime: None, is_no_builtins: Default::default(), native_libraries: Default::default(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), + used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), link_args: tcx.link_args(LOCAL_CRATE), crate_name: Default::default(), used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), @@ -787,7 +787,8 @@ impl CrateInfo { info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.native_libraries + .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); if tcx.is_panic_runtime(cnum) { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ee889d552412e..bc93bd8b7bd96 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,15 +21,17 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{self, CrateSource, LibSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -105,6 +107,19 @@ bitflags::bitflags! { } } +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct NativeLib { + pub kind: NativeLibKind, + pub name: Option, + pub cfg: Option, +} + +impl From<&cstore::NativeLib> for NativeLib { + fn from(lib: &cstore::NativeLib) -> Self { + NativeLib { kind: lib.kind.clone(), name: lib.name.clone(), cfg: lib.cfg.clone() } + } +} + /// Misc info we load from metadata to persist beyond the tcx. /// /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` @@ -119,9 +134,9 @@ pub struct CrateInfo { pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>>, + pub native_libraries: FxHashMap>, pub crate_name: FxHashMap, - pub used_libraries: Lrc>, + pub used_libraries: Vec, pub link_args: Lrc>, pub used_crate_source: FxHashMap>, pub used_crates_static: Vec<(CrateNum, LibSource)>, From e8a564edc0a0c19633039848c68d5f81fcfcc00d Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Wed, 23 Dec 2020 12:17:45 +1100 Subject: [PATCH 17/22] Add a test that rustc compiles and links separately --- src/test/run-make-fulldeps/separate-link/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/test/run-make-fulldeps/separate-link/Makefile diff --git a/src/test/run-make-fulldeps/separate-link/Makefile b/src/test/run-make-fulldeps/separate-link/Makefile new file mode 100644 index 0000000000000..060484e89f930 --- /dev/null +++ b/src/test/run-make-fulldeps/separate-link/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + echo 'fn main(){}' | $(RUSTC) -Z no-link - + $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink + $(call RUN,rust_out) From 1a30823370d64f4dc5e55b3832c47774aa87179c Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Tue, 22 Dec 2020 14:02:07 -0800 Subject: [PATCH 18/22] Improvements to NatVis support NatVis files describe how to display types in some Windows debuggers, such as Visual Studio, WinDbg, and VS Code. This commit makes several improvements: * Adds visualizers for Rc, Weak, and Arc. * Changes [size] to [len], for consistency with the Rust API. Visualizers often use [size] to mirror the size() method on C++ STL collections. * Several visualizers used the PVOID and ULONG typedefs. These are part of the Windows API; they are not guaranteed to always be defined in a pure Rust DLL/EXE. I converted PVOID to `void*` and `ULONG` to `unsigned long`. * Cosmetic change: Removed {} braces around the visualized display for `Option` types. They now display simply as `Some(value)` or `None`, which reflects what is written in source code. * The visualizer for `alloc::string::String` makes assumptions about the layout of `String` (it casts `String*` to another type), rather than using symbolic expressions. This commit changes the visualizer so that it simply uses symbolic expressions to access the string data and string length. --- src/etc/natvis/intrinsic.natvis | 18 ++++++++----- src/etc/natvis/liballoc.natvis | 46 ++++++++++++++++++++++++--------- src/etc/natvis/libcore.natvis | 26 +++++++------------ src/etc/natvis/libstd.natvis | 8 +++--- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 874550da8b0c9..030892a432b31 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -4,17 +4,21 @@ {data_ptr,[length]s8} data_ptr,[length]s8 - length - - length - data_ptr - + length + + + + length + data_ptr + + + - {{ length={length} }} + {{ len={length} }} - length + length length data_ptr diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index de30b58526a13..cfaafc5734bce 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -1,9 +1,9 @@ - {{ size={len} }} + {{ len={len} }} - len + len buf.cap len @@ -12,9 +12,9 @@ - {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} + {{ len={tail <= head ? head - tail : buf.cap - tail + head} }} - tail <= head ? head - tail : buf.cap - tail + head + tail <= head ? head - tail : buf.cap - tail + head buf.cap @@ -31,7 +31,7 @@ - {{ size={len} }} + {{ len={len} }} len @@ -42,15 +42,37 @@ - {*(char**)this,[vec.len]s8} - *(char**)this,[vec.len]s8 + {(char*)vec.buf.ptr.pointer,[vec.len]s8} + (char*)vec.buf.ptr.pointer,[vec.len]s8 - vec.len + vec.len vec.buf.cap - - vec.len - *(char**)this - + + + + vec.len + (char*)vec.buf.ptr.pointer + + + + + + + {ptr.pointer->value} + + ptr.pointer->value + + + + {ptr.pointer->data} + + ptr.pointer->data + + + + {ptr.pointer->data} + + ptr.pointer->data diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 0e703b3b95026..984a8bfb13c7c 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -6,34 +6,28 @@ pointer + {{ Shared {pointer} }} pointer + - {{ None }} - {{ Some {__0} }} + None + Some({__0}) - (ULONG)(RUST$ENUM$DISR != 0) - __0 - - (ULONG)(RUST$ENUM$DISR != 0) - &__0 - + __0 + - {{ None }} - {{ Some {($T1 *)this} }} + None + Some({($T1 *)this}) - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - + ($T1 *)this + \ No newline at end of file diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index 9550c25f2fcfe..7e5ee7b13daf1 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -26,9 +26,9 @@ --> - {{ size={base.table.items} }} + {{ len={base.table.items} }} - base.table.items + base.table.items base.table.items + base.table.growth_left base.hash_builder @@ -50,9 +50,9 @@ - {{ size={base.map.table.items} }} + {{ len={base.map.table.items} }} - base.map.table.items + base.map.table.items base.map.table.items + base.map.table.growth_left base.map.hash_builder From 619c2001c7e2c9b7de55838001b1881134dfea40 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 20 Dec 2020 00:34:49 +0100 Subject: [PATCH 19/22] Make doc-test pass with the new rustdoc --- compiler/rustc_trait_selection/src/opaque_types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index f5bc90e6f9621..e8c7e380e749f 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -46,6 +46,7 @@ pub struct OpaqueTypeDecl<'tcx> { /// type Foo = impl Baz; /// fn bar() -> Foo { /// // ^^^ This is the span we are looking for! + /// } /// ``` /// /// In cases where the fn returns `(impl Trait, impl Trait)` or From f459b0fea5723010bf1654d8073389fd0a0263d1 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 18:55:37 +0000 Subject: [PATCH 20/22] Addressed feedbacks Also updated the mir-opt test output files. --- compiler/rustc_mir/src/util/pretty.rs | 20 +++---------------- .../checked_add.main.ConstProp.diff | 3 --- .../const_prop/indirect.main.ConstProp.diff | 3 --- .../issue_67019.main.ConstProp.diff | 3 --- ...ble_variable_aggregate.main.ConstProp.diff | 3 --- ...es_into_variable.main.ConstProp.32bit.diff | 3 --- ...es_into_variable.main.ConstProp.64bit.diff | 3 --- .../return_place.add.ConstProp.diff | 3 --- ...le_literal_propagation.main.ConstProp.diff | 3 --- ...ves_unused_consts.main.SimplifyLocals.diff | 3 --- 10 files changed, 3 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 9b81629400a66..394eb8334223c 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,6 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -414,22 +413,9 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => { - // could have used `try_fold` here but it seems a bit silly that - // the accumulator is useless - let mut should_be_verbose = false; - for g_arg in g_args.iter() { - if match g_arg.unpack() { - GenericArgKind::Type(ty) => use_verbose(&ty), - GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), - _ => false, - } { - should_be_verbose = true; - break; - } - } - should_be_verbose - } + ty::Tuple(g_args) => g_args.iter().any(|g_arg| { + use_verbose(&g_arg.expect_ty()) + }), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index f01676b6da863..3397ef95856a5 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -14,9 +14,6 @@ - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/checked_add.rs:5:18: 5:23 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index 8c7b35887c915..9ddb34e58e5a6 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -18,9 +18,6 @@ - assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 -+ // ty::Const -+ // + ty: (u8, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/indirect.rs:5:13: 5:29 + // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 492938fc206bd..da35bf18c7116 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -15,9 +15,6 @@ (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 - (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 -+ // ty::Const -+ // + ty: (u8, u8) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/issue-67019.rs:11:10: 11:19 + // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 204c1acecf548..12b02e90345d9 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -20,9 +20,6 @@ StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 -+ // ty::Const -+ // + ty: (i32, i32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 53ffc01ccaf25..a10bac4f3ea3b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 53ffc01ccaf25..a10bac4f3ea3b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index fc8a5437232cf..f0e9916e6300e 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -9,9 +9,6 @@ - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/return_place.rs:6:5: 6:10 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 2de1ab19b7c3d..da4b135d4c6d6 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -18,9 +18,6 @@ StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 - _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 + _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 -+ // ty::Const -+ // + ty: (u32, u32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14 + // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index 3064e92f90007..34f8ca870cd23 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -42,9 +42,6 @@ // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar()) } - // ty::Const - // + ty: ((), ()) - // + val: Value(Scalar()) // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // + literal: Const { ty: ((), ()), val: Value(Scalar()) } From ecba49c1bd6e16235e13a076e03e31fcd8d7ffc8 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:10:59 +0000 Subject: [PATCH 21/22] Fixed formatting --- compiler/rustc_mir/src/util/pretty.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 394eb8334223c..34ec16d9f2916 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -413,9 +413,7 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => g_args.iter().any(|g_arg| { - use_verbose(&g_arg.expect_ty()) - }), + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, From 152d4e74bec46c08e388b47f3c5693929caf377f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 23 Dec 2020 20:27:12 +0100 Subject: [PATCH 22/22] Update HTML DOM attribute "edition" to "data-edition" --- src/librustdoc/html/highlight.rs | 2 +- src/librustdoc/html/static/rustdoc.css | 2 +- src/test/rustdoc/codeblock-title.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 47d2707e40dfc..077481c89895e 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -30,7 +30,7 @@ crate fn render_with_highlighting( "
", class, if let Some(edition_info) = edition_info { - format!(" edition=\"{}\"", edition_info) + format!(" data-edition=\"{}\"", edition_info) } else { String::new() }, diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index afc4308b68f93..0b40480f738da 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1098,7 +1098,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { content: "This example panics"; } .tooltip.edition::after { - content: "This code runs with edition " attr(edition); + content: "This code runs with edition " attr(data-edition); } .tooltip::before { diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs index 1327fd67d316b..140c5b3a67203 100644 --- a/src/test/rustdoc/codeblock-title.rs +++ b/src/test/rustdoc/codeblock-title.rs @@ -3,7 +3,7 @@ // @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ" // @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ" // @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ" -// @has foo/fn.bar.html '//*[@edition="2018"]' "ⓘ" +// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ" /// foo ///