From a0f9d4beec3a89eec88289701c152a69d488487b Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 15 Sep 2020 16:18:05 -0700 Subject: [PATCH 01/15] Enable smart punctuation --- src/librustdoc/html/markdown.rs | 3 ++- src/test/rustdoc/inline_cross/add-docs.rs | 2 +- src/test/rustdoc/smart-punct.rs | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/smart-punct.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a81fd55f6f192..34bda2b7883ea 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -52,11 +52,12 @@ pub(crate) fn opts() -> Options { | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH | Options::ENABLE_TASKLISTS + | Options::ENABLE_SMART_PUNCTUATION } /// A subset of [`opts()`] used for rendering summaries. pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH + Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION } /// When `to_string` is called, this struct will emit the HTML corresponding to diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs index 1af5e8f03b44e..8f0c4e5e64184 100644 --- a/src/test/rustdoc/inline_cross/add-docs.rs +++ b/src/test/rustdoc/inline_cross/add-docs.rs @@ -4,6 +4,6 @@ extern crate inner; // @has add_docs/struct.MyStruct.html -// @has add_docs/struct.MyStruct.html "Doc comment from 'pub use', Doc comment from definition" +// @has add_docs/struct.MyStruct.html "Doc comment from ‘pub use’, Doc comment from definition" /// Doc comment from 'pub use', pub use inner::MyStruct; diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs new file mode 100644 index 0000000000000..5c4530c97a9b3 --- /dev/null +++ b/src/test/rustdoc/smart-punct.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +//! This is the "start" of the 'document'! How'd you know that "it's" the start? +//! +//! # Header with "smart punct'" +//! +//! [link with "smart punct'" -- yessiree!][] +//! +//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org + +// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" +// @has "foo/index.html" "//h1" "Header with “smart punct’”" +// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" From f1581ed8fc752417a02d7664067e6895d2f448eb Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 7 Feb 2021 19:54:54 -0800 Subject: [PATCH 02/15] Test that code does not get smart-punctuated --- src/test/rustdoc/smart-punct.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index 5c4530c97a9b3..ce166b7906459 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + #![crate_name = "foo"] //! This is the "start" of the 'document'! How'd you know that "it's" the start? @@ -7,7 +9,22 @@ //! [link with "smart punct'" -- yessiree!][] //! //! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org +//! +//! # Code should not be smart-punct'd +//! +//! `this inline code -- it shouldn't have "smart punct"` +//! +//! ``` +//! let x = "don't smart-punct me -- please!"; +//! ``` +//! +//! ```text +//! I say "don't smart-punct me -- please!" +//! ``` // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" // @has "foo/index.html" "//h1" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" +// @has "foo/index.html" '//code' 'this inline code -- it shouldn\'t have "smart punct"' +// @has "foo/index.html" '//pre' 'let x = "don\'t smart-punct me -- please!";' +// @has "foo/index.html" '//pre' 'I say "don\'t smart-punct me -- please!"' From e4b83fcad48dc78e0d0753d4441ffdb34121b1c2 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 7 Feb 2021 20:12:26 -0800 Subject: [PATCH 03/15] Document smart punctuation --- .../rustdoc/src/how-to-write-documentation.md | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 9938cddc94106..688be7aedea38 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -101,7 +101,7 @@ what an item is, how it is used, and for what purpose it exists. Let's see an example coming from the [standard library] by taking a look at the [`std::env::args()`][env::args] function: -``````text +``````markdown Returns the arguments which this program was started with (normally passed via the command line). @@ -135,7 +135,7 @@ for argument in env::args() { Everything before the first empty line will be reused to describe the component in searches and module overviews. For example, the function `std::env::args()` -above will be shown on the [`std::env`] module documentation. It is good +above will be shown on the [`std::env`] module documentation. It is good practice to keep the summary to one line: concise writing is a goal of good documentation. @@ -153,9 +153,10 @@ and finally provides a code example. ## Markdown -`rustdoc` uses the [CommonMark markdown specification]. You might be -interested into taking a look at their website to see what's possible to do. - - [commonmark quick reference] +`rustdoc` uses the [CommonMark Markdown specification]. You might be +interested in taking a look at their website to see what's possible: + + - [CommonMark quick reference] - [current spec] In addition to the standard CommonMark syntax, `rustdoc` supports several @@ -240,6 +241,21 @@ This will render as See the specification for the [task list extension] for more details. +### Smart punctuation + +Some ASCII punctuation sequences will be automatically turned into fancy Unicode +characters: + +| ASCII sequence | Unicode | +|----------------|---------| +| `--` | – | +| `---` | — | +| `...` | … | +| `"` | “ or ”, depending on context | +| `'` | ‘ or ’, depending on context | + +So, no need to manually enter those Unicode characters! + [`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/ [commonmark markdown specification]: https://commonmark.org/ [commonmark quick reference]: https://commonmark.org/help/ From 0a3452110c605655e7ab949c0904f053ab0cc71b Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 8 Feb 2021 15:49:04 -0800 Subject: [PATCH 04/15] Fix `@has` checks "no closing quotation" error Apparently `"foo\""` has different behavior from `'foo\''` in Python shlex. See the [discussion on Zulip][z] for more. [z]: https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/.40has.20checks.20.22no.20closing.20quotation.22 --- src/test/rustdoc/smart-punct.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index ce166b7906459..a1ca2699554e5 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -25,6 +25,6 @@ // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" // @has "foo/index.html" "//h1" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" -// @has "foo/index.html" '//code' 'this inline code -- it shouldn\'t have "smart punct"' -// @has "foo/index.html" '//pre' 'let x = "don\'t smart-punct me -- please!";' -// @has "foo/index.html" '//pre' 'I say "don\'t smart-punct me -- please!"' +// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" +// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" +// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\"" From 1b29b2920033a48ec950a4b4b74402029a155a50 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 8 Feb 2021 16:49:11 -0800 Subject: [PATCH 05/15] Update Markdown unit tests --- src/librustdoc/html/markdown/tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 9da3072ec282f..dceafd6458c41 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -201,8 +201,8 @@ fn test_short_markdown_summary() { t("Hard-break \nsummary", "Hard-break summary"); t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); - t("code `let x = i32;` ...", "code let x = i32; ..."); - t("type `Type<'static>` ...", "type Type<'static> ..."); + t("code `let x = i32;` ...", "code let x = i32; …"); + t("type `Type<'static>` ...", "type Type<'static> …"); t("# top header", "top header"); t("## header", "header"); t("first paragraph\n\nsecond paragraph", "first paragraph"); @@ -227,8 +227,8 @@ fn test_plain_text_summary() { t("Hard-break \nsummary", "Hard-break summary"); t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); - t("code `let x = i32;` ...", "code `let x = i32;` ..."); - t("type `Type<'static>` ...", "type `Type<'static>` ..."); + t("code `let x = i32;` ...", "code `let x = i32;` …"); + t("type `Type<'static>` ...", "type `Type<'static>` …"); t("# top header", "top header"); t("## header", "header"); t("first paragraph\n\nsecond paragraph", "first paragraph"); @@ -250,6 +250,6 @@ fn test_markdown_html_escape() { } t("`Struct<'a, T>`", "

Struct<'a, T>

\n"); - t("Struct<'a, T>", "

Struct<'a, T>

\n"); + t("Struct<'a, T>", "

Struct<’a, T>

\n"); t("Struct
", "

Struct<br>

\n"); } From eeb555266764069937491a26e817d4bcfea5da3a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Feb 2021 20:24:50 +0100 Subject: [PATCH 06/15] Remove query parameters when leaving search results --- src/librustdoc/html/static/main.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ec89ae0228c5e..e8daa8414a274 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -101,7 +101,7 @@ function focusSearchBar() { getSearchInput().focus(); } -// Removes the focus from the search bar +// Removes the focus from the search bar. function defocusSearchBar() { getSearchInput().blur(); } @@ -220,6 +220,11 @@ function defocusSearchBar() { addClass(search, "hidden"); removeClass(main, "hidden"); document.title = titleBeforeSearch; + // We also remove the query parameter from the URL. + if (browserSupportsHistoryApi()) { + history.replaceState("", window.currentCrate + " - Rust", + getNakedUrl() + window.location.hash); + } } // used for special search precedence From 343b67387772dbd068d06a76267288579d3eaed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 19 Feb 2021 00:00:00 +0000 Subject: [PATCH 07/15] Consider auto derefs before warning about write only fields Changes from 81473 extended the dead code lint with an ability to detect fields that are written to but never read from. The implementation skips over fields on the left hand side of an assignment, without marking them as live. A field access might involve an automatic dereference and de-facto read the field. Conservatively mark expressions with deref adjustments as live to avoid generating false positive warnings. --- compiler/rustc_passes/src/dead.rs | 28 ++++++----- .../ui/lint/dead-code/write-only-field.rs | 49 +++++++++++++++++++ .../ui/lint/dead-code/write-only-field.stderr | 20 +++++++- 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d51b501f7ae3d..62a95aa57c29f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -37,15 +37,6 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { ) } -fn base_expr<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - loop { - match expr.kind { - hir::ExprKind::Field(base, ..) => expr = base, - _ => return expr, - } - } -} - struct MarkSymbolVisitor<'tcx> { worklist: Vec, tcx: TyCtxt<'tcx>, @@ -143,6 +134,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if self + .typeck_results() + .expr_adjustments(expr) + .iter() + .any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) + { + self.visit_expr(expr); + } else if let hir::ExprKind::Field(base, ..) = expr.kind { + // Ignore write to field + self.handle_assign(base); + } else { + self.visit_expr(expr); + } + } + fn handle_field_pattern_match( &mut self, lhs: &hir::Pat<'_>, @@ -272,8 +279,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.lookup_and_handle_method(expr.hir_id); } hir::ExprKind::Assign(ref left, ref right, ..) => { - // Ignore write to field - self.visit_expr(base_expr(left)); + self.handle_assign(left); self.visit_expr(right); return; } diff --git a/src/test/ui/lint/dead-code/write-only-field.rs b/src/test/ui/lint/dead-code/write-only-field.rs index 78cfcfda8f971..7b3f1e9f5b6cb 100644 --- a/src/test/ui/lint/dead-code/write-only-field.rs +++ b/src/test/ui/lint/dead-code/write-only-field.rs @@ -17,4 +17,53 @@ fn field_write(s: &mut S) { fn main() { let mut s = S { f: 0, sub: Sub { f: 0 } }; field_write(&mut s); + + auto_deref(); + nested_boxes(); +} + +fn auto_deref() { + struct E { + x: bool, + y: bool, //~ ERROR: field is never read + } + + struct P<'a> { + e: &'a mut E + } + + impl P<'_> { + fn f(&mut self) { + self.e.x = true; + self.e.y = true; + } + } + + let mut e = E { x: false, y: false }; + let mut p = P { e: &mut e }; + p.f(); + assert!(e.x); +} + +fn nested_boxes() { + struct A { + b: Box, + } + + struct B { + c: Box, + } + + struct C { + u: u32, //~ ERROR: field is never read + v: u32, //~ ERROR: field is never read + } + + let mut a = A { + b: Box::new(B { + c: Box::new(C { u: 0, v: 0 }), + }), + }; + a.b.c.v = 10; + a.b.c = Box::new(C { u: 1, v: 2 }); } diff --git a/src/test/ui/lint/dead-code/write-only-field.stderr b/src/test/ui/lint/dead-code/write-only-field.stderr index 70d2149665b20..a191d22c8b94c 100644 --- a/src/test/ui/lint/dead-code/write-only-field.stderr +++ b/src/test/ui/lint/dead-code/write-only-field.stderr @@ -22,5 +22,23 @@ error: field is never read: `f` LL | f: i32, | ^^^^^^ -error: aborting due to 3 previous errors +error: field is never read: `y` + --> $DIR/write-only-field.rs:28:9 + | +LL | y: bool, + | ^^^^^^^ + +error: field is never read: `u` + --> $DIR/write-only-field.rs:58:9 + | +LL | u: u32, + | ^^^^^^ + +error: field is never read: `v` + --> $DIR/write-only-field.rs:59:9 + | +LL | v: u32, + | ^^^^^^ + +error: aborting due to 6 previous errors From a00eb7ee1d8f5b38b94410940e87af9c10ed458a Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 00:43:02 +0000 Subject: [PATCH 08/15] Add @is command to jsondocck --- src/test/rustdoc-json/nested.rs | 20 ++++++++++---------- src/tools/jsondocck/src/main.rs | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 7e705255d983d..f32692b70cd2b 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -1,24 +1,24 @@ // edition:2018 -// @has nested.json "$.index[*][?(@.name=='nested')].kind" \"module\" -// @has - "$.index[*][?(@.name=='nested')].inner.is_crate" true +// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\" +// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true // @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1 -// @has nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" -// @has - "$.index[*][?(@.name=='l1')].inner.is_crate" false +// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" +// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 pub mod l1 { - // @has nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" - // @has - "$.index[*][?(@.name=='l3')].inner.is_crate" false + // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" + // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 pub mod l3 { - // @has nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" - // @has - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" + // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" pub struct L4; } - // @has nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" - // @has - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false + // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" + // @is - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false pub use l3::L4; } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 6ec292aba6495..2afb66b969685 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -48,13 +48,14 @@ pub struct Command { pub enum CommandKind { Has, Count, + Is, } impl CommandKind { fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool { let count = match self { CommandKind::Has => (1..=3).contains(&args.len()), - CommandKind::Count => 3 == args.len(), + CommandKind::Count | CommandKind::Is => 3 == args.len(), }; if !count { @@ -83,6 +84,7 @@ impl fmt::Display for CommandKind { let text = match self { CommandKind::Has => "has", CommandKind::Count => "count", + CommandKind::Is => "is", }; write!(f, "{}", text) } @@ -127,6 +129,7 @@ fn get_commands(template: &str) -> Result, ()> { let cmd = match cmd { "has" => CommandKind::Has, "count" => CommandKind::Count, + "is" => CommandKind::Is, _ => { print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); errors = true; @@ -180,6 +183,7 @@ fn get_commands(template: &str) -> Result, ()> { /// Performs the actual work of ensuring a command passes. Generally assumes the command /// is syntactically valid. fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { + // FIXME: Be more granular about why, (eg syntax error, count not equal) let result = match command.kind { CommandKind::Has => { match command.args.len() { @@ -220,6 +224,18 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Err(_) => false, } } + CommandKind::Is => { + // @has = check *exactly one* item matched by path, and it equals value + assert_eq!(command.args.len(), 3); + let val = cache.get_value(&command.args[0])?; + match select(&val, &command.args[1]) { + Ok(results) => { + let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); + results.len() == 1 && *results[0] == pat + } + Err(_) => false, + } + } }; if result == command.negated { From cd5f603c314edcf2d75656ac86fc1d303aacfb83 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 01:25:09 +0000 Subject: [PATCH 09/15] Implement @set --- src/test/rustdoc-json/nested.rs | 3 +++ src/tools/jsondocck/src/cache.rs | 2 ++ src/tools/jsondocck/src/main.rs | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index f32692b70cd2b..2e0179113acf4 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -7,15 +7,18 @@ // @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" // @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 +// @set l1_id = - "$.index[*][?(@.name=='l1')].id" pub mod l1 { // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 + // @set l3_id = - "$.index[*][?(@.name=='l3')].id" pub mod l3 { // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @set l4_id = - "$.index[*][?(@.name=='L4')].id" pub struct L4; } // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index b742f0eb3ee55..8a6a911321c34 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -9,6 +9,7 @@ pub struct Cache { root: PathBuf, files: HashMap, values: HashMap, + pub variables: HashMap, last_path: Option, } @@ -19,6 +20,7 @@ impl Cache { root: Path::new(doc_dir).to_owned(), files: HashMap::new(), values: HashMap::new(), + variables: HashMap::new(), last_path: None, } } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 2afb66b969685..9f231842c60ea 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -49,6 +49,7 @@ pub enum CommandKind { Has, Count, Is, + Set, } impl CommandKind { @@ -56,6 +57,7 @@ impl CommandKind { let count = match self { CommandKind::Has => (1..=3).contains(&args.len()), CommandKind::Count | CommandKind::Is => 3 == args.len(), + CommandKind::Set => 4 == args.len(), }; if !count { @@ -85,6 +87,7 @@ impl fmt::Display for CommandKind { CommandKind::Has => "has", CommandKind::Count => "count", CommandKind::Is => "is", + CommandKind::Set => "set", }; write!(f, "{}", text) } @@ -130,6 +133,7 @@ fn get_commands(template: &str) -> Result, ()> { "has" => CommandKind::Has, "count" => CommandKind::Count, "is" => CommandKind::Is, + "set" => CommandKind::Set, _ => { print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); errors = true; @@ -236,6 +240,23 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Err(_) => false, } } + // FIXME, Figure out semantics for @!set + CommandKind::Set => { + // @set = + assert_eq!(command.args.len(), 4); + assert_eq!(command.args[1], "=", "Expected an `=`"); + let val = cache.get_value(&command.args[2])?; + + match select(&val, &command.args[3]) { + Ok(results) => { + assert_eq!(results.len(), 1); + let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); + assert!(r.is_none(), "Name collision"); + true + } + Err(_) => false, + } + } }; if result == command.negated { From dd4b938c7f0c7704582a786f973bcfb17e523e94 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 20 Feb 2021 01:47:17 +0000 Subject: [PATCH 10/15] Implement using @set values --- src/test/rustdoc-json/nested.rs | 3 ++- src/tools/jsondocck/src/main.rs | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 2e0179113acf4..a3d4935f49614 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -7,18 +7,19 @@ // @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" // @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 -// @set l1_id = - "$.index[*][?(@.name=='l1')].id" pub mod l1 { // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 // @set l3_id = - "$.index[*][?(@.name=='l3')].id" + // @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id pub mod l3 { // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" // @set l4_id = - "$.index[*][?(@.name=='L4')].id" + // @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id pub struct L4; } // @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 9f231842c60ea..8cb9564531a98 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -207,9 +207,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); - - !results.is_empty() && results.into_iter().any(|val| *val == pat) + // FIXME: Share the pat getting code with the `Is` branch. + let v_holder; + let pat: &Value = if command.args[2].starts_with("$") { + &cache.variables[&command.args[2][1..]] + } else { + v_holder = serde_json::from_str(&command.args[2]).unwrap(); + &v_holder + }; + !results.is_empty() && results.into_iter().any(|val| val == pat) } Err(_) => false, } @@ -234,8 +240,14 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let pat: Value = serde_json::from_str(&command.args[2]).unwrap(); - results.len() == 1 && *results[0] == pat + let v_holder; + let pat: &Value = if command.args[2].starts_with("$") { + &cache.variables[&command.args[2][1..]] + } else { + v_holder = serde_json::from_str(&command.args[2]).unwrap(); + &v_holder + }; + results.len() == 1 && results[0] == pat } Err(_) => false, } From a22d948eb0cd509b7ea52c3c615253d03ca9914b Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 21 Feb 2021 19:45:32 +0000 Subject: [PATCH 11/15] Apply suggestions from code review Co-authored-by: Joshua Nelson --- src/tools/jsondocck/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 8cb9564531a98..9c9d49b821f4a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -187,7 +187,7 @@ fn get_commands(template: &str) -> Result, ()> { /// Performs the actual work of ensuring a command passes. Generally assumes the command /// is syntactically valid. fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { - // FIXME: Be more granular about why, (eg syntax error, count not equal) + // FIXME: Be more granular about why, (e.g. syntax error, count not equal) let result = match command.kind { CommandKind::Has => { match command.args.len() { @@ -215,7 +215,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { v_holder = serde_json::from_str(&command.args[2]).unwrap(); &v_holder }; - !results.is_empty() && results.into_iter().any(|val| val == pat) + results.contains(pat) } Err(_) => false, } @@ -263,7 +263,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Ok(results) => { assert_eq!(results.len(), 1); let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); - assert!(r.is_none(), "Name collision"); + assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]); true } Err(_) => false, From ba22a69d964283d388a362830e73a992f024a6bf Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 21 Feb 2021 20:10:57 +0000 Subject: [PATCH 12/15] Extract string_to_value to its own function --- src/tools/jsondocck/src/main.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 9c9d49b821f4a..e3334e559db65 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -2,6 +2,7 @@ use jsonpath_lib::select; use lazy_static::lazy_static; use regex::{Regex, RegexBuilder}; use serde_json::Value; +use std::borrow::Cow; use std::{env, fmt, fs}; mod cache; @@ -207,15 +208,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - // FIXME: Share the pat getting code with the `Is` branch. - let v_holder; - let pat: &Value = if command.args[2].starts_with("$") { - &cache.variables[&command.args[2][1..]] - } else { - v_holder = serde_json::from_str(&command.args[2]).unwrap(); - &v_holder - }; - results.contains(pat) + let pat = string_to_value(&command.args[2], cache); + results.contains(&pat.as_ref()) } Err(_) => false, } @@ -240,14 +234,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; match select(&val, &command.args[1]) { Ok(results) => { - let v_holder; - let pat: &Value = if command.args[2].starts_with("$") { - &cache.variables[&command.args[2][1..]] - } else { - v_holder = serde_json::from_str(&command.args[2]).unwrap(); - &v_holder - }; - results.len() == 1 && results[0] == pat + let pat = string_to_value(&command.args[2], cache); + results.len() == 1 && results[0] == pat.as_ref() } Err(_) => false, } @@ -296,3 +284,11 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { Ok(()) } } + +fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { + if s.starts_with("$") { + Cow::Borrowed(&cache.variables[&s[1..]]) + } else { + Cow::Owned(serde_json::from_str(s).unwrap()) + } +} From dd9ab160a14e8e7b9eee1802482db6a38fa78b80 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Feb 2021 09:41:20 +0100 Subject: [PATCH 13/15] disable atomic_max/min tests in Miri --- library/core/tests/atomic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index b735957666fc5..539982eb0e49f 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -61,6 +61,7 @@ fn uint_xor() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min fn uint_min() { let x = AtomicUsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -71,6 +72,7 @@ fn uint_min() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max fn uint_max() { let x = AtomicUsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); @@ -109,6 +111,7 @@ fn int_xor() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min fn int_min() { let x = AtomicIsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -119,6 +122,7 @@ fn int_min() { #[test] #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max fn int_max() { let x = AtomicIsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); From 4c949a455df81924b37dc41f2edf1071ea329fb5 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 22 Feb 2021 10:33:33 +0000 Subject: [PATCH 14/15] Simplify Error Handling. --- src/tools/jsondocck/src/main.rs | 50 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index e3334e559db65..5020a4917a00a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -197,22 +197,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { // @has = check path exists 2 => { let val = cache.get_value(&command.args[0])?; - - match select(&val, &command.args[1]) { - Ok(results) => !results.is_empty(), - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + !results.is_empty() } // @has = check *any* item matched by path equals value 3 => { let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => { - let pat = string_to_value(&command.args[2], cache); - results.contains(&pat.as_ref()) - } - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + let pat = string_to_value(&command.args[2], cache); + results.contains(&pat.as_ref()) } _ => unreachable!(), } @@ -223,38 +216,37 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let expected: usize = command.args[2].parse().unwrap(); let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => results.len() == expected, - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + results.len() == expected } CommandKind::Is => { // @has = check *exactly one* item matched by path, and it equals value assert_eq!(command.args.len(), 3); let val = cache.get_value(&command.args[0])?; - match select(&val, &command.args[1]) { - Ok(results) => { - let pat = string_to_value(&command.args[2], cache); - results.len() == 1 && results[0] == pat.as_ref() - } - Err(_) => false, - } + let results = select(&val, &command.args[1]).unwrap(); + let pat = string_to_value(&command.args[2], cache); + results.len() == 1 && results[0] == pat.as_ref() } - // FIXME, Figure out semantics for @!set CommandKind::Set => { // @set = assert_eq!(command.args.len(), 4); assert_eq!(command.args[1], "=", "Expected an `=`"); let val = cache.get_value(&command.args[2])?; - - match select(&val, &command.args[3]) { - Ok(results) => { - assert_eq!(results.len(), 1); + let results = select(&val, &command.args[3]).unwrap(); + assert_eq!(results.len(), 1); + match results.len() { + 0 => false, + 1 => { let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]); true } - Err(_) => false, + _ => { + panic!( + "Got multiple results in `@set` for `{}`: {:?}", + &command.args[3], results + ); + } } } }; From 2145a8770c941f79e28cfdabd524ca2aea8ab2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sun, 21 Feb 2021 11:15:37 +0300 Subject: [PATCH 15/15] Fix mir-cfg dumps Fixes #81918 Fixes #82326 (duplicate) Fixes #82325 --- compiler/rustc_mir/src/util/graphviz.rs | 23 ++++++++++++++++++----- src/test/ui/issues/issue-81918.rs | 11 +++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-81918.rs diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 37498e50c0eb1..92c7a358c0a41 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -2,7 +2,7 @@ use gsgdt::GraphvizSettings; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use std::fmt::Debug; use std::io::{self, Write}; @@ -16,14 +16,27 @@ where { let def_ids = dump_mir_def_ids(tcx, single); - let use_subgraphs = def_ids.len() > 1; + let mirs = + def_ids + .iter() + .flat_map(|def_id| { + if tcx.is_const_fn_raw(*def_id) { + vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] + } else { + vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + *def_id, + )))] + } + }) + .collect::>(); + + let use_subgraphs = mirs.len() > 1; if use_subgraphs { writeln!(w, "digraph __crate__ {{")?; } - for def_id in def_ids { - let body = &tcx.optimized_mir(def_id); - write_mir_fn_graphviz(tcx, body, use_subgraphs, w)?; + for mir in mirs { + write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?; } if use_subgraphs { diff --git a/src/test/ui/issues/issue-81918.rs b/src/test/ui/issues/issue-81918.rs new file mode 100644 index 0000000000000..8938b8a6f2c52 --- /dev/null +++ b/src/test/ui/issues/issue-81918.rs @@ -0,0 +1,11 @@ +// check-pass +// dont-check-compiler-stdout +// compile-flags: -Z unpretty=mir-cfg + +// This checks that unpretty=mir-cfg does not panic. See #81918. + +const TAG: &'static str = "ABCD"; + +fn main() { + if TAG == "" {} +}