profile
viewpoint

tmandry/AXSwift 109

Swift wrapper for accessibility clients

tmandry/lavender 41

Generate Visual Studio projects for Bazel (experimental)

tmandry/great-start 2

Great starting point for Rails projects. Includes Mongoid, Devise, RSpec, Spork, Guard, Slim, and Bootstrap.

tmandry/django-fresh 1

Auto-refreshes your browser after updating files in your project in a development environment.

tmandry/adage 0

2D game and AI engine built using Qt/C++ (high school side project)

tmandry/agent 0

The configuration application of the Ultimate Hacking Keyboard

tmandry/alloy 0

Toy OS project in Rust

tmandry/askbot-devel 0

ASKBOT is a StackOverflow-like Q&A forum, based on CNPROG.

tmandry/async-book 0

Asynchronous Programming in Rust

PR opened rust-lang/rust

Capture output from threads spawned in tests

Fixes #42474.

r? @dtolnay since you expressed interest in this, but feel free to redirect if you aren't the right person anymore.

+150 -6

0 comment

10 changed files

pr created time in 7 hours

push eventtmandry/rust

Tyler Mandry

commit sha d266a8ccc6a8a4e8b504fb7d11ec4f6ea514a8ae

Capture output from threads spawned in tests Fixes #42474.

view details

push time in 7 hours

create barnchtmandry/rust

branch : test-thread-capture

created branch time in 7 hours

pull request commentrust-lang/rust

Completes support for coverage in external crates

@bors retry

richkadel

comment created time in 7 hours

pull request commentrust-lang/rust

Completes support for coverage in external crates

@bors retry

richkadel

comment created time in 9 hours

pull request commentrust-lang/rust

Completes support for coverage in external crates

Looks spurious:

    Updating crates.io index
error: failed to get `cc` as a dependency of package `bootstrap v0.0.0 (/checkout/src/bootstrap)`

Caused by:
  failed to fetch `https://github.com/rust-lang/crates.io-index`

Caused by:
  error inflating zlib stream; class=Zlib (5)
failed to run: /checkout/obj/build/i686-unknown-linux-gnu/stage0/bin/cargo build --manifest-path /checkout/src/bootstrap/Cargo.toml --locked
Build completed unsuccessfully in 0:00:29
make: *** [prepare] Error 1
Makefile:60: recipe for target 'prepare' failed

@bors r=wesleywiser

richkadel

comment created time in 9 hours

Pull request review commentrust-lang/rfcs

RFC: Add JSON backend to Rustdoc

+- Feature Name: `rustdoc_json`+- Start Date: 2020-06-26+- RFC PR: [rust-lang/rfcs#2963](https://github.com/rust-lang/rfcs/pull/2963)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)++# Summary+[summary]: #summary++This RFC describes the design of a JSON output for the tool `rustdoc`, to allow tools to+lean on its data collection and refinement but provide a different front-end.++# Motivation+[motivation]: #motivation++The current HTML output of `rustdoc` is often lauded as a key selling point of Rust. It's a+ubiquitous tool, that you can use to easily find nearly anything you need to know about a crate.+However, despite its versatility, its output format has some drawbacks:++- Viewing this output requires a web browser, with (for some features of the output) a JavaScript+  interpreter.+- The HTML output of `rustdoc` is explicitly not stabilized, to allow `rustdoc` developers the+  option to tweak the display of information, add new information, etc. In addition it's not+  generated  with the intent of being scraped by users which makes converting this HTML into a+  different format impractical. People are still able to build [cool stuff](https://crates.io/crates/rocdoc)+  on top of it, but it's unwieldy and limiting to parse the HTML like that. For use cases like+  this, a stable, well documented, easily parsable format with semantic information+  accessible would be far more useful.+- As the HTML is the only available output of `rustdoc`, its integration into centralized,+  multi-language, documentation browsers is difficult.++In addition, `rustdoc` had JSON output in the past, but it failed to keep up with the changing+language and [was taken out][remove-json] in 2016. With `rustdoc` in a more stable position, it's+possible to re-introduce this feature and ensure its stability. This [was brought up in 2018][2018-discussion]+with a positive response and there are [several][2019-interest] [recent][rustdoc-infopages]+discussions indicating that it would be a useful feature.++In [the draft RFC from 2018][previous-rfc] there was some discussion of utilizing `save-analysis`+to provide this information, but with [RLS being replaced by rust-analyzer][RA-RLS] it's possible+that the feature will be eventually removed from the compiler. In addition `save-analysis` output+is just as unstable as the current HTML output of `rustdoc`, so a separate format is preferable.++[remove-json]: https://github.com/rust-lang/rust/pull/32773+[2018-discussion]: https://internals.rust-lang.org/t/design-discussion-json-output-for-rustdoc/8271/6+[2019-interest]: https://github.com/rust-lang/rust/issues/44136#issuecomment-467144974+[rustdoc-infopages]: https://internals.rust-lang.org/t/current-state-of-rustdoc-and-cargo/11721+[previous-rfc]: https://github.com/QuietMisdreavus/rfcs/blob/rustdoc-json/text/0000-rustdoc-json.md#unresolved-questions+[RA-RLS]: https://github.com/rust-lang/rfcs/pull/2912++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++(*Upon successful implementation/stabilization, this documentation should live in The Rustdoc+Book.*)++In addition to generating the regular HTML, `rustdoc` can create a JSON file based on your crate.+These can be used by other tools to take information about your crate and convert it into other+output formats, insert into centralized documentation systems, create language bindings, etc.++To get this output, pass the `--output-format json` flag to `rustdoc`:++```shell+$ rustdoc lib.rs --output-format json+```++This will output a JSON file in the current directory (by default). For example, say you have the+following crate:++```rust+//! Here are some crate-level docs!++/// Here are some docs for `some_fn`!+pub fn some_fn() {}++/// Here are some docs for `SomeStruct`!+pub struct SomeStruct;+```++After running the above command, you should get a `lib.json` file like the following:++```json+{+  "root": "0:0",+  "version": null,+  "includes_private": false,+  "index": {+    "0:3": {+      "crate_num": 0,+      "name": "some_fn",+      "source": {+        "filename": "lib.rs",+        "begin": [4, 0],+        "end": [4, 19]+      },+      "visibility": "public",+      "docs": "Here are some docs for `some_fn`!",+      "attrs": [],+      "kind": "function",+      "inner": {+        "decl": {+          "inputs": [],+          "output": null,+          "c_variadic": false+        },+        "generics": {...},+        "header": "",+        "abi": "\"Rust\""+      }+    },+    "0:4": {+      "crate_num": 0,+      "name": "SomeStruct",+      "source": {+        "filename": "lib.rs",+        "begin": [7, 0],+        "end": [7, 22]+      },+      "visibility": "public",+      "docs": "Here are some docs for `SomeStruct`!",+      "attrs": [],+      "kind": "struct",+      "inner": {+        "struct_type": "unit",+        "generics": {...},+        "fields_stripped": false,+        "fields": [],+        "impls": [...]+      }+    },+    "0:0": {+      "crate_num": 0,+      "name": "lib",+      "source": {+        "filename": "lib.rs",+        "begin": [1, 0],+        "end": [7, 22]+      },+      "visibility": "public",+      "docs": "Here are some crate-level docs!",+      "attrs": [],+      "kind": "module",+      "inner": {+        "is_crate": true,+        "items": [+          "0:4",+          "0:3"+        ]+      }+    }+  },+  "paths": {+    "0:3": {+      "crate_num": 0,+      "path": ["lib", "some_fn"],+      "kind": "function"+    },+    "0:4": {+      "crate_num": 0,+      "path": ["lib", "SomeStruct"],+      "kind": "struct"+    },+    ...+  },+  "extern_crates": {+    "9": {+      "name": "backtrace",+      "html_root_url": "https://docs.rs/backtrace/"+      },+    "2": {+      "name": "core",+      "html_root_url": "https://doc.rust-lang.org/nightly/"+    },+    "1": {+      "name": "std",+      "html_root_url": "https://doc.rust-lang.org/nightly/"+    },+    ...+  }+}+```++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++(*Upon successful implementation/stabilization, this documentation should live in The Rustdoc+Book and/or an external crate's Rustdoc.*)++(*Given that the JSON output will be implemented as a set of Rust types with serde serialization,+the most useful docs for them would be the 40 or so types themselves. By writing docs on those+types the Rustdoc page for that module would become a good reference. It may be helpful to provide+some sort of [schema](http://json-schema.org/) for use with other languages*)++When you request JSON output from `rustdoc`, you're getting a version of the Rust abstract syntax+tree (AST), so you could see anything that you could export from a valid Rust crate. The following+types can appear in the output:++## ID++To provide various maps/references to items, the JSON output uses unique strings as IDs for each+item. They happen to be the compiler internal DefId for that item, but in the JSON blob they should+be treated as opaque as they aren't guaranteed to be stable across compiler invocations. IDs are+only valid/consistent within a single JSON blob. They cannot be used to resolve references between+the JSON output of different crates (see [the Resolving IDs section](#resolving-ids)).++## Crate++A Crate is the root of the outputted JSON blob. It contains all doc-relevant information about the+local crate, as well as some information about external items that are referred to locally.++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`name`    | String  | The name of the crate. If `--crate-name` is not given, based on the filename.+`version` | String  | (*Optional*) The version string given to `--crate-version`, if any.+`includes_private`  | bool  | Whether or not the output includes private items.+`root`    | [ID](#ID)      | The ID of the root module Item.+`index`   | Map<[ID](#ID), [Item](#Item)> | A collection of all Items in the crate[\*](#resolving-ids).+`paths`   | Map<[ID](#ID), [ItemSummary](#ItemSummary)> | Maps all IDs (even external ones[\*](#resolving-ids)) to a brief description including their name, crate of origin, and kind.+`extern_crates` | Map<int, [ExternalCrate](#ExternalCrate)> | A map of "crate numbers" to metadata about that crate.++### Resolving IDs++The crate's `index` contains mostly local items, which includes impls of external traits on local+types or local traits on external types. The exception to this is that external trait definitions+and their associated items are also included in the `index` because this information is useful when+generating the comprehensive list of methods for a type.++This means that many IDs aren't included in the `index` (any reference to a struct, macro, etc.+from a different crate). In these cases the fallback is to look up the ID in the crate's `paths`.+That gives [enough information](#ItemSummary) about the item to create cross references or simply+provide a name without copying all of the information about external items into the local+crate's JSON output.++### ExternalCrate++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`name`    | String  | The name of the crate.+`html_root_url` | String  | (*Optional*) The `html_root_url` for that crate if they specify one.++### ItemSummary++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`crate_num` | int   | A number corresponding to the crate this Item is from. Used as an key to the `extern_crates` map in [Crate](#Crate). A value of zero represents an Item from the local crate, any other number means that this Item is external.+`path`    | [String] | The fully qualified path (e.g. `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`) of this Item.+`kind`    | String  | What type of Item this is (see [Item](#Item)).++## Item++An Item represents anything that can hold documentation - modules, structs, enums, functions,+traits, type aliases, and more. The Item data type holds fields that can apply to any of these,+and leaves kind-specific details (like function args or enum variants) to the `inner` field.++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`crate_num` | int   | A number corresponding to the crate this Item is from. Used as an key to the `extern_crates` map in [Crate](#Crate). A value of zero represents an Item from the local crate, any other number means that this Item is external.+`name`    | String  | The name of the Item, if present. Some Items, like impl blocks, do not have names.+`span`    | [Span](#Span) | (*Optional*) The source location of this Item.+`visibility` | String | `"default"`, `"public"`, `"crate"`, or `"restricted"` (`pub(path)`).+`restricted_path` | String | (*Optional*) If `visitility == "restricted"`, this field contains the path that it's restricted to.+`docs`    | String  | The extracted documentation text from the Item.+`attrs`   | [String] | The attributes (other than doc comments) on the Item, rendered as strings.+`deprecation` | [Deprecation](#Deprecation) | (*Optional*) Information about the Item's deprecation, if present.+`kind`    | String  | The kind of Item this is. Determines what fields are in `inner`.+`inner`   | Object  | The type-specific fields describing this Item. Check the `kind` field to determine what's available.++### `kind == "module"`++Name     | Type   | Description+---------|--------|--------------------------------------------------------------------------------+`items`  | [[ID](#ID)] | The list of Items contained within this module. The order of definitions is preserved.++### `kind == "function"`++Name       | Type     | Description+-----------|----------|----------------------------------------------------------------------------+`decl`     | [FnDecl](#FnDecl) | Information about the function signature, or declaration.+`generics` | [Generics](#Generics) | Information about the function's type parameters and `where` clauses.+`header`   | String   | `"const"`, `"async"`, `"unsafe"`, or a space separated combination of those modifiers.+`abi`      | String   | The ABI string on the function. Non-`extern` functions have a `"Rust"` ABI, whereas `extern` functions without an explicit ABI are `"C"`. See [the reference](https://doc.rust-lang.org/reference/items/external-blocks.html#abi) for more details.++### `kind == "struct" || "union"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`struct_type` | String   | Either `"plain"` for braced structs, `"tuple"` for tuple structs, or `"unit"` for unit structs.+`generics`    | [Generics](#Generics) | Information about the struct's type parameters and `where` clauses.+`fields_stripped` | bool | Whether any fields have been removed from the result, due to being private or hidden.+`fields`      | [[ID](#ID)] | The list of fields in the struct. All of the corresponding Items have `kind == "structfield"`.+`impls`       | [[ID](#ID)] | All impls (both trait and inherent) for this type. All of the corresponding Items have `kind = "impl"`++### `kind == "structfield"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`type`        | [Type](#Type) | The type of this field.++### `kind == "enum"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`generics`    | [Generics](#Generics) | Information about the enum's type parameters and `where` clauses.+`fields`      | [[ID](#ID)]     | The list of variants in the enum. All of the corresponding Items have `kind == "variant"`.+`fields_stripped` | bool | Whether any variants have been removed from the result, due to being private or hidden.+`impls`       | [[ID](#ID)] | All impls (both trait and inherent) for this type. All of the corresponding Items have `kind = "impl"`++### `kind == "variant"`++`inner` can be one of the 3 following objects:+- `"plain"` (e.g. `Enum::Variant`)+- `{"tuple": [Type]}` (e.g. `Enum::Variant(u32, String)`)+- `{"struct": Object}` (e.g. `Enum::Variant{foo: u32, bar: String}`) in which case the `Object`+  has a single key `"struct"` with a value that's the same object as `inner` when `kind == "struct"`.++### `kind == "trait"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`is_auto`     | bool     | Whether this trait is an autotrait like `Sync`.+`is_unsafe`   | bool     | Whether this is an `unsafe trait` such as `GlobalAlloc`.+`items`       | [[ID](#ID)] | The list of method, constant, and typedef items contained in this trait definition.+`generics`    | [Generics](#Generics) | Information about the trait's type parameters and `where` clauses.+`bounds`      | [[GenericBound](#GenericBound)] | Trait bounds for this trait definition (e.g.  `trait Foo: Bar<T> + Clone`).++### `kind == "trait_alias"`++An [unstable feature](https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html)+which allows writing aliases like `trait Foo = std::fmt::Debug + Send` and then using `Foo` in+bounds rather than writing out the individual traits.++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`generics`    | [Generics](#Generics) | Any type parameters that the trait alias takes.+`bounds`      | [[GenericBound](#GenericBound)] | The list of traits after the equals.++### `kind == "method"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`decl`        | [FnDecl](#FnDecl) | Information about the method signature, or declaration.+`generics`    | [Generics](#Generics) | Information about the method's type parameters and `where` clauses.+`header`      | String   | `"const"`, `"async"`, `"unsafe"`, or a space separated combination of those modifiers.+`has_body`    | bool     | Whether this is just a method signature (in a trait definition) or a method with an actual body.++### `kind == "assoc_const"`++These items only show up in trait _definitions_. When looking at a trait impl item, the item where the associated constant is defined is a `"constant"` item.++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`type`        | [Type](#Type) | The type of this associated const.+`default`     | String | (*Optional*) The stringified expression for the default value, if provided.++### `kind == "assoc_type"`++These items only show up in trait _definitions_. When looking at a trait impl item, the item where the associated type is defined is a `"typedef"` item.++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`bounds`      | [[GenericBound](#GenericBound)] | The bounds for this associated type.+`default`     | [Type](#Type) | (*Optional*) The default for this type, if provided.++### `kind == "impl"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`is_unsafe`   | bool     | Whether this impl is for an unsafe trait.+`generics`    | [Generics](#Generics) | Information about the impl's type parameters and `where` clauses.+`provided_trait_methods` | [String] | The list of names for all provided methods in this impl block. This is provided for ease of access if you don't need more information from the `items` field.+`trait`       | [Type](#Type) | The trait being implemented or `null` if the impl is "inherent".+`for`         | [Type](#Type) | The type that the impl block is for.+`items`       | [[ID](#ID)] | The list of method, constant, and typedef items contained in this impl block.+`negative`    | bool     | Whether this is a negative impl (e.g. `!Sized` or `!Send`).+`synthetic`   | bool     | Whether this is an impl that's implied by the compiler (for autotraits).+`blanket_impl` | String | (*Optional*) The name of the generic parameter used for the blanket impl, if this impl was produced by one. For example `impl<T, U> Into<U> for T` would result in `blanket_impl == "T"`.++### `kind == "constant"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`type`        | [Type](#Type) | The type of this constant.+`expr`        | String   | The stringified expression of this constant.+`value`       | String   | (*Optional*) The value of the evaluated expression for this constant, which is only computed for numeric types.+`is_literal`  | bool     | Whether this constant is a bool, numeric, string, or char literal.++### `kind == "static"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`type`        | [Type](#Type) | The type of this static.+`expr`        | String   | The stringified expression that this static is assigned to.+`mutable`     | bool     | Whether this static is mutable.++### `kind == "typedef"`++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`type`        | [Type](#Type) | The type on the right hand side of this definition.+`generics`    | [Generics](#Generics) | Any generic parameters on the left hand side of this definition.++### `kind == "opaque_ty"`++Represents [trait aliases](https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html)+of the form:++```rust+type Foo<T> = Clone + std::fmt::Debug + Into<T>;+```++Name          | Type     | Description+--------------|----------|-------------------------------------------------------------------------+`bounds`      | [[GenericBound](#GenericBound)] | The trait bounds on the right hand side.+`generics`    | [Generics](#Generics) | Any generic parameters on the type itself.++### `kind == "foreign_type"`++`inner` contains no fields. This item represents a type declaration in an extern block (see [here](https://github.com/rust-lang/rfcs/blob/master/text/1861-extern-types.md)+for more details):++```rust+extern {+    type Foo;+}+```++### `kind == "extern_crate"`++Name     | Type     | Description+---------|----------|-------------------------------------------------------------------------+`name`   | String   | The name of the extern crate.+`rename` | String   | (*Optional*) The renaming of this crate with `extern crate foo as bar`.++### `kind == "import"`++Name     | Type     | Description+---------|----------|-------------------------------------------------------------------------+`source` | String   | The full path being imported (e.g. `"super::some_mod::other_mod::Struct"`).+`name`   | String   | The name of the imported item (may be different from the last segment of `source` due to import renaming: `use source as name`).+`id`     | [ID](#ID) | (*Optional*) The ID of the item being imported.+`glob`   | bool     | Whether this import ends in a glob: `use source::*`.++### `kind == "macro"`++A `macro_rules!` declarative macro. Contains a single string with the source representation of+the macro with the patterns stripped, for example:++```rust+macro_rules! vec {+    () => { ... };+    ($elem:expr; $n:expr) => { ... };+    ($($x:expr),+ $(,)?) => { ... };+}+```++TODO: proc macros++## Span++Name       | Type     | Description+-----------|----------|----------------------------------------------------------------------------+`filename` | String   | The path to the source file for this span relative to the crate root.+`begin`    | (int, int) | The zero indexed line and column of the first character in this span.+`begin`    | (int, int) | The zero indexed line and column of the last character in this span.++## Deprecation++Name       | Type     | Description+-----------|----------|----------------------------------------------------------------------------+`since`    | String   | (*Optional*) Usually a version number when this Item first became deprecated.+`note`     | String   | (*Optional*) The reason for deprecation and/or what alternatives to use.++## FnDecl++Name       | Type     | Description+-----------|----------|----------------------------------------------------------------------------+`inputs`   | [(String, [Type](#Type))] | A list of parameter names and their types.

+1 to marking the format of the value as unstable and subject to change, but I think we could stabilize its existence and that it's a reasonable thing to put in the docs. (Here and elsewhere)

P1n3appl3

comment created time in 11 hours

Pull request review commentrust-lang/rfcs

RFC: Add JSON backend to Rustdoc

+- Feature Name: `rustdoc_json`+- Start Date: 2020-06-26+- RFC PR: [rust-lang/rfcs#2963](https://github.com/rust-lang/rfcs/pull/2963)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)++# Summary+[summary]: #summary++This RFC describes the design of a JSON output for the tool `rustdoc`, to allow tools to+lean on its data collection and refinement but provide a different front-end.++# Motivation+[motivation]: #motivation++The current HTML output of `rustdoc` is often lauded as a key selling point of Rust. It's a+ubiquitous tool, that you can use to easily find nearly anything you need to know about a crate.+However, despite its versatility, its output format has some drawbacks:++- Viewing this output requires a web browser, with (for some features of the output) a JavaScript+  interpreter.+- The HTML output of `rustdoc` is explicitly not stabilized, to allow `rustdoc` developers the+  option to tweak the display of information, add new information, etc. In addition it's not+  generated  with the intent of being scraped by users which makes converting this HTML into a+  different format impractical. People are still able to build [cool stuff](https://crates.io/crates/rocdoc)+  on top of it, but it's unwieldy and limiting to parse the HTML like that. For use cases like+  this, a stable, well documented, easily parsable format with semantic information+  accessible would be far more useful.+- As the HTML is the only available output of `rustdoc`, its integration into centralized,+  multi-language, documentation browsers is difficult.++In addition, `rustdoc` had JSON output in the past, but it failed to keep up with the changing+language and [was taken out][remove-json] in 2016. With `rustdoc` in a more stable position, it's+possible to re-introduce this feature and ensure its stability. This [was brought up in 2018][2018-discussion]+with a positive response and there are [several][2019-interest] [recent][rustdoc-infopages]+discussions indicating that it would be a useful feature.++In [the draft RFC from 2018][previous-rfc] there was some discussion of utilizing `save-analysis`+to provide this information, but with [RLS being replaced by rust-analyzer][RA-RLS] it's possible+that the feature will be eventually removed from the compiler. In addition `save-analysis` output+is just as unstable as the current HTML output of `rustdoc`, so a separate format is preferable.++[remove-json]: https://github.com/rust-lang/rust/pull/32773+[2018-discussion]: https://internals.rust-lang.org/t/design-discussion-json-output-for-rustdoc/8271/6+[2019-interest]: https://github.com/rust-lang/rust/issues/44136#issuecomment-467144974+[rustdoc-infopages]: https://internals.rust-lang.org/t/current-state-of-rustdoc-and-cargo/11721+[previous-rfc]: https://github.com/QuietMisdreavus/rfcs/blob/rustdoc-json/text/0000-rustdoc-json.md#unresolved-questions+[RA-RLS]: https://github.com/rust-lang/rfcs/pull/2912++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++(*Upon successful implementation/stabilization, this documentation should live in The Rustdoc+Book.*)++In addition to generating the regular HTML, `rustdoc` can create a JSON file based on your crate.+These can be used by other tools to take information about your crate and convert it into other+output formats, insert into centralized documentation systems, create language bindings, etc.++To get this output, pass the `--output-format json` flag to `rustdoc`:++```shell+$ rustdoc lib.rs --output-format json+```++This will output a JSON file in the current directory (by default). For example, say you have the+following crate:++```rust+//! Here are some crate-level docs!++/// Here are some docs for `some_fn`!+pub fn some_fn() {}++/// Here are some docs for `SomeStruct`!+pub struct SomeStruct;+```++After running the above command, you should get a `lib.json` file like the following:++```json+{+  "root": "0:0",+  "version": null,+  "includes_private": false,+  "index": {+    "0:3": {+      "crate_num": 0,+      "name": "some_fn",+      "source": {+        "filename": "lib.rs",+        "begin": [4, 0],+        "end": [4, 19]+      },+      "visibility": "public",+      "docs": "Here are some docs for `some_fn`!",+      "attrs": [],+      "kind": "function",+      "inner": {+        "decl": {+          "inputs": [],+          "output": null,+          "c_variadic": false+        },+        "generics": {...},+        "header": "",+        "abi": "\"Rust\""+      }+    },+    "0:4": {+      "crate_num": 0,+      "name": "SomeStruct",+      "source": {+        "filename": "lib.rs",+        "begin": [7, 0],+        "end": [7, 22]+      },+      "visibility": "public",+      "docs": "Here are some docs for `SomeStruct`!",+      "attrs": [],+      "kind": "struct",+      "inner": {+        "struct_type": "unit",+        "generics": {...},+        "fields_stripped": false,+        "fields": [],+        "impls": [...]+      }+    },+    "0:0": {+      "crate_num": 0,+      "name": "lib",+      "source": {+        "filename": "lib.rs",+        "begin": [1, 0],+        "end": [7, 22]+      },+      "visibility": "public",+      "docs": "Here are some crate-level docs!",+      "attrs": [],+      "kind": "module",+      "inner": {+        "is_crate": true,+        "items": [+          "0:4",+          "0:3"+        ]+      }+    }+  },+  "paths": {+    "0:3": {+      "crate_num": 0,+      "path": ["lib", "some_fn"],+      "kind": "function"+    },+    "0:4": {+      "crate_num": 0,+      "path": ["lib", "SomeStruct"],+      "kind": "struct"+    },+    ...+  },+  "extern_crates": {+    "9": {+      "name": "backtrace",+      "html_root_url": "https://docs.rs/backtrace/"+      },+    "2": {+      "name": "core",+      "html_root_url": "https://doc.rust-lang.org/nightly/"+    },+    "1": {+      "name": "std",+      "html_root_url": "https://doc.rust-lang.org/nightly/"+    },+    ...+  }+}+```++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++(*Upon successful implementation/stabilization, this documentation should live in The Rustdoc+Book and/or an external crate's Rustdoc.*)++(*Given that the JSON output will be implemented as a set of Rust types with serde serialization,+the most useful docs for them would be the 40 or so types themselves. By writing docs on those+types the Rustdoc page for that module would become a good reference. It may be helpful to provide+some sort of [schema](http://json-schema.org/) for use with other languages*)++When you request JSON output from `rustdoc`, you're getting a version of the Rust abstract syntax+tree (AST), so you could see anything that you could export from a valid Rust crate. The following+types can appear in the output:++## ID++To provide various maps/references to items, the JSON output uses unique strings as IDs for each+item. They happen to be the compiler internal DefId for that item, but in the JSON blob they should+be treated as opaque as they aren't guaranteed to be stable across compiler invocations. IDs are+only valid/consistent within a single JSON blob. They cannot be used to resolve references between+the JSON output of different crates (see [the Resolving IDs section](#resolving-ids)).++## Crate++A Crate is the root of the outputted JSON blob. It contains all doc-relevant information about the+local crate, as well as some information about external items that are referred to locally.++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`name`    | String  | The name of the crate. If `--crate-name` is not given, based on the filename.+`version` | String  | (*Optional*) The version string given to `--crate-version`, if any.+`includes_private`  | bool  | Whether or not the output includes private items.+`root`    | [ID](#ID)      | The ID of the root module Item.+`index`   | Map<[ID](#ID), [Item](#Item)> | A collection of all Items in the crate[\*](#resolving-ids).+`paths`   | Map<[ID](#ID), [ItemSummary](#ItemSummary)> | Maps all IDs (even external ones[\*](#resolving-ids)) to a brief description including their name, crate of origin, and kind.+`extern_crates` | Map<int, [ExternalCrate](#ExternalCrate)> | A map of "crate numbers" to metadata about that crate.++### Resolving IDs++The crate's `index` contains mostly local items, which includes impls of external traits on local+types or local traits on external types. The exception to this is that external trait definitions+and their associated items are also included in the `index` because this information is useful when+generating the comprehensive list of methods for a type.++This means that many IDs aren't included in the `index` (any reference to a struct, macro, etc.+from a different crate). In these cases the fallback is to look up the ID in the crate's `paths`.+That gives [enough information](#ItemSummary) about the item to create cross references or simply+provide a name without copying all of the information about external items into the local+crate's JSON output.++### ExternalCrate++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`name`    | String  | The name of the crate.+`html_root_url` | String  | (*Optional*) The `html_root_url` for that crate if they specify one.++### ItemSummary++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`crate_num` | int   | A number corresponding to the crate this Item is from. Used as an key to the `extern_crates` map in [Crate](#Crate). A value of zero represents an Item from the local crate, any other number means that this Item is external.+`path`    | [String] | The fully qualified path (e.g. `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`) of this Item.+`kind`    | String  | What type of Item this is (see [Item](#Item)).++## Item++An Item represents anything that can hold documentation - modules, structs, enums, functions,+traits, type aliases, and more. The Item data type holds fields that can apply to any of these,+and leaves kind-specific details (like function args or enum variants) to the `inner` field.++Name      | Type    | Description+----------|---------|------------------------------------------------------------------------------+`crate_num` | int   | A number corresponding to the crate this Item is from. Used as an key to the `extern_crates` map in [Crate](#Crate). A value of zero represents an Item from the local crate, any other number means that this Item is external.+`name`    | String  | The name of the Item, if present. Some Items, like impl blocks, do not have names.+`span`    | [Span](#Span) | (*Optional*) The source location of this Item.+`visibility` | String | `"default"`, `"public"`, `"crate"`, or `"restricted"` (`pub(path)`).+`restricted_path` | String | (*Optional*) If `visitility == "restricted"`, this field contains the path that it's restricted to.+`docs`    | String  | The extracted documentation text from the Item.+`attrs`   | [String] | The attributes (other than doc comments) on the Item, rendered as strings.

The intention of this is to give renderers an "easy path" way to consume this format by giving them a reasonable string of text to present. If we document that the exact format is unstable and subject to change, would that alleviate your concerns @jyn514?

P1n3appl3

comment created time in 11 hours

issue commentrust-lang/rust

Async/.await and const-generics causes "Broken MIR:"

Related to #72651. Not going to mark as a duplicate yet, since the MVCE is quite different.

rot256

comment created time in 15 hours

issue closedrust-lang/rust

src\librustc_mir\transform\generator.rs:739:13: Broken MIR: generator contains type &rocket::http::Cookie in MIR, but typeck only knows about for...

Code

Minimal verifiable example can be found here: https://github.com/Weasy666/rustc-bug Just clone and cargo run.

Meta

<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. -->

rustc --version --verbose:

rustc 1.47.0-nightly (6c8927b0c 2020-07-26)
binary: rustc
commit-hash: 6c8927b0cf80ceee19386026cf9d7fd4fd9d486f
commit-date: 2020-07-26
host: x86_64-pc-windows-msvc
release: 1.47.0-nightly
LLVM version: 10.0

Error output

error: internal compiler error: src\librustc_mir\transform\generator.rs:739:13: Broken MIR: generator contains type &rocket::http::Cookie in MIR, but typeck only knows about for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {std::future::ResumeTy, &'r rocket::Request<'s>, rocket::http::Cookies<'t0>, &'t1 mut rocket::http::Cookies<'t2>, &'t3 str, std::option::Option<rocket::http::Cookie<'t4>>, rocket::http::Cookie<'t5>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = rocket::outcome::Outcome<rocket_airlock::Airlock<hatch::SimpleHatch>, (rocket::http::Status, ()), ()>> + std::marker::Send + 't6)>>, ()}
  --> src\user.rs:16:83
   |
16 |       async fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
   |  ___________________________________________________________________________________^
17 | |         let mut cookies = request.cookies();
18 | |         match cookies.get_private("logged_in") {
19 | |             Some(logged_in) if request.guard::<Airlock<hatch::SimpleHatch>>().await.expect("Hatch 'SimpleHatch' was not installed into th...
...  |
25 | |         }
26 | |     }
   | |_____^

thread 'rustc' panicked at 'Box<Any>', /rustc/6c8927b0cf80ceee19386026cf9d7fd4fd9d486f\src\libstd\macros.rs:13:23
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md


note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

<!-- Include a backtrace in the code block by setting RUST_BACKTRACE=1 in your environment. E.g. RUST_BACKTRACE=1 cargo build. --> <details><summary><strong>Backtrace</strong></summary> <p>

stack backtrace:
   0: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
   1: core::fmt::write
   2: <std::io::IoSliceMut as core::fmt::Debug>::fmt
   3: std::panicking::take_hook
   4: std::panicking::take_hook
   5: rustc_driver::report_ice
   6: std::panicking::rust_panic_with_hook
   7: rustc_mir_build::provide
   8: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
   9: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  10: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  11: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  12: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  13: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  14: <rustc_mir::borrow_check::InitializationRequiringAction as core::fmt::Debug>::fmt
  15: <rustc_mir::transform::generator::StateTransform as rustc_mir::transform::MirPass>::run_pass
  16: rustc_mir::transform::run_passes
  17: rustc_mir::transform::run_passes
  18: rustc_mir::transform::run_passes
  19: rustc_mir::transform::run_passes
  20: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::debug_node
  21: <rustc_middle::ty::consts::kind::InferConst as core::fmt::Debug>::fmt
  22: <rustc_middle::ty::subst::UserSubsts as core::fmt::Debug>::fmt
  23: rustc_middle::ty::structural_impls::<impl rustc_middle::ty::context::Lift for rustc_middle::ty::TraitPredicate>::lift_to_tcx
  24: rustc_middle::ty::layout::provide
  25: <rustc_middle::ty::layout::LayoutError as core::fmt::Display>::fmt
  26: <rustc_middle::ty::query::Query as rustc_data_structures::stable_hasher::HashStable<rustc_middle::ich::hcx::StableHashingContext>>::hash_stable
  27: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::debug_node
  28: <rustc_middle::ty::consts::kind::InferConst as core::fmt::Debug>::fmt
  29: <rustc_middle::ty::subst::UserSubsts as core::fmt::Debug>::fmt
  30: rustc_middle::ty::structural_impls::<impl rustc_middle::ty::context::Lift for rustc_middle::ty::TraitPredicate>::lift_to_tcx
  31: <rustc_middle::ty::layout::LayoutCx<rustc_middle::ty::context::TyCtxt> as rustc_target::abi::LayoutOf>::layout_of
  32: <rustc_middle::ty::relate::GeneratorWitness as core::fmt::Debug>::fmt
  33: ZN238_$LT$rustc_infer..infer..undo_log..UndoLog$u20$as$u20$core..convert..From$LT$rustc_data_structures..snapshot_map..UndoLog$LT$rustc_infer..traits..project..ProjectionCacheKey$C$rustc_infer..traits..project..ProjectionCacheEntry$GT$$GT$$GT$4from17h3714
  34: <rustc_middle::ty::relate::GeneratorWitness as core::fmt::Debug>::fmt
  35: ZN238_$LT$rustc_infer..infer..undo_log..UndoLog$u20$as$u20$core..convert..From$LT$rustc_data_structures..snapshot_map..UndoLog$LT$rustc_infer..traits..project..ProjectionCacheKey$C$rustc_infer..traits..project..ProjectionCacheEntry$GT$$GT$$GT$4from17h3714
  36: rustc_middle::ty::layout::provide
  37: <rustc_middle::ty::layout::LayoutError as core::fmt::Display>::fmt
  38: <rustc_middle::ty::query::Query as rustc_data_structures::stable_hasher::HashStable<rustc_middle::ich::hcx::StableHashingContext>>::hash_stable
  39: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::debug_node
  40: <rustc_middle::ty::consts::kind::InferConst as core::fmt::Debug>::fmt
  41: <rustc_middle::ty::subst::UserSubsts as core::fmt::Debug>::fmt
  42: rustc_middle::ty::structural_impls::<impl rustc_middle::ty::context::Lift for rustc_middle::ty::TraitPredicate>::lift_to_tcx
  43: <rustc_middle::ty::layout::LayoutCx<rustc_middle::ty::query::TyCtxtAt> as rustc_target::abi::LayoutOf>::layout_of
  44: <rustc_mir::transform::const_prop::ConstProp as rustc_mir::transform::MirPass>::run_pass
  45: rustc_mir::transform::run_passes
  46: rustc_mir::transform::run_passes
  47: rustc_mir::transform::run_passes
  48: rustc_mir::transform::run_passes
  49: rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::debug_node
  50: <rustc_middle::ty::consts::kind::InferConst as core::fmt::Debug>::fmt
  51: <rustc_middle::ty::subst::UserSubsts as core::fmt::Debug>::fmt
  52: rustc_middle::ty::structural_impls::<impl rustc_middle::ty::context::Lift for rustc_middle::ty::TraitPredicate>::lift_to_tcx
  53: rustc_middle::ty::<impl rustc_middle::ty::context::TyCtxt>::instance_mir
  54: <rustc_mir::monomorphize::collector::RootCollector as rustc_hir::itemlikevisit::ItemLikeVisitor>::visit_impl_item
  55: rustc_mir::monomorphize::collector::collect_crate_mono_items
  56: rustc_mir::monomorphize::collector::collect_crate_mono_items
  57: rustc_mir::monomorphize::collector::collect_crate_mono_items
  58: rustc_mir::monomorphize::collector::collect_crate_mono_items
  59: rustc_mir::monomorphize::collector::collect_crate_mono_items
  60: rustc_mir::monomorphize::collector::collect_crate_mono_items
  61: <rustc_mir::interpret::machine::StackPopJump as core::fmt::Debug>::fmt
  62: rustc_mir::monomorphize::collector::collect_crate_mono_items
  63: rustc_mir::monomorphize::partitioning::compute_codegen_unit_name
  64: <rustc_target::abi::TyAndLayout<&rustc_middle::ty::TyS> as rustc_codegen_llvm::type_of::LayoutLlvmExt>::pointee_info_at
  65: rustc_codegen_llvm::llvm_::archive_ro::Child::data
  66: <rustc_codegen_llvm::llvm_::ffi::debuginfo::DISPFlags as core::fmt::Debug>::fmt
  67: <rustc_codegen_llvm::debuginfo::metadata::MemberDescription as core::fmt::Debug>::fmt
  68: <rustc_codegen_llvm::llvm_::ffi::debuginfo::DISPFlags as core::fmt::Debug>::fmt
  69: <rustc_target::abi::TyAndLayout<&rustc_middle::ty::TyS> as rustc_codegen_llvm::type_of::LayoutLlvmExt>::pointee_info_at
  70: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
  71: rustc_interface::passes::QueryContext::print_stats
  72: rustc_interface::passes::BoxedResolver::complete
  73: rustc_interface::queries::Queries::ongoing_codegen
  74: <rustc_lint::BuiltinCombinedModuleLateLintPass as rustc_lint::passes::LateLintPass>::check_trait_item_post
  75: <env_logger::filter::inner::Filter as core::fmt::Display>::fmt
  76: <rustc_driver::DEFAULT_HOOK as core::ops::deref::Deref>::deref
  77: <rustc_driver::DEFAULT_HOOK as core::ops::deref::Deref>::deref
  78: <rustc_mir::shim::DropShimElaborator as rustc_mir::util::elaborate_drops::DropElaborator>::array_subpath
  79: std::sys::windows::thread::Thread::new
  80: BaseThreadInitThunk
  81: RtlUserThreadStart
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.47.0-nightly (6c8927b0c 2020-07-26) running on x86_64-pc-windows-msvc

note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [optimized_mir] optimizing MIR for `<user::User as rocket::request::FromRequest<'a, 'r>>::from_request::__from_request::{{closure}}#0`
#1 [layout_raw] computing layout of `[static generator@src\user.rs:16:83: 26:6 request:&rocket::Request for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {std::future::ResumeTy, &'r rocket::Request<'s>, rocket::http::Cookies<'t0>, &'t1 mut rocket::http::Cookies<'t2>, &'t3 str, std::option::Option<rocket::http::Cookie<'t4>>, rocket::http::Cookie<'t5>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = rocket::outcome::Outcome<rocket_airlock::Airlock<hatch::SimpleHatch>, (rocket::http::Status, ()), ()>> + std::marker::Send + 't6)>>, ()}]`
#2 [layout_raw] computing layout of `std::future::from_generator::GenFuture<[static generator@src\user.rs:16:83: 26:6 request:&rocket::Request for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {std::future::ResumeTy, &'r rocket::Request<'s>, rocket::http::Cookies<'t0>, &'t1 mut rocket::http::Cookies<'t2>, &'t3 str, std::option::Option<rocket::http::Cookie<'t4>>, rocket::http::Cookie<'t5>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = rocket::outcome::Outcome<rocket_airlock::Airlock<hatch::SimpleHatch>, (rocket::http::Status, ()), ()>> + std::marker::Send + 't6)>>, ()}]>`
#3 [optimized_mir] optimizing MIR for `<user::User as rocket::request::FromRequest<'a, 'r>>::from_request::__from_request`
#4 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack

</p> </details>

closed time in 15 hours

Weasy666

issue commentrust-lang/rust

src\librustc_mir\transform\generator.rs:739:13: Broken MIR: generator contains type &rocket::http::Cookie in MIR, but typeck only knows about for...

Thanks @SNCPlay42! Going to close this as a duplicate, I've added the MVCE here to #72651.

Weasy666

comment created time in 15 hours

issue commentrust-lang/rust

ICE: Broken MIR

A smaller MVCE is in https://github.com/rust-lang/rust/issues/74961#issuecomment-666893845

Spanfile

comment created time in 15 hours

Pull request review commentrust-lang/rust

JSON backend experimental impl

+mod conversions;+mod types;++use std::cell::RefCell;+use std::fs::File;+use std::rc::Rc;++use rustc_data_structures::fx::FxHashMap;+use rustc_span::edition::Edition;+ use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer;--use rustc_span::edition::Edition;+use crate::html::render::cache::ExternalLocation;  #[derive(Clone)]-pub struct JsonRenderer {}+pub struct JsonRenderer {+    index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,+}++impl JsonRenderer {+    fn insert(&self, item: clean::Item, cache: &Cache) {+        let id = item.def_id;+        let mut new_item: types::Item = item.into();+        if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner {+            t.implementors = self.get_trait_implementors(id, cache)+        } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner {+            s.impls = self.get_impls(id, cache)+        } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner {+            e.impls = self.get_impls(id, cache)+        }+        self.index.borrow_mut().insert(id.into(), new_item);+    }++    fn get_trait_implementors(+        &self,+        id: rustc_span::def_id::DefId,+        cache: &Cache,+    ) -> Vec<types::Id> {+        cache+            .implementors+            .get(&id)+            .map(|implementors| {+                implementors+                    .iter()+                    .map(|i| {+                        let item = &i.impl_item;+                        self.insert(item.clone(), cache);+                        item.def_id.into()+                    })+                    .collect()+            })+            .unwrap_or_default()+    }++    fn get_impls(&self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec<types::Id> {+        cache+            .impls+            .get(&id)+            .map(|impls| {+                impls+                    .iter()+                    .filter_map(|i| {+                        let item = &i.impl_item;+                        if item.def_id.is_local() {+                            self.insert(item.clone(), cache);+                            Some(item.def_id.into())+                        } else {+                            None+                        }+                    })+                    .collect()+            })+            .unwrap_or_default()+    }+}  impl FormatRenderer for JsonRenderer {     fn init(-        _krate: clean::Crate,+        krate: clean::Crate,         _options: RenderOptions,         _render_info: RenderInfo,         _edition: Edition,         _cache: &mut Cache,     ) -> Result<(Self, clean::Crate), Error> {-        unimplemented!()+        debug!("Initializing json renderer");+        Ok((JsonRenderer { index: Rc::new(RefCell::new(FxHashMap::default())) }, krate))     } -    fn item(&mut self, _item: clean::Item, _cache: &Cache) -> Result<(), Error> {-        unimplemented!()+    fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> {+        use clean::ItemEnum::*;+        // Flatten items that recursively store other items by putting their children in the index+        match item.inner.clone() {+            StructItem(s) => s.fields.into_iter().for_each(|i| self.insert(i, cache)),+            UnionItem(u) => u.fields.into_iter().for_each(|i| self.insert(i, cache)),+            VariantItem(clean::Variant { kind: clean::VariantKind::Struct(v) }) => {+                v.fields.into_iter().for_each(|i| self.insert(i, cache));+            }+            EnumItem(e) => e.variants.into_iter().for_each(|i| self.item(i, cache).unwrap()),+            TraitItem(t) => t.items.into_iter().for_each(|i| self.insert(i, cache)),+            ImplItem(i) => i.items.into_iter().for_each(|i| self.insert(i, cache)),+            _ => {}+        }

I think it would be better to have this knowledge inside a method on ItemEnum itself, either returning an iterator of inner items or taking a closure.

Also, a problem with using a wildcard here is that a new kind of item with children could be added, and this match could be forgotten. So it's actually safer to list everything out.

P1n3appl3

comment created time in a day

Pull request review commentrust-lang/rust

JSON backend experimental impl

+mod conversions;

Suggestion: Add a module-level doc comment pointing to the RFC

P1n3appl3

comment created time in a day

Pull request review commentrust-lang/rust

JSON backend experimental impl

+//! Rustdoc's JSON output interface+//!+//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`][]+//! struct is the root of the JSON blob and all other items are contained within.++use std::path::PathBuf;++use rustc_data_structures::fx::FxHashMap;+use serde::{Deserialize, Serialize};++/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information+/// about the language items in the local crate, as well as info about external items to allow+/// tools to find or link to them.+#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Crate {+    /// The id of the root [`Module`][] item of the local crate.+    pub root: Id,+    /// The version string given to `--crate-version`, if any.+    pub version: Option<String>,+    /// Whether or not the output includes private items.+    pub includes_private: bool,+    /// A collection of all items in the local crate as well as some external traits and their+    /// items that are referenced locally.+    pub index: FxHashMap<Id, Item>,+    /// Maps ids to fully qualified paths (e.g. `["std", "io", "lazy", "Lazy"]` for+    /// `std::io::lazy::Lazy`) as well as their `ItemKind`+    pub paths: FxHashMap<Id, ItemSummary>,+    /// Maps `crate_num` of items to a crate name and html_root_url if it exists+    pub external_crates: FxHashMap<u32, ExternalCrate>,+    /// A single version number to be used in the future when making backwards incompatible changes+    /// to the JSON output.+    pub format_version: u32,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct ExternalCrate {+    pub name: String,+    pub html_root_url: Option<String>,+}++/// For external items (stuff not defined in the local crate), you don't get the same level of+/// information. This struct should contain enough to generate a link/reference to the item in+/// question, or can be used by a tool that takes the json output of multiple crates to find+/// the actual item definition with all the relevant info.+#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct ItemSummary {+    pub crate_num: u32,+    pub path: Vec<String>,+    pub kind: ItemKind,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Item {+    /// This can be used as a key to the `external_crates` map of [`Crate`][] to see which crate+    /// this item came from.+    pub crate_num: u32,+    /// Some items such as impls don't have names.+    pub name: Option<String>,+    /// The source location of this item. May not be present if it came from a macro expansion,+    /// inline assembly, other "virtual" files.+    pub source: Option<Span>,+    /// Usually documented items are all public, but you can tell rustdoc to output private items+    /// so this field is needed to differentiate.+    pub visibility: Visibility,+    /// The full docstring of this item.+    pub docs: String,+    /// This mapping resolves [intradoc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs+    pub links: FxHashMap<String, Id>,+    /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)+    pub attrs: Vec<String>,+    pub deprecation: Option<Deprecation>,+    pub kind: ItemKind,+    pub inner: ItemEnum,+    // TODO: should we stringify the cfg attrs as well, or should we preserve their structure so+    // the consumer doesn't have to parse an arbitrarily nested tree to figure out what platforms+    // the item is available on?+    // TODO: should we have a "stability" field if it's only used by the standard library?+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Span {+    /// The path to the source file for this span relative to the crate root.+    pub filename: PathBuf,+    /// Zero indexed Line and Column of the first character of the `Span`+    pub begin: (usize, usize),+    /// Zero indexed Line and Column of the last character of the `Span`+    pub end: (usize, usize),+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Deprecation {+    pub since: Option<String>,+    pub note: Option<String>,+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum Visibility {+    Public,+    Default,+    Crate,+    // TODO: Restricted(Id, String),+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum GenericArgs {+    /// <'a, 32, B: Copy, C = u32>+    AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },+    /// Fn(A, B) -> C+    Parenthesized { inputs: Vec<Type>, output: Option<Type> },+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum GenericArg {+    Lifetime(String),+    Type(Type),+    Const(Constant),+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Constant {+    #[serde(rename = "type")]+    pub type_: Type,+    pub expr: String,+    pub value: Option<String>,+    pub is_literal: bool,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct TypeBinding {+    pub name: String,+    pub binding: TypeBindingKind,+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum TypeBindingKind {+    Equality(Type),+    Constraint(Vec<GenericBound>),+}++#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]+pub struct Id(pub String);++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum ItemKind {+    Module,+    ExternCrate,+    Import,+    Struct,+    StructField,+    Union,+    Enum,+    Variant,+    Function,+    Typedef,+    OpaqueTy,+    Constant,+    Trait,+    TraitAlias,+    Method,+    Impl,+    Static,+    ForeignType,+    Macro,+    ProcAttribute,+    ProcDerive,+    AssocConst,+    AssocType,+    Primitive,+    Keyword,+}++#[serde(untagged)]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum ItemEnum {+    ModuleItem(Module),+    ExternCrateItem {+        name: String,+        rename: Option<String>,+    },+    ImportItem(Import),++    StructItem(Struct),+    StructFieldItem(Type),+    EnumItem(Enum),+    VariantItem(Variant),++    FunctionItem(Function),++    TypedefItem(Typedef),+    OpaqueTyItem(OpaqueTy),+    ConstantItem(Constant),++    TraitItem(Trait),+    TraitAliasItem(TraitAlias),+    MethodItem(Method),+    ImplItem(Impl),++    StaticItem(Static),++    /// `type`s from an extern block+    ForeignTypeItem,++    /// Declarative macro_rules! macro+    MacroItem(String),+    ProcMacroItem(ProcMacro),++    AssocConstItem {+        #[serde(rename = "type")]+        type_: Type,+        default: Option<String>,+    },+    AssocTypeItem {+        bounds: Vec<GenericBound>,+        default: Option<Type>,+    },++    /// An item that has been stripped by a rustdoc pass+    StrippedItem(Box<ItemEnum>),+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Module {+    pub is_crate: bool,+    pub items: Vec<Id>,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Struct {+    pub struct_type: StructType,+    pub generics: Generics,+    pub fields_stripped: bool,+    pub fields: Vec<Id>,+    pub impls: Vec<Id>,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Enum {+    pub generics: Generics,+    pub variants_stripped: bool,+    pub variants: Vec<Id>,+    pub impls: Vec<Id>,+}++#[serde(rename_all = "snake_case")]+#[serde(tag = "variant_kind", content = "variant_inner")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum Variant {+    Plain,+    Tuple(Vec<Type>),+    Struct(Vec<Id>),+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum StructType {+    Plain,+    Tuple,+    Unit,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Function {+    pub decl: FnDecl,+    pub generics: Generics,+    pub header: String,+    pub abi: String,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Method {+    pub decl: FnDecl,+    pub generics: Generics,+    pub header: String,+    pub has_body: bool,+}++#[derive(Clone, Debug, Default, Serialize, Deserialize)]+pub struct Generics {+    pub params: Vec<GenericParamDef>,+    pub where_predicates: Vec<WherePredicate>,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct GenericParamDef {+    pub name: String,+    pub kind: GenericParamDefKind,+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum GenericParamDefKind {+    Lifetime,+    Type { bounds: Vec<GenericBound>, default: Option<Type> },+    Const(Type),+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum WherePredicate {+    BoundPredicate { ty: Type, bounds: Vec<GenericBound> },+    RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },+    EqPredicate { lhs: Type, rhs: Type },+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum GenericBound {+    TraitBound {+        #[serde(rename = "trait")]+        trait_: Type,+        /// Used for HRTBs+        generic_params: Vec<GenericParamDef>,+        modifier: TraitBoundModifier,+    },+    Outlives(String),+}++#[serde(rename_all = "snake_case")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum TraitBoundModifier {+    None,+    Maybe,+    MaybeConst,+}++#[serde(rename_all = "snake_case")]+#[serde(tag = "kind", content = "inner")]+#[derive(Clone, Debug, Serialize, Deserialize)]+pub enum Type {+    /// Structs, enums, and traits+    ResolvedPath {+        name: String,+        id: Id,+        args: Box<Option<GenericArgs>>,+        param_names: Vec<GenericBound>,+    },+    /// Parameterized types+    Generic(String),+    /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples+    Primitive(String),+    /// `extern "ABI" fn`+    FunctionPointer(Box<FunctionPointer>),+    /// `(String, u32, Box<usize>)`+    Tuple(Vec<Type>),+    /// `[u32]`+    Slice(Box<Type>),+    /// [u32; 15]+    Array {+        #[serde(rename = "type")]+        type_: Box<Type>,+        len: String,+    },+    /// `impl TraitA + TraitB + ...`+    ImplTrait(Vec<GenericBound>),+    /// `!`+    Never,+    /// `_`+    Infer,+    /// `*mut u32`, `*u8`, etc.+    RawPointer {+        mutable: bool,+        #[serde(rename = "type")]+        type_: Box<Type>,+    },+    /// `&'a mut String`, `&str`, etc.+    BorrowedRef {+        lifetime: Option<String>,+        mutable: bool,+        #[serde(rename = "type")]+        type_: Box<Type>,+    },+    /// `<Type as Trait>::Name` or associated types like `T::Item` where `T: Iterator`+    QualifiedPath {+        name: String,+        self_type: Box<Type>,+        #[serde(rename = "trait")]+        trait_: Box<Type>,+    },+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct FunctionPointer {+    pub is_unsafe: bool,+    pub generic_params: Vec<GenericParamDef>,+    pub decl: FnDecl,+    pub abi: String,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct FnDecl {+    pub inputs: Vec<(String, Type)>,+    pub output: Option<Type>,+    pub c_variadic: bool,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Trait {+    pub is_auto: bool,+    pub is_unsafe: bool,+    pub items: Vec<Id>,+    pub generics: Generics,+    pub bounds: Vec<GenericBound>,+    pub implementors: Vec<Id>,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct TraitAlias {+    pub generics: Generics,+    pub bounds: Vec<GenericBound>,+}++#[derive(Clone, Debug, Serialize, Deserialize)]+pub struct Impl {+    pub is_unsafe: bool,+    pub generics: Generics,+    pub provided_trait_methods: Vec<String>,+    #[serde(rename = "trait")]+    pub trait_: Option<Type>,+    #[serde(rename = "for")]+    pub for_: Type,

I wonder if we'd ever want to create an index of Types so we could de-duplicate them. This could be an open question on the RFC to consider before stabilizing.

P1n3appl3

comment created time in a day

Pull request review commentrust-lang/rust

JSON backend experimental impl

+mod conversions;+mod types;++use std::cell::RefCell;+use std::fs::File;+use std::rc::Rc;++use rustc_data_structures::fx::FxHashMap;+use rustc_span::edition::Edition;+ use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer;--use rustc_span::edition::Edition;+use crate::html::render::cache::ExternalLocation;  #[derive(Clone)]-pub struct JsonRenderer {}+pub struct JsonRenderer {+    index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,+}++impl JsonRenderer {+    fn insert(&self, item: clean::Item, cache: &Cache) {+        let id = item.def_id;+        let mut new_item: types::Item = item.into();+        if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner {+            t.implementors = self.get_trait_implementors(id, cache)+        } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner {+            s.impls = self.get_impls(id, cache)+        } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner {+            e.impls = self.get_impls(id, cache)+        }+        self.index.borrow_mut().insert(id.into(), new_item);+    }++    fn get_trait_implementors(+        &self,+        id: rustc_span::def_id::DefId,+        cache: &Cache,+    ) -> Vec<types::Id> {+        cache+            .implementors+            .get(&id)+            .map(|implementors| {+                implementors+                    .iter()+                    .map(|i| {+                        let item = &i.impl_item;+                        self.insert(item.clone(), cache);+                        item.def_id.into()+                    })+                    .collect()+            })+            .unwrap_or_default()+    }++    fn get_impls(&self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec<types::Id> {+        cache+            .impls+            .get(&id)+            .map(|impls| {+                impls+                    .iter()+                    .filter_map(|i| {+                        let item = &i.impl_item;+                        if item.def_id.is_local() {+                            self.insert(item.clone(), cache);+                            Some(item.def_id.into())+                        } else {+                            None+                        }+                    })+                    .collect()+            })+            .unwrap_or_default()+    }+}  impl FormatRenderer for JsonRenderer {     fn init(-        _krate: clean::Crate,+        krate: clean::Crate,         _options: RenderOptions,         _render_info: RenderInfo,         _edition: Edition,         _cache: &mut Cache,     ) -> Result<(Self, clean::Crate), Error> {-        unimplemented!()+        debug!("Initializing json renderer");+        Ok((JsonRenderer { index: Rc::new(RefCell::new(FxHashMap::default())) }, krate))     } -    fn item(&mut self, _item: clean::Item, _cache: &Cache) -> Result<(), Error> {-        unimplemented!()+    fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> {+        use clean::ItemEnum::*;+        // Flatten items that recursively store other items by putting their children in the index+        match item.inner.clone() {+            StructItem(s) => s.fields.into_iter().for_each(|i| self.insert(i, cache)),+            UnionItem(u) => u.fields.into_iter().for_each(|i| self.insert(i, cache)),+            VariantItem(clean::Variant { kind: clean::VariantKind::Struct(v) }) => {+                v.fields.into_iter().for_each(|i| self.insert(i, cache));+            }+            EnumItem(e) => e.variants.into_iter().for_each(|i| self.item(i, cache).unwrap()),+            TraitItem(t) => t.items.into_iter().for_each(|i| self.insert(i, cache)),+            ImplItem(i) => i.items.into_iter().for_each(|i| self.insert(i, cache)),+            _ => {}+        }+        self.insert(item.clone(), cache);+        Ok(())     }      fn mod_item_in(         &mut self,-        _item: &clean::Item,+        item: &clean::Item,         _item_name: &str,-        _cache: &Cache,+        cache: &Cache,     ) -> Result<(), Error> {-        unimplemented!()+        self.insert(item.clone(), cache);+        Ok(())     }      fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> {-        unimplemented!()+        Ok(())     } -    fn after_krate(&mut self, _krate: &clean::Crate, _cache: &Cache) -> Result<(), Error> {-        unimplemented!()+    fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> {+        debug!("Done with crate");+        let mut index = (*self.index).clone().into_inner();+        let trait_items = cache.traits.iter().filter_map(|(id, trait_item)| {

nit: this could be extracted to a function instead of happening directly in after_krate

P1n3appl3

comment created time in a day

Pull request review commentrust-lang/rust

JSON backend experimental impl

+mod conversions;+mod types;++use std::cell::RefCell;+use std::fs::File;+use std::rc::Rc;++use rustc_data_structures::fx::FxHashMap;+use rustc_span::edition::Edition;+ use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer;--use rustc_span::edition::Edition;+use crate::html::render::cache::ExternalLocation;  #[derive(Clone)]-pub struct JsonRenderer {}+pub struct JsonRenderer {+    index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,

This and/or insert could use some docs about what they're for

P1n3appl3

comment created time in a day

issue commentrust-lang/rust

std::fs::canonicalize returns UNC paths on Windows, and a lot of software doesn't support UNC paths

Unless I'm somehow mistaken, it seems that one tool that doesn't support UNC paths is rustc itself: I tried to pass a UNC path to --extern and it claimed the path didn't exist until I trimmed off the \\?\.

radix

comment created time in 4 days

issue commentrust-lang/compiler-team

Set ninja=true by default

As a data point, this is how we build rust for fuchsia. I don't think it's ever caused any problems.

joshtriplett

comment created time in 4 days

pull request commentrust-lang/rust

Rust function-level coverage now works on external crates

@bors r+ rollup

richkadel

comment created time in 5 days

pull request commentrust-lang/rust

Add `--output-format json` for Rustdoc on nightly

@bors r=GuillaumeGomez

P1n3appl3

comment created time in 6 days

pull request commentrust-lang/rust

Add `--output-format json` for Rustdoc on nightly

@bors rollup=always

P1n3appl3

comment created time in 6 days

pull request commentrust-lang/rust

Add `--output-format json` for Rustdoc on nightly

cc @GuillaumeGomez

P1n3appl3

comment created time in 6 days

pull request commentrust-lang/rust

Refactor librustdoc html backend

@jyn514 rollups already ignore PRs that have merge conflicts when creating them

P1n3appl3

comment created time in 6 days

pull request commentrust-lang/rust

Refactor librustdoc html backend

@bors r+

P1n3appl3

comment created time in 6 days

Pull request review commentrust-lang/rust

Refactor librustdoc html backend

 pub trait PathError {         S: ToString + Sized; } -pub struct ErrorStorage {-    sender: Option<Sender<Option<String>>>,-    receiver: Receiver<Option<String>>,-}--impl ErrorStorage {-    pub fn new() -> ErrorStorage {-        let (sender, receiver) = channel();-        ErrorStorage { sender: Some(sender), receiver }-    }--    /// Prints all stored errors. Returns the number of printed errors.-    pub fn write_errors(&mut self, diag: &rustc_errors::Handler) -> usize {-        let mut printed = 0;-        // In order to drop the sender part of the channel.-        self.sender = None;--        for msg in self.receiver.iter() {-            if let Some(ref error) = msg {-                diag.struct_err(&error).emit();-                printed += 1;-            }-        }-        printed-    }-}- pub struct DocFS {     sync_only: bool,-    errors: Arc<ErrorStorage>,+    errors: Option<Sender<String>>, }  impl DocFS {-    pub fn new(errors: &Arc<ErrorStorage>) -> DocFS {-        DocFS { sync_only: false, errors: Arc::clone(errors) }+    pub fn new(errors: &Sender<String>) -> DocFS {

nit: better to pass the sender by value, the caller shouldn't need it

P1n3appl3

comment created time in 6 days

issue commentmicrosoft/vscode

Create a node-pty host process with flow control and event batching

Restoring the actual terminal session would be great, but restoring the shell layout with current directory and scrollback saved would give 99% of the benefits for me.

Tyriar

comment created time in 7 days

pull request commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

I think this is ready to merge. @bors r+

richkadel

comment created time in 7 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {     }      fn inject_counters(&mut self) {+        let mir_body = &self.mir_body;         let body_span = self.hir_body.value.span;-        debug!(-            "instrumenting {:?}, span: {}",-            self.mir_def_id,-            self.tcx.sess.source_map().span_to_string(body_span)-        );+        debug!("instrumenting {:?}, span: {:?}", self.mir_def_id, body_span);          // FIXME(richkadel): As a first step, counters are only injected at the top of each         // function. The complete solution will inject counters at each conditional code branch.-        let next_block = START_BLOCK;-        self.inject_counter(body_span, next_block);+        let _ignore = mir_body;+        let id = self.next_counter();+        let function_source_hash = self.function_source_hash();

Binding is_cleanup makes the code more readable, but I'm not sure this does

richkadel

comment created time in 7 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

-use rustc_data_structures::sync::Lrc;-use rustc_middle::mir;-use rustc_span::source_map::{Pos, SourceFile, SourceMap};-use rustc_span::{BytePos, FileName, RealFileName};+use rustc_middle::ty::Instance;+use rustc_middle::ty::TyCtxt;+use rustc_span::source_map::{Pos, SourceMap};+use rustc_span::{BytePos, FileName, Loc, RealFileName};  use std::cmp::{Ord, Ordering};-use std::collections::BTreeMap; use std::fmt; use std::path::PathBuf; +/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discriminators is important. #[derive(Copy, Clone, Debug)] #[repr(C)]-pub enum CounterOp {-    // Note the order (and therefore the default values) is important. With the attribute-    // `#[repr(C)]`, this enum matches the layout of the LLVM enum defined for the nested enum,-    // `llvm::coverage::CounterExpression::ExprKind`, as shown in the following source snippet:-    // https://github.com/rust-lang/llvm-project/blob/f208b70fbc4dee78067b3c5bd6cb92aa3ba58a1e/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146-    Subtract,-    Add,+enum CounterKind {+    Zero,+    CounterValueReference,+    Expression, } +/// Aligns to C++ struct llvm::coverage::Counter. Note that `id` has+/// different interpretations, depending on the `kind`:+///   * For `CounterKind::Zero`, `id` is assumed to be `0`+///   * For `CounterKind::CounterValueReference`,  `id` matches the `counter_id` of the injected+///     instrumentation counter (the `index` argument to the LLVM intrinsic `instrprof.increment()`)+///   * For `CounterKind::Expression`, `id` is the index into the array of counter expressions.+/// The order of fields is important. #[derive(Copy, Clone, Debug)]-pub enum CoverageKind {-    Counter,-    CounterExpression(u32, CounterOp, u32),-    Unreachable,+#[repr(C)]+pub struct Counter {+    kind: CounterKind,+    id: u32, } -#[derive(Clone, Debug)]-pub struct CoverageRegion {-    pub kind: CoverageKind,-    pub start_byte_pos: u32,-    pub end_byte_pos: u32,-}+impl Counter {+    pub fn zero() -> Self {+        Self { kind: CounterKind::Zero, id: 0 }+    } -impl CoverageRegion {-    pub fn source_loc(&self, source_map: &SourceMap) -> Option<(Lrc<SourceFile>, CoverageLoc)> {-        let (start_file, start_line, start_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.start_byte_pos));-        let (end_file, end_line, end_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.end_byte_pos));-        let start_file_path = match &start_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => {-                bug!("start_file_path should be a RealFileName, but it was: {:?}", start_file.name)-            }-        };-        let end_file_path = match &end_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => bug!("end_file_path should be a RealFileName, but it was: {:?}", end_file.name),-        };-        if start_file_path == end_file_path {-            Some((start_file, CoverageLoc { start_line, start_col, end_line, end_col }))-        } else {-            None-            // FIXME(richkadel): There seems to be a problem computing the file location in-            // some cases. I need to investigate this more. When I generate and show coverage-            // for the example binary in the crates.io crate `json5format`, I had a couple of-            // notable problems:-            //-            //   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in-            //      various comments (not corresponding to rustdoc code), indicating a possible-            //      problem with the byte_pos-to-source-map implementation.-            //-            //   2. And (perhaps not related) when I build the aforementioned example binary with:-            //      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`-            //      and then run that binary with-            //      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \-            //      some.json5` for some reason the binary generates *TWO* `.profraw` files. One-            //      named `default.profraw` and the other named `formatjson5.profraw` (the expected-            //      name, in this case).-            //-            // If the byte range conversion is wrong, fix it. But if it-            // is right, then it is possible for the start and end to be in different files.-            // Can I do something other than ignore coverages that span multiple files?-            //-            // If I can resolve this, remove the "Option<>" result type wrapper-            // `regions_in_file_order()` accordingly.-        }+    pub fn counter_value_reference(counter_id: u32) -> Self {+        Self { kind: CounterKind::CounterValueReference, id: counter_id }+    }++    pub fn expression(final_expression_index: u32) -> Self {+        Self { kind: CounterKind::Expression, id: final_expression_index }     } } -impl Default for CoverageRegion {-    fn default() -> Self {-        Self {-            // The default kind (Unreachable) is a placeholder that will be overwritten before-            // backend codegen.-            kind: CoverageKind::Unreachable,-            start_byte_pos: 0,-            end_byte_pos: 0,-        }+/// Aligns to C++ struct llvm::coverage::CounterExpression::ExprKind.+/// The order of discriminators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub enum ExprKind {+    Subtract,+    Add,+}++/// Aligns to C++ struct llvm::coverage::CounterExpression.+/// The order of fields is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub struct CounterExpression {+    // Note the field order is important.+    kind: ExprKind,+    lhs: Counter,+    rhs: Counter,+}++impl CounterExpression {+    pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self {+        Self { kind, lhs, rhs }     } } -/// A source code region used with coverage information.-#[derive(Debug, Eq, PartialEq)]-pub struct CoverageLoc {-    /// The (1-based) line number of the region start.-    pub start_line: u32,-    /// The (1-based) column number of the region start.-    pub start_col: u32,-    /// The (1-based) line number of the region end.-    pub end_line: u32,-    /// The (1-based) column number of the region end.-    pub end_col: u32,+#[derive(Clone, Debug)]+pub struct Region {+    start: Loc,+    end: Loc, } -impl Ord for CoverageLoc {+impl Ord for Region {     fn cmp(&self, other: &Self) -> Ordering {-        (self.start_line, &self.start_col, &self.end_line, &self.end_col).cmp(&(-            other.start_line,-            &other.start_col,-            &other.end_line,-            &other.end_col,-        ))+        (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col)+            .cmp(&(+                &other.start.file.name,+                &other.start.line,+                &other.start.col,+                &other.end.line,+                &other.end.col,+            ))     } } -impl PartialOrd for CoverageLoc {+impl PartialOrd for Region {     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {         Some(self.cmp(other))     } } -impl fmt::Display for CoverageLoc {+impl PartialEq for Region {+    fn eq(&self, other: &Self) -> bool {+        self.start.file.name == other.start.file.name+            && self.start.line == other.start.line+            && self.start.col == other.start.col+            && self.end.line == other.end.line+            && self.end.col == other.end.col+    }+}++impl Eq for Region {}++impl fmt::Display for Region {     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {-        // Customize debug format, and repeat the file name, so generated location strings are-        // "clickable" in many IDEs.-        write!(f, "{}:{} - {}:{}", self.start_line, self.start_col, self.end_line, self.end_col)+        let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end();+        write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col)     } } -fn lookup_file_line_col(source_map: &SourceMap, byte_pos: BytePos) -> (Lrc<SourceFile>, u32, u32) {-    let found = source_map-        .lookup_line(byte_pos)-        .expect("should find coverage region byte position in source");-    let file = found.sf;-    let line_pos = file.line_begin_pos(byte_pos);+impl Region {+    pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self {+        let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos));+        let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos));+        assert_eq!(start.file.name, end.file.name);+        Self { start, end }+    } -    // Use 1-based indexing.-    let line = (found.line + 1) as u32;-    let col = (byte_pos - line_pos).to_u32() + 1;+    pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) {+        let start = &self.start;+        let end = &self.end;+        match &start.file.name {+            FileName::Real(RealFileName::Named(path)) => (+                path,+                start.line as u32,+                start.col.to_u32() + 1,+                end.line as u32,+                end.col.to_u32() + 1,+            ),+            _ => {+                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)+            }+        }+    }+} -    (file, line, col)+#[derive(Clone, Debug)]+pub struct ExpressionRegion {+    lhs: u32,+    op: ExprKind,+    rhs: u32,+    region: Region, } +// FIXME(richkadel): There seems to be a problem computing the file location in+// some cases. I need to investigate this more. When I generate and show coverage+// for the example binary in the crates.io crate `json5format`, I had a couple of+// notable problems:+//+//   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in+//      various comments (not corresponding to rustdoc code), indicating a possible+//      problem with the byte_pos-to-source-map implementation.+//+//   2. And (perhaps not related) when I build the aforementioned example binary with:+//      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`+//      and then run that binary with+//      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \+//      some.json5` for some reason the binary generates *TWO* `.profraw` files. One+//      named `default.profraw` and the other named `formatjson5.profraw` (the expected+//      name, in this case).+//+//   3. I think that if I eliminate regions within a function, their region_ids,+//      referenced in expressions, will be wrong? I think the ids are implied by their+//      array position in the final coverage map output (IIRC).+//+//   4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some+//      region start/end byte positions. Just like I couldn't get the function hash at+//      intrinsic codegen time for external crate functions, I think the SourceMap I+//      have here only applies to the local crate, and I know I have coverages that+//      reference external crates.+//+//          I still don't know if I fixed the hash problem correctly. If external crates+//          implement the function, can't I use the coverage counters already compiled+//          into those external crates? (Maybe not for generics and/or maybe not for

I'm saying that the solution we already use for code (weak linkage) might work for the counters, too.

richkadel

comment created time in 7 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();         coverage_regions             .entry(instance)-            .or_insert_with(|| {-                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))-            })-            .add_unreachable(start_byte_pos, end_byte_pos);+            .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))+            .add_unreachable_region(start_byte_pos, end_byte_pos);     } } -/// This struct wraps an opaque reference to the C++ template instantiation of-/// `llvm::SmallVector<coverage::CounterExpression>`. Each `coverage::CounterExpression` object is-/// constructed from primative-typed arguments, and pushed to the `SmallVector`, in the C++-/// implementation of `LLVMRustCoverageSmallVectorCounterExpressionAdd()` (see-/// `src/rustllvm/CoverageMappingWrapper.cpp`).-pub struct SmallVectorCounterExpression<'a> {-    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterExpression<'a>,-}+/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discrimiators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+enum RegionKind {+    /// A CodeRegion associates some code with a counter+    CodeRegion, -impl SmallVectorCounterExpression<'a> {-    pub fn new() -> Self {-        SmallVectorCounterExpression {-            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterExpressionCreate() },-        }-    }+    /// An ExpansionRegion represents a file expansion region that associates+    /// a source range with the expansion of a virtual source file, such as+    /// for a macro instantiation or #include file.+    ExpansionRegion, -    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterExpression<'a> {-        self.raw-    }+    /// A SkippedRegion represents a source range with code that was skipped+    /// by a preprocessor or similar means.+    SkippedRegion, -    pub fn push_from(-        &mut self,-        kind: rustc_codegen_ssa::coverageinfo::CounterOp,-        left_index: u32,-        right_index: u32,-    ) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionAdd(-                &mut *(self.raw as *mut _),-                kind,-                left_index,-                right_index,-            )-        }-    }+    /// A GapRegion is like a CodeRegion, but its count is only set as the+    /// line execution count when its the only region in the line.+    GapRegion, } -impl Drop for SmallVectorCounterExpression<'a> {-    fn drop(&mut self) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionDispose(&mut *(self.raw as *mut _));-        }-    }-}+/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the+/// coverage map in accordance with LLVM's "Coverage Mapping Format". The struct composes fields+/// representing the `Counter` type and value(s) (injected counter ID, or expression type and+/// operands), the source file (an indirect index into a "filenames array", encoded separately),+/// and source location (start and end positions of the represented code region).+///+/// Aligns to C++ struct llvm::coverage::CounterMappingRegion.

Okay, we may want to consider putting these in the file you mention so as not to make upgrading LLVM harder. Or in a coverageinfo/ffi.rs which makes it easier to find.

richkadel

comment created time in 7 days

issue openedrust-analyzer/rust-analyzer

Use branch, not tag, for nightly

The fact that the nightly tag regularly changes causes errors while fetching rust in our infrastructure:

Fetching submodule src/tools/rust-analyzer
From https://github.com/rust-analyzer/rust-analyzer
 + 8f51657c6...def1a2c14 gh-pages   -> origin/gh-pages  (forced update)
   41feb816c..5a8124273  master     -> origin/master
   8b0983e89..8ff40af72  release    -> origin/release
   41feb816c..5a8124273  staging    -> origin/staging
 * [new tag]             2020-07-13 -> 2020-07-13
 * [new tag]             2020-07-20 -> 2020-07-20
 * [new tag]             2020-07-27 -> 2020-07-27
 ! [rejected]            nightly    -> nightly  (would clobber existing tag)
Errors during submodule fetch:
        src/tools/rust-analyzer

There are options to fix this I'm sure, but tags aren't expected to change like this (certainly not on a regular basis); that's what branches are for.

created time in 7 days

issue commentrust-lang/cargo

`cargo metadata` output shouldn't filter by target in .cargo/config

This was a stable-to-beta regression and is now a stable-to-stable regression, I think it needs to be marked as such.

ComputerDruid

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 use std::path::PathBuf; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {-    let mut coverage_writer = CoverageMappingWriter::new(cx);-     let function_coverage_map = cx.coverage_context().take_function_coverage_map();+    if function_coverage_map.len() == 0 {+        // This module has no functions with coverage instrumentation+        return;+    }++    let mut mapgen = CoverageMapGenerator::new();      // Encode coverage mappings and generate function records     let mut function_records = Vec::<&'ll llvm::Value>::new();     let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| {         for (instance, function_coverage) in function_coverage_map.into_iter() {-            if let Some(function_record) = coverage_writer.write_function_mappings_and_record(-                instance,-                function_coverage,-                coverage_mappings_buffer,-            ) {-                function_records.push(function_record);-            }+            debug!("Generate coverage map for: {:?}", instance);++            let mangled_function_name = cx.tcx.symbol_name(instance).to_string();+            let function_source_hash = function_coverage.source_hash();+            let (expressions, counter_regions) =+                function_coverage.get_expressions_and_counter_regions();++            let old_len = coverage_mappings_buffer.len();+            mapgen.write_coverage_mappings(expressions, counter_regions, coverage_mappings_buffer);+            let mapping_data_size = coverage_mappings_buffer.len() - old_len;+            debug_assert!(+                mapping_data_size > 0,+                "Every `FunctionCoverage` should have at least one counter"+            );++            let function_record = mapgen.make_function_record(+                cx,+                mangled_function_name,+                function_source_hash,+                mapping_data_size,+            );+            function_records.push(function_record);         }     }); -    // Encode all filenames covered in this module, ordered by `file_id`+    // Encode all filenames referenced by counters/expressions in this module     let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {-        coverageinfo::write_filenames_section_to_buffer(-            &coverage_writer.filenames,-            filenames_buffer,-        );+        coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);     }); -    if coverage_mappings_buffer.len() > 0 {-        // Generate the LLVM IR representation of the coverage map and store it in a well-known-        // global constant.-        coverage_writer.write_coverage_map(-            function_records,-            filenames_buffer,-            coverage_mappings_buffer,-        );-    }+    // Generate the LLVM IR representation of the coverage map and store it in a well-known global+    mapgen.save_generated_coverage_map(+        cx,+        function_records,+        filenames_buffer,+        coverage_mappings_buffer,+    ); } -struct CoverageMappingWriter<'a, 'll, 'tcx> {-    cx: &'a CodegenCx<'ll, 'tcx>,+struct CoverageMapGenerator {     filenames: Vec<CString>,     filename_to_index: FxHashMap<CString, u32>, } -impl<'a, 'll, 'tcx> CoverageMappingWriter<'a, 'll, 'tcx> {-    fn new(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {-        Self { cx, filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }+impl CoverageMapGenerator {+    fn new() -> Self {+        Self { filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }     } -    /// For the given function, get the coverage region data, stream it to the given buffer, and-    /// then generate and return a new function record.-    fn write_function_mappings_and_record(+    /// Using the `expressions` and `counter_regions` collected for the current function, generate+    /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use+    /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into+    /// the given `coverage_mappings` byte buffer, compliant with the LLVM Coverage Mapping format.+    fn write_coverage_mappings(         &mut self,-        instance: Instance<'tcx>,-        mut function_coverage: FunctionCoverage,+        expressions: Vec<CounterExpression>,+        counter_regions: impl Iterator<Item = (Counter, &'a Region)>,         coverage_mappings_buffer: &RustString,-    ) -> Option<&'ll llvm::Value> {-        let cx = self.cx;-        let coverageinfo: &mir::CoverageInfo = cx.tcx.coverageinfo(instance.def_id());-        debug!(-            "Generate coverage map for: {:?}, num_counters: {}, num_expressions: {}",-            instance, coverageinfo.num_counters, coverageinfo.num_expressions-        );-        debug_assert!(coverageinfo.num_counters > 0);--        let regions_in_file_order = function_coverage.regions_in_file_order(cx.sess().source_map());-        if regions_in_file_order.len() == 0 {-            return None;+    ) {+        let mut counter_regions = counter_regions.collect::<Vec<_>>();+        if counter_regions.len() == 0 {+            return;         } -        // Stream the coverage mapping regions for the function (`instance`) to the buffer, and-        // compute the data byte size used.-        let old_len = coverage_mappings_buffer.len();-        self.regions_to_mappings(regions_in_file_order, coverage_mappings_buffer);-        let mapping_data_size = coverage_mappings_buffer.len() - old_len;-        debug_assert!(mapping_data_size > 0);--        let mangled_function_name = cx.tcx.symbol_name(instance).to_string();-        let name_ref = coverageinfo::compute_hash(&mangled_function_name);-        let function_source_hash = function_coverage.source_hash();--        // Generate and return the function record-        let name_ref_val = cx.const_u64(name_ref);-        let mapping_data_size_val = cx.const_u32(mapping_data_size as u32);-        let func_hash_val = cx.const_u64(function_source_hash);-        Some(cx.const_struct(-            &[name_ref_val, mapping_data_size_val, func_hash_val],-            /*packed=*/ true,-        ))-    }--    /// For each coverage region, extract its coverage data from the earlier coverage analysis.-    /// Use LLVM APIs to convert the data into buffered bytes compliant with the LLVM Coverage-    /// Mapping format.-    fn regions_to_mappings(-        &mut self,-        regions_in_file_order: BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>>,-        coverage_mappings_buffer: &RustString,-    ) {         let mut virtual_file_mapping = Vec::new();-        let mut mapping_regions = coverageinfo::SmallVectorCounterMappingRegion::new();-        let mut expressions = coverageinfo::SmallVectorCounterExpression::new();--        for (file_id, (file_path, file_coverage_regions)) in-            regions_in_file_order.into_iter().enumerate()-        {-            let file_id = file_id as u32;-            let filename = CString::new(file_path.to_string_lossy().to_string())-                .expect("null error converting filename to C string");-            debug!("  file_id: {} = '{:?}'", file_id, filename);-            let filenames_index = match self.filename_to_index.get(&filename) {-                Some(index) => *index,-                None => {-                    let index = self.filenames.len() as u32;-                    self.filenames.push(filename.clone());-                    self.filename_to_index.insert(filename, index);-                    index+        let mut mapping_regions = Vec::new();+        let mut current_file_path = None;+        let mut current_file_id = 0;++        // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted+        // by filename and position. Capture any new files to compute the `CounterMappingRegion`s+        // `file_id` (indexing files referenced by the current function), and construct the+        // function-specific `virtual_file_mapping` from `file_id` to its index in the module's+        // `filenames` array.+        counter_regions.sort_by_key(|(_counter, region)| *region);+        for (counter, region) in counter_regions {+            let (file_path, start_line, start_col, end_line, end_col) = region.file_start_and_end();+            let same_file = current_file_path.as_ref().map_or(false, |p| p == file_path);+            if !same_file {+                if current_file_path.is_some() {+                    current_file_id += 1;                 }-            };-            virtual_file_mapping.push(filenames_index);--            let mut mapping_indexes = vec![0 as u32; file_coverage_regions.len()];-            for (mapping_index, (region_id, _)) in file_coverage_regions.values().enumerate() {-                mapping_indexes[*region_id] = mapping_index as u32;-            }--            for (region_loc, (region_id, region_kind)) in file_coverage_regions.into_iter() {-                let mapping_index = mapping_indexes[region_id];-                match region_kind {-                    CoverageKind::Counter => {-                        debug!(-                            "  Counter {}, file_id: {}, region_loc: {}",-                            mapping_index, file_id, region_loc-                        );-                        mapping_regions.push_from(-                            mapping_index,-                            file_id,-                            region_loc.start_line,-                            region_loc.start_col,-                            region_loc.end_line,-                            region_loc.end_col,-                        );-                    }-                    CoverageKind::CounterExpression(lhs, op, rhs) => {-                        debug!(-                            "  CounterExpression {} = {} {:?} {}, file_id: {}, region_loc: {:?}",-                            mapping_index, lhs, op, rhs, file_id, region_loc,-                        );-                        mapping_regions.push_from(-                            mapping_index,-                            file_id,-                            region_loc.start_line,-                            region_loc.start_col,-                            region_loc.end_line,-                            region_loc.end_col,-                        );-                        expressions.push_from(op, lhs, rhs);-                    }-                    CoverageKind::Unreachable => {-                        debug!(-                            "  Unreachable region, file_id: {}, region_loc: {:?}",-                            file_id, region_loc,-                        );-                        bug!("Unreachable region not expected and not yet handled!")-                        // FIXME(richkadel): implement and call-                        //   mapping_regions.push_from(...) for unreachable regions+                current_file_path = Some(file_path.clone());+                let filename = CString::new(file_path.to_string_lossy().to_string())+                    .expect("null error converting filename to C string");+                debug!("  file_id: {} = '{:?}'", current_file_id, filename);+                let filenames_index = match self.filename_to_index.get(&filename) {

can probably use the entry API here, too

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

-use rustc_data_structures::sync::Lrc;-use rustc_middle::mir;-use rustc_span::source_map::{Pos, SourceFile, SourceMap};-use rustc_span::{BytePos, FileName, RealFileName};+use rustc_middle::ty::Instance;+use rustc_middle::ty::TyCtxt;+use rustc_span::source_map::{Pos, SourceMap};+use rustc_span::{BytePos, FileName, Loc, RealFileName};  use std::cmp::{Ord, Ordering};-use std::collections::BTreeMap; use std::fmt; use std::path::PathBuf; +/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discriminators is important. #[derive(Copy, Clone, Debug)] #[repr(C)]-pub enum CounterOp {-    // Note the order (and therefore the default values) is important. With the attribute-    // `#[repr(C)]`, this enum matches the layout of the LLVM enum defined for the nested enum,-    // `llvm::coverage::CounterExpression::ExprKind`, as shown in the following source snippet:-    // https://github.com/rust-lang/llvm-project/blob/f208b70fbc4dee78067b3c5bd6cb92aa3ba58a1e/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146-    Subtract,-    Add,+enum CounterKind {+    Zero,+    CounterValueReference,+    Expression, } +/// Aligns to C++ struct llvm::coverage::Counter. Note that `id` has+/// different interpretations, depending on the `kind`:+///   * For `CounterKind::Zero`, `id` is assumed to be `0`+///   * For `CounterKind::CounterValueReference`,  `id` matches the `counter_id` of the injected+///     instrumentation counter (the `index` argument to the LLVM intrinsic `instrprof.increment()`)+///   * For `CounterKind::Expression`, `id` is the index into the array of counter expressions.+/// The order of fields is important. #[derive(Copy, Clone, Debug)]-pub enum CoverageKind {-    Counter,-    CounterExpression(u32, CounterOp, u32),-    Unreachable,+#[repr(C)]+pub struct Counter {+    kind: CounterKind,+    id: u32, } -#[derive(Clone, Debug)]-pub struct CoverageRegion {-    pub kind: CoverageKind,-    pub start_byte_pos: u32,-    pub end_byte_pos: u32,-}+impl Counter {+    pub fn zero() -> Self {+        Self { kind: CounterKind::Zero, id: 0 }+    } -impl CoverageRegion {-    pub fn source_loc(&self, source_map: &SourceMap) -> Option<(Lrc<SourceFile>, CoverageLoc)> {-        let (start_file, start_line, start_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.start_byte_pos));-        let (end_file, end_line, end_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.end_byte_pos));-        let start_file_path = match &start_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => {-                bug!("start_file_path should be a RealFileName, but it was: {:?}", start_file.name)-            }-        };-        let end_file_path = match &end_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => bug!("end_file_path should be a RealFileName, but it was: {:?}", end_file.name),-        };-        if start_file_path == end_file_path {-            Some((start_file, CoverageLoc { start_line, start_col, end_line, end_col }))-        } else {-            None-            // FIXME(richkadel): There seems to be a problem computing the file location in-            // some cases. I need to investigate this more. When I generate and show coverage-            // for the example binary in the crates.io crate `json5format`, I had a couple of-            // notable problems:-            //-            //   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in-            //      various comments (not corresponding to rustdoc code), indicating a possible-            //      problem with the byte_pos-to-source-map implementation.-            //-            //   2. And (perhaps not related) when I build the aforementioned example binary with:-            //      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`-            //      and then run that binary with-            //      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \-            //      some.json5` for some reason the binary generates *TWO* `.profraw` files. One-            //      named `default.profraw` and the other named `formatjson5.profraw` (the expected-            //      name, in this case).-            //-            // If the byte range conversion is wrong, fix it. But if it-            // is right, then it is possible for the start and end to be in different files.-            // Can I do something other than ignore coverages that span multiple files?-            //-            // If I can resolve this, remove the "Option<>" result type wrapper-            // `regions_in_file_order()` accordingly.-        }+    pub fn counter_value_reference(counter_id: u32) -> Self {+        Self { kind: CounterKind::CounterValueReference, id: counter_id }+    }++    pub fn expression(final_expression_index: u32) -> Self {+        Self { kind: CounterKind::Expression, id: final_expression_index }     } } -impl Default for CoverageRegion {-    fn default() -> Self {-        Self {-            // The default kind (Unreachable) is a placeholder that will be overwritten before-            // backend codegen.-            kind: CoverageKind::Unreachable,-            start_byte_pos: 0,-            end_byte_pos: 0,-        }+/// Aligns to C++ struct llvm::coverage::CounterExpression::ExprKind.+/// The order of discriminators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub enum ExprKind {+    Subtract,+    Add,+}++/// Aligns to C++ struct llvm::coverage::CounterExpression.+/// The order of fields is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub struct CounterExpression {+    // Note the field order is important.+    kind: ExprKind,+    lhs: Counter,+    rhs: Counter,+}++impl CounterExpression {+    pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self {+        Self { kind, lhs, rhs }     } } -/// A source code region used with coverage information.-#[derive(Debug, Eq, PartialEq)]-pub struct CoverageLoc {-    /// The (1-based) line number of the region start.-    pub start_line: u32,-    /// The (1-based) column number of the region start.-    pub start_col: u32,-    /// The (1-based) line number of the region end.-    pub end_line: u32,-    /// The (1-based) column number of the region end.-    pub end_col: u32,+#[derive(Clone, Debug)]+pub struct Region {+    start: Loc,+    end: Loc, } -impl Ord for CoverageLoc {+impl Ord for Region {     fn cmp(&self, other: &Self) -> Ordering {-        (self.start_line, &self.start_col, &self.end_line, &self.end_col).cmp(&(-            other.start_line,-            &other.start_col,-            &other.end_line,-            &other.end_col,-        ))+        (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col)+            .cmp(&(+                &other.start.file.name,+                &other.start.line,+                &other.start.col,+                &other.end.line,+                &other.end.col,+            ))     } } -impl PartialOrd for CoverageLoc {+impl PartialOrd for Region {     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {         Some(self.cmp(other))     } } -impl fmt::Display for CoverageLoc {+impl PartialEq for Region {+    fn eq(&self, other: &Self) -> bool {+        self.start.file.name == other.start.file.name+            && self.start.line == other.start.line+            && self.start.col == other.start.col+            && self.end.line == other.end.line+            && self.end.col == other.end.col+    }+}++impl Eq for Region {}++impl fmt::Display for Region {     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {-        // Customize debug format, and repeat the file name, so generated location strings are-        // "clickable" in many IDEs.-        write!(f, "{}:{} - {}:{}", self.start_line, self.start_col, self.end_line, self.end_col)+        let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end();+        write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col)     } } -fn lookup_file_line_col(source_map: &SourceMap, byte_pos: BytePos) -> (Lrc<SourceFile>, u32, u32) {-    let found = source_map-        .lookup_line(byte_pos)-        .expect("should find coverage region byte position in source");-    let file = found.sf;-    let line_pos = file.line_begin_pos(byte_pos);+impl Region {+    pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self {+        let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos));+        let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos));+        assert_eq!(start.file.name, end.file.name);+        Self { start, end }+    } -    // Use 1-based indexing.-    let line = (found.line + 1) as u32;-    let col = (byte_pos - line_pos).to_u32() + 1;+    pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) {+        let start = &self.start;+        let end = &self.end;+        match &start.file.name {+            FileName::Real(RealFileName::Named(path)) => (+                path,+                start.line as u32,+                start.col.to_u32() + 1,+                end.line as u32,+                end.col.to_u32() + 1,+            ),+            _ => {+                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)+            }+        }+    }+} -    (file, line, col)+#[derive(Clone, Debug)]+pub struct ExpressionRegion {+    lhs: u32,+    op: ExprKind,+    rhs: u32,+    region: Region, } +// FIXME(richkadel): There seems to be a problem computing the file location in+// some cases. I need to investigate this more. When I generate and show coverage+// for the example binary in the crates.io crate `json5format`, I had a couple of+// notable problems:+//+//   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in+//      various comments (not corresponding to rustdoc code), indicating a possible+//      problem with the byte_pos-to-source-map implementation.+//+//   2. And (perhaps not related) when I build the aforementioned example binary with:+//      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`+//      and then run that binary with+//      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \+//      some.json5` for some reason the binary generates *TWO* `.profraw` files. One+//      named `default.profraw` and the other named `formatjson5.profraw` (the expected+//      name, in this case).+//+//   3. I think that if I eliminate regions within a function, their region_ids,+//      referenced in expressions, will be wrong? I think the ids are implied by their+//      array position in the final coverage map output (IIRC).+//+//   4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some+//      region start/end byte positions. Just like I couldn't get the function hash at+//      intrinsic codegen time for external crate functions, I think the SourceMap I+//      have here only applies to the local crate, and I know I have coverages that+//      reference external crates.+//+//          I still don't know if I fixed the hash problem correctly. If external crates+//          implement the function, can't I use the coverage counters already compiled+//          into those external crates? (Maybe not for generics and/or maybe not for

For generics you can have this problem with the generated code itself, too. Weak linkage is usually used so we only get one copy of each symbol in the final binary, and I suspect that may be useful here too.

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

-use rustc_data_structures::sync::Lrc;-use rustc_middle::mir;-use rustc_span::source_map::{Pos, SourceFile, SourceMap};-use rustc_span::{BytePos, FileName, RealFileName};+use rustc_middle::ty::Instance;+use rustc_middle::ty::TyCtxt;+use rustc_span::source_map::{Pos, SourceMap};+use rustc_span::{BytePos, FileName, Loc, RealFileName};  use std::cmp::{Ord, Ordering};-use std::collections::BTreeMap; use std::fmt; use std::path::PathBuf; +/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discriminators is important. #[derive(Copy, Clone, Debug)] #[repr(C)]-pub enum CounterOp {-    // Note the order (and therefore the default values) is important. With the attribute-    // `#[repr(C)]`, this enum matches the layout of the LLVM enum defined for the nested enum,-    // `llvm::coverage::CounterExpression::ExprKind`, as shown in the following source snippet:-    // https://github.com/rust-lang/llvm-project/blob/f208b70fbc4dee78067b3c5bd6cb92aa3ba58a1e/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146-    Subtract,-    Add,+enum CounterKind {+    Zero,+    CounterValueReference,+    Expression, } +/// Aligns to C++ struct llvm::coverage::Counter. Note that `id` has+/// different interpretations, depending on the `kind`:+///   * For `CounterKind::Zero`, `id` is assumed to be `0`+///   * For `CounterKind::CounterValueReference`,  `id` matches the `counter_id` of the injected+///     instrumentation counter (the `index` argument to the LLVM intrinsic `instrprof.increment()`)+///   * For `CounterKind::Expression`, `id` is the index into the array of counter expressions.+/// The order of fields is important. #[derive(Copy, Clone, Debug)]-pub enum CoverageKind {-    Counter,-    CounterExpression(u32, CounterOp, u32),-    Unreachable,+#[repr(C)]+pub struct Counter {+    kind: CounterKind,+    id: u32, } -#[derive(Clone, Debug)]-pub struct CoverageRegion {-    pub kind: CoverageKind,-    pub start_byte_pos: u32,-    pub end_byte_pos: u32,-}+impl Counter {+    pub fn zero() -> Self {+        Self { kind: CounterKind::Zero, id: 0 }+    } -impl CoverageRegion {-    pub fn source_loc(&self, source_map: &SourceMap) -> Option<(Lrc<SourceFile>, CoverageLoc)> {-        let (start_file, start_line, start_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.start_byte_pos));-        let (end_file, end_line, end_col) =-            lookup_file_line_col(source_map, BytePos::from_u32(self.end_byte_pos));-        let start_file_path = match &start_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => {-                bug!("start_file_path should be a RealFileName, but it was: {:?}", start_file.name)-            }-        };-        let end_file_path = match &end_file.name {-            FileName::Real(RealFileName::Named(path)) => path,-            _ => bug!("end_file_path should be a RealFileName, but it was: {:?}", end_file.name),-        };-        if start_file_path == end_file_path {-            Some((start_file, CoverageLoc { start_line, start_col, end_line, end_col }))-        } else {-            None-            // FIXME(richkadel): There seems to be a problem computing the file location in-            // some cases. I need to investigate this more. When I generate and show coverage-            // for the example binary in the crates.io crate `json5format`, I had a couple of-            // notable problems:-            //-            //   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in-            //      various comments (not corresponding to rustdoc code), indicating a possible-            //      problem with the byte_pos-to-source-map implementation.-            //-            //   2. And (perhaps not related) when I build the aforementioned example binary with:-            //      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`-            //      and then run that binary with-            //      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \-            //      some.json5` for some reason the binary generates *TWO* `.profraw` files. One-            //      named `default.profraw` and the other named `formatjson5.profraw` (the expected-            //      name, in this case).-            //-            // If the byte range conversion is wrong, fix it. But if it-            // is right, then it is possible for the start and end to be in different files.-            // Can I do something other than ignore coverages that span multiple files?-            //-            // If I can resolve this, remove the "Option<>" result type wrapper-            // `regions_in_file_order()` accordingly.-        }+    pub fn counter_value_reference(counter_id: u32) -> Self {+        Self { kind: CounterKind::CounterValueReference, id: counter_id }+    }++    pub fn expression(final_expression_index: u32) -> Self {+        Self { kind: CounterKind::Expression, id: final_expression_index }     } } -impl Default for CoverageRegion {-    fn default() -> Self {-        Self {-            // The default kind (Unreachable) is a placeholder that will be overwritten before-            // backend codegen.-            kind: CoverageKind::Unreachable,-            start_byte_pos: 0,-            end_byte_pos: 0,-        }+/// Aligns to C++ struct llvm::coverage::CounterExpression::ExprKind.+/// The order of discriminators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub enum ExprKind {+    Subtract,+    Add,+}++/// Aligns to C++ struct llvm::coverage::CounterExpression.+/// The order of fields is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub struct CounterExpression {+    // Note the field order is important.+    kind: ExprKind,+    lhs: Counter,+    rhs: Counter,+}++impl CounterExpression {+    pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self {+        Self { kind, lhs, rhs }     } } -/// A source code region used with coverage information.-#[derive(Debug, Eq, PartialEq)]-pub struct CoverageLoc {-    /// The (1-based) line number of the region start.-    pub start_line: u32,-    /// The (1-based) column number of the region start.-    pub start_col: u32,-    /// The (1-based) line number of the region end.-    pub end_line: u32,-    /// The (1-based) column number of the region end.-    pub end_col: u32,+#[derive(Clone, Debug)]+pub struct Region {+    start: Loc,+    end: Loc, } -impl Ord for CoverageLoc {+impl Ord for Region {     fn cmp(&self, other: &Self) -> Ordering {-        (self.start_line, &self.start_col, &self.end_line, &self.end_col).cmp(&(-            other.start_line,-            &other.start_col,-            &other.end_line,-            &other.end_col,-        ))+        (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col)+            .cmp(&(+                &other.start.file.name,+                &other.start.line,+                &other.start.col,+                &other.end.line,+                &other.end.col,+            ))     } } -impl PartialOrd for CoverageLoc {+impl PartialOrd for Region {     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {         Some(self.cmp(other))     } } -impl fmt::Display for CoverageLoc {+impl PartialEq for Region {+    fn eq(&self, other: &Self) -> bool {+        self.start.file.name == other.start.file.name+            && self.start.line == other.start.line+            && self.start.col == other.start.col+            && self.end.line == other.end.line+            && self.end.col == other.end.col+    }+}++impl Eq for Region {}++impl fmt::Display for Region {     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {-        // Customize debug format, and repeat the file name, so generated location strings are-        // "clickable" in many IDEs.-        write!(f, "{}:{} - {}:{}", self.start_line, self.start_col, self.end_line, self.end_col)+        let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end();+        write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col)     } } -fn lookup_file_line_col(source_map: &SourceMap, byte_pos: BytePos) -> (Lrc<SourceFile>, u32, u32) {-    let found = source_map-        .lookup_line(byte_pos)-        .expect("should find coverage region byte position in source");-    let file = found.sf;-    let line_pos = file.line_begin_pos(byte_pos);+impl Region {+    pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self {+        let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos));+        let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos));+        assert_eq!(start.file.name, end.file.name);+        Self { start, end }+    } -    // Use 1-based indexing.-    let line = (found.line + 1) as u32;-    let col = (byte_pos - line_pos).to_u32() + 1;+    pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) {+        let start = &self.start;+        let end = &self.end;+        match &start.file.name {+            FileName::Real(RealFileName::Named(path)) => (+                path,+                start.line as u32,+                start.col.to_u32() + 1,+                end.line as u32,+                end.col.to_u32() + 1,+            ),+            _ => {+                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)+            }+        }+    }+} -    (file, line, col)+#[derive(Clone, Debug)]+pub struct ExpressionRegion {+    lhs: u32,+    op: ExprKind,+    rhs: u32,+    region: Region, } +// FIXME(richkadel): There seems to be a problem computing the file location in+// some cases. I need to investigate this more. When I generate and show coverage+// for the example binary in the crates.io crate `json5format`, I had a couple of+// notable problems:+//+//   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in+//      various comments (not corresponding to rustdoc code), indicating a possible+//      problem with the byte_pos-to-source-map implementation.

Was this related to the spans in some terminators being weird, or was that something else?

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();         coverage_regions             .entry(instance)-            .or_insert_with(|| {-                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))-            })-            .add_unreachable(start_byte_pos, end_byte_pos);+            .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))+            .add_unreachable_region(start_byte_pos, end_byte_pos);     } } -/// This struct wraps an opaque reference to the C++ template instantiation of-/// `llvm::SmallVector<coverage::CounterExpression>`. Each `coverage::CounterExpression` object is-/// constructed from primative-typed arguments, and pushed to the `SmallVector`, in the C++-/// implementation of `LLVMRustCoverageSmallVectorCounterExpressionAdd()` (see-/// `src/rustllvm/CoverageMappingWrapper.cpp`).-pub struct SmallVectorCounterExpression<'a> {-    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterExpression<'a>,-}+/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discrimiators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+enum RegionKind {+    /// A CodeRegion associates some code with a counter+    CodeRegion, -impl SmallVectorCounterExpression<'a> {-    pub fn new() -> Self {-        SmallVectorCounterExpression {-            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterExpressionCreate() },-        }-    }+    /// An ExpansionRegion represents a file expansion region that associates+    /// a source range with the expansion of a virtual source file, such as+    /// for a macro instantiation or #include file.+    ExpansionRegion, -    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterExpression<'a> {-        self.raw-    }+    /// A SkippedRegion represents a source range with code that was skipped+    /// by a preprocessor or similar means.+    SkippedRegion, -    pub fn push_from(-        &mut self,-        kind: rustc_codegen_ssa::coverageinfo::CounterOp,-        left_index: u32,-        right_index: u32,-    ) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionAdd(-                &mut *(self.raw as *mut _),-                kind,-                left_index,-                right_index,-            )-        }-    }+    /// A GapRegion is like a CodeRegion, but its count is only set as the+    /// line execution count when its the only region in the line.+    GapRegion, } -impl Drop for SmallVectorCounterExpression<'a> {-    fn drop(&mut self) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionDispose(&mut *(self.raw as *mut _));-        }-    }-}+/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the+/// coverage map in accordance with LLVM's "Coverage Mapping Format". The struct composes fields+/// representing the `Counter` type and value(s) (injected counter ID, or expression type and+/// operands), the source file (an indirect index into a "filenames array", encoded separately),+/// and source location (start and end positions of the represented code region).+///+/// Aligns to C++ struct llvm::coverage::CounterMappingRegion.+/// The order of fields is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+pub struct CounterMappingRegion {+    /// The counter type and type-dependent counter data, if any.+    counter: Counter,++    /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the+    /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes that,+    /// in turn, are used to look up the filename for this region.+    file_id: u32, -/// This struct wraps an opaque reference to the C++ template instantiation of-/// `llvm::SmallVector<coverage::CounterMappingRegion>`. Each `coverage::CounterMappingRegion`-/// object is constructed from primative-typed arguments, and pushed to the `SmallVector`, in the-/// C++ implementation of `LLVMRustCoverageSmallVectorCounterMappingRegionAdd()` (see-/// `src/rustllvm/CoverageMappingWrapper.cpp`).-pub struct SmallVectorCounterMappingRegion<'a> {-    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterMappingRegion<'a>,+    /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find the+    /// mapping regions created as a result of macro expansion, by checking if their file id matches+    /// the expanded file id.+    expanded_file_id: u32,++    /// 1-based starting line of the mapping region.+    start_line: u32,++    /// 1-based starting column of the mapping region.+    start_col: u32,++    /// 1-based ending line of the mapping region.+    end_line: u32,++    /// 1-based ending column of the mapping region. If the high bit is set, the current mapping+    /// region is a gap area.+    end_col: u32,++    kind: RegionKind, } -impl SmallVectorCounterMappingRegion<'a> {-    pub fn new() -> Self {-        SmallVectorCounterMappingRegion {-            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterMappingRegionCreate() },+impl CounterMappingRegion {+    pub fn code_region(+        counter: Counter,+        file_id: u32,

Question: I'm wondering if we should be using newtype'd integers for some of these to prevent accidentally mixing them up.

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();         coverage_regions             .entry(instance)-            .or_insert_with(|| {-                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))-            })-            .add_unreachable(start_byte_pos, end_byte_pos);+            .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))+            .add_unreachable_region(start_byte_pos, end_byte_pos);     } } -/// This struct wraps an opaque reference to the C++ template instantiation of-/// `llvm::SmallVector<coverage::CounterExpression>`. Each `coverage::CounterExpression` object is-/// constructed from primative-typed arguments, and pushed to the `SmallVector`, in the C++-/// implementation of `LLVMRustCoverageSmallVectorCounterExpressionAdd()` (see-/// `src/rustllvm/CoverageMappingWrapper.cpp`).-pub struct SmallVectorCounterExpression<'a> {-    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterExpression<'a>,-}+/// Aligns to C++ struct llvm::coverage::Counter::CounterKind.+/// The order of discrimiators is important.+#[derive(Copy, Clone, Debug)]+#[repr(C)]+enum RegionKind {+    /// A CodeRegion associates some code with a counter+    CodeRegion, -impl SmallVectorCounterExpression<'a> {-    pub fn new() -> Self {-        SmallVectorCounterExpression {-            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterExpressionCreate() },-        }-    }+    /// An ExpansionRegion represents a file expansion region that associates+    /// a source range with the expansion of a virtual source file, such as+    /// for a macro instantiation or #include file.+    ExpansionRegion, -    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterExpression<'a> {-        self.raw-    }+    /// A SkippedRegion represents a source range with code that was skipped+    /// by a preprocessor or similar means.+    SkippedRegion, -    pub fn push_from(-        &mut self,-        kind: rustc_codegen_ssa::coverageinfo::CounterOp,-        left_index: u32,-        right_index: u32,-    ) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionAdd(-                &mut *(self.raw as *mut _),-                kind,-                left_index,-                right_index,-            )-        }-    }+    /// A GapRegion is like a CodeRegion, but its count is only set as the+    /// line execution count when its the only region in the line.+    GapRegion, } -impl Drop for SmallVectorCounterExpression<'a> {-    fn drop(&mut self) {-        unsafe {-            llvm::LLVMRustCoverageSmallVectorCounterExpressionDispose(&mut *(self.raw as *mut _));-        }-    }-}+/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the+/// coverage map in accordance with LLVM's "Coverage Mapping Format". The struct composes fields+/// representing the `Counter` type and value(s) (injected counter ID, or expression type and+/// operands), the source file (an indirect index into a "filenames array", encoded separately),+/// and source location (start and end positions of the represented code region).+///+/// Aligns to C++ struct llvm::coverage::CounterMappingRegion.

Is this layout documented? If it changes, how will we know?

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 use std::path::PathBuf; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {-    let mut coverage_writer = CoverageMappingWriter::new(cx);-     let function_coverage_map = cx.coverage_context().take_function_coverage_map();+    if function_coverage_map.len() == 0 {

nit: use is_empty() if that exists

richkadel

comment created time in 8 days

Pull request review commentrust-lang/rust

Fixed coverage map issues; better aligned with LLVM APIs

 use std::path::PathBuf; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {-    let mut coverage_writer = CoverageMappingWriter::new(cx);-     let function_coverage_map = cx.coverage_context().take_function_coverage_map();+    if function_coverage_map.len() == 0 {+        // This module has no functions with coverage instrumentation+        return;+    }++    let mut mapgen = CoverageMapGenerator::new();      // Encode coverage mappings and generate function records     let mut function_records = Vec::<&'ll llvm::Value>::new();     let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| {         for (instance, function_coverage) in function_coverage_map.into_iter() {-            if let Some(function_record) = coverage_writer.write_function_mappings_and_record(-                instance,-                function_coverage,-                coverage_mappings_buffer,-            ) {-                function_records.push(function_record);-            }+            debug!("Generate coverage map for: {:?}", instance);++            let mangled_function_name = cx.tcx.symbol_name(instance).to_string();+            let function_source_hash = function_coverage.source_hash();+            let (expressions, counter_regions) =+                function_coverage.get_expressions_and_counter_regions();++            let old_len = coverage_mappings_buffer.len();+            mapgen.write_coverage_mappings(expressions, counter_regions, coverage_mappings_buffer);+            let mapping_data_size = coverage_mappings_buffer.len() - old_len;+            debug_assert!(+                mapping_data_size > 0,+                "Every `FunctionCoverage` should have at least one counter"+            );++            let function_record = mapgen.make_function_record(+                cx,+                mangled_function_name,+                function_source_hash,+                mapping_data_size,+            );+            function_records.push(function_record);         }     }); -    // Encode all filenames covered in this module, ordered by `file_id`+    // Encode all filenames referenced by counters/expressions in this module     let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {-        coverageinfo::write_filenames_section_to_buffer(-            &coverage_writer.filenames,-            filenames_buffer,-        );+        coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);     }); -    if coverage_mappings_buffer.len() > 0 {-        // Generate the LLVM IR representation of the coverage map and store it in a well-known-        // global constant.-        coverage_writer.write_coverage_map(-            function_records,-            filenames_buffer,-            coverage_mappings_buffer,-        );-    }+    // Generate the LLVM IR representation of the coverage map and store it in a well-known global+    mapgen.save_generated_coverage_map(+        cx,+        function_records,+        filenames_buffer,+        coverage_mappings_buffer,+    ); } -struct CoverageMappingWriter<'a, 'll, 'tcx> {-    cx: &'a CodegenCx<'ll, 'tcx>,+struct CoverageMapGenerator {     filenames: Vec<CString>,     filename_to_index: FxHashMap<CString, u32>, } -impl<'a, 'll, 'tcx> CoverageMappingWriter<'a, 'll, 'tcx> {-    fn new(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {-        Self { cx, filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }+impl CoverageMapGenerator {+    fn new() -> Self {+        Self { filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }     } -    /// For the given function, get the coverage region data, stream it to the given buffer, and-    /// then generate and return a new function record.-    fn write_function_mappings_and_record(+    /// Using the `expressions` and `counter_regions` collected for the current function, generate+    /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use+    /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into+    /// the given `coverage_mappings` byte buffer, compliant with the LLVM Coverage Mapping format.+    fn write_coverage_mappings(         &mut self,-        instance: Instance<'tcx>,-        mut function_coverage: FunctionCoverage,+        expressions: Vec<CounterExpression>,+        counter_regions: impl Iterator<Item = (Counter, &'a Region)>,         coverage_mappings_buffer: &RustString,-    ) -> Option<&'ll llvm::Value> {-        let cx = self.cx;-        let coverageinfo: &mir::CoverageInfo = cx.tcx.coverageinfo(instance.def_id());-        debug!(-            "Generate coverage map for: {:?}, num_counters: {}, num_expressions: {}",-            instance, coverageinfo.num_counters, coverageinfo.num_expressions-        );-        debug_assert!(coverageinfo.num_counters > 0);--        let regions_in_file_order = function_coverage.regions_in_file_order(cx.sess().source_map());-        if regions_in_file_order.len() == 0 {-            return None;+    ) {+        let mut counter_regions = counter_regions.collect::<Vec<_>>();+        if counter_regions.len() == 0 {+            return;         } -        // Stream the coverage mapping regions for the function (`instance`) to the buffer, and-        // compute the data byte size used.-        let old_len = coverage_mappings_buffer.len();-        self.regions_to_mappings(regions_in_file_order, coverage_mappings_buffer);-        let mapping_data_size = coverage_mappings_buffer.len() - old_len;-        debug_assert!(mapping_data_size > 0);--        let mangled_function_name = cx.tcx.symbol_name(instance).to_string();-        let name_ref = coverageinfo::compute_hash(&mangled_function_name);-        let function_source_hash = function_coverage.source_hash();--        // Generate and return the function record-        let name_ref_val = cx.const_u64(name_ref);-        let mapping_data_size_val = cx.const_u32(mapping_data_size as u32);-        let func_hash_val = cx.const_u64(function_source_hash);-        Some(cx.const_struct(-            &[name_ref_val, mapping_data_size_val, func_hash_val],-            /*packed=*/ true,-        ))-    }--    /// For each coverage region, extract its coverage data from the earlier coverage analysis.-    /// Use LLVM APIs to convert the data into buffered bytes compliant with the LLVM Coverage-    /// Mapping format.-    fn regions_to_mappings(-        &mut self,-        regions_in_file_order: BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>>,-        coverage_mappings_buffer: &RustString,-    ) {         let mut virtual_file_mapping = Vec::new();-        let mut mapping_regions = coverageinfo::SmallVectorCounterMappingRegion::new();-        let mut expressions = coverageinfo::SmallVectorCounterExpression::new();--        for (file_id, (file_path, file_coverage_regions)) in-            regions_in_file_order.into_iter().enumerate()-        {-            let file_id = file_id as u32;-            let filename = CString::new(file_path.to_string_lossy().to_string())-                .expect("null error converting filename to C string");-            debug!("  file_id: {} = '{:?}'", file_id, filename);-            let filenames_index = match self.filename_to_index.get(&filename) {-                Some(index) => *index,-                None => {-                    let index = self.filenames.len() as u32;-                    self.filenames.push(filename.clone());-                    self.filename_to_index.insert(filename, index);-                    index+        let mut mapping_regions = Vec::new();+        let mut current_file_path = None;+        let mut current_file_id = 0;++        // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted+        // by filename and position. Capture any new files to compute the `CounterMappingRegion`s+        // `file_id` (indexing files referenced by the current function), and construct the+        // function-specific `virtual_file_mapping` from `file_id` to its index in the module's+        // `filenames` array.+        counter_regions.sort_by_key(|(_counter, region)| *region);

If you can use sort_unstable_by_key that'd be faster.

richkadel

comment created time in 8 days

pull request commentrust-lang/rust

Refactor librustdoc html backend

Looks like all comments have been addressed, so

@bors r+

P1n3appl3

comment created time in 8 days

push eventtmandry/trybuild

Tyler Mandry

commit sha 1a5990c464ace441be4eb2b0b59bb1315c93e0a1

Expose normalization API

view details

push time in 9 days

delete branch tmandry/rust

delete branch : issue-73818

delete time in 10 days

issue closedrust-lang/rust

`rustfmt` no longer builds after rust-lang/rust#74073

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust#74073, I observed that the tool rustfmt no longer builds. A follow-up PR to the repository https://github.com/rust-lang/rustfmt is needed to fix the fallout.

cc @Manishearth, do you think you would have time to do the follow-up work? If so, that would be great!

And nominating for compiler team prioritization.

closed time in 10 days

rust-highfive

pull request commentrust-lang/rust

Update rustfmt and rls

@bors r+ p=1

tmandry

comment created time in 10 days

PR opened rust-lang/rust

Update rustfmt and rls

Closes #74080, #74081.

+44 -43

0 comment

3 changed files

pr created time in 10 days

create barnchtmandry/rust

branch : roll

created branch time in 10 days

pull request commentrust-lang/rust

Normalize bounds fully when checking defaulted types

That worked!

Note that I now add the predicate unconditionally (removing the branch on is_final()) to avoid regressing an error message for a GAT outlives bound. Details are in the commit history.

tmandry

comment created time in 10 days

push eventtmandry/rust

Tyler Mandry

commit sha 31a3bb59ce42ae86e19c2e316d0809e8606c810f

Remove manual normalization in compare_projection_bounds

view details

Tyler Mandry

commit sha e35d2867f14a36094bdceadc731fdd1d26882fc9

Fix diagnostic by using predicate in GATs too

view details

push time in 10 days

delete branch rust-lang/rust

delete branch : issue-73818

delete time in 10 days

create barnchrust-lang/rust

branch : issue-73818

created branch time in 10 days

delete branch tmandry/rust

delete branch : issue-74047

delete time in 11 days

pull request commentrust-lang/rust

Normalize bounds fully when checking defaulted types

Friendly ping, can I get a review?

tmandry

comment created time in 12 days

pull request commentrust-lang/async-book

Fix typo in "async_trait"

Thanks!

nrc

comment created time in 12 days

push eventrust-lang/async-book

Nick Cameron

commit sha 2afebef7c04868da06ede47d316634c6cfded34d

Fix typo in "async_trait" The crate is async-trait. Also, removed the backticks, since it is a name, not a code snippet

view details

Tyler Mandry

commit sha 1d7355576ae54bc14738ec8045fa08bad5c61b96

Merge pull request #98 from rust-lang/nrc-patch-1 Fix typo in "async_trait"

view details

push time in 12 days

PR merged rust-lang/async-book

Fix typo in "async_trait"

The crate is async-trait. Also, removed the backticks, since it is a name, not a code snippet

+1 -1

0 comment

1 changed file

nrc

pr closed time in 12 days

pull request commentgitgitgadget/git

subtree: Fix handling of complex history

Friendly ping @tqc, is there anything we can do to help push this over the finish line?

tqc

comment created time in 12 days

issue commentrust-lang/rust

Replace submodules with subtrees

I'm really glad this effort is underway. On Fuchsia we try to roll to a new tip-of-tree rust compiler every few weeks, which helps with catching bugs. If we could we'd roll more often. But the main thing slowing us down is the constant state of toolstate breakage.

Some of this (like rustfmt) we can work around in practice by distributing separate versions, but it's a pain to set up and maintain. Some tools (like clippy and rls) really have to match the version of the compiler.

This seems like it would make toolstate breakage a thing of the past, which is why I'm very supportive of this effort and would be glad to help however I can.

oli-obk

comment created time in 12 days

delete branch tmandry/racer

delete branch : rustc-ap-670

delete time in 12 days

PR closed racer-rust/racer

Bump rustc-ap crates to 670

To fix rls and rustfmt again.

cc https://github.com/rust-lang/rust/issues/74081 https://github.com/rust-lang/rust/issues/74080 cc @topecongiro @Xanewok @calebcartwright

+98 -92

3 comments

2 changed files

tmandry

pr closed time in 12 days

pull request commentracer-rust/racer

Bump rustc-ap crates to 670

Sorry, I misunderstood the problem. I'll close this for now because I also want to get things green again.

If there's anything I can do to help with that, I'd be happy to :)

tmandry

comment created time in 12 days

pull request commentracer-rust/racer

Bump rustc-ap crates to 670

CI failure looks spurious (due to https://github.com/rust-lang/rustup/issues/2434). I ran a build locally and it succeeded.

tmandry

comment created time in 12 days

PR opened racer-rust/racer

Bump rustc-ap crates to 670

To fix rls and rustfmt again.

cc https://github.com/rust-lang/rust/issues/74081 https://github.com/rust-lang/rust/issues/74080 cc @topecongiro @Xanewok @calebcartwright

+98 -92

0 comment

2 changed files

pr created time in 12 days

create barnchtmandry/racer

branch : rustc-ap-670

created branch time in 12 days

fork tmandry/racer

Rust Code Completion utility

fork in 12 days

pull request commentrust-lang/rust

Fix ICE while building MIR with type errors

I would assume that the ICE tickets were closed with tests

Yep, they were!

tmandry

comment created time in 12 days

PR opened rust-lang/rust

Fix ICE while building MIR with type errors

See https://github.com/rust-lang/rust/issues/74047#issuecomment-663290913 for background. Replacing a binding with PatKind::Wild (introduced in #51789 and later refactored in #67439) caused an ICE downstream while building MIR.

I noticed that taking this code out no longer triggers the ICEs it was added to prevent. I'm not sure what else changed, or if this change is correct, but it does seem to be passing ui tests at least.

r? @oli-obk cc @estebank

Fixes #74047.

+29 -5

0 comment

3 changed files

pr created time in 12 days

create barnchtmandry/rust

branch : issue-74047

created branch time in 12 days

issue commentrust-lang/rust

ICE on improperly implemented TryFrom

I did some digging here. The source of the panic is here, during HAIR construction:

https://github.com/rust-lang/rust/blob/0820e54a8ad7795d7b555b37994f43cfe62356d4/src/librustc_mir_build/hair/pattern/mod.rs#L512-L515

In this case, the binding err below is of the error type (meaning type check for it failed). By replacing the binding with _ we prevent a local from being created for it, which means that when we try to generate code that reads the local we get a panic here.

pub async fn connect()
 ->
    /*impl Trait*/ ::std::future::from_generator(move |mut _task_context| {
        {
            let _t =
                {
                    let stream:
                            MyStream =
                        match ::std::ops::Try::into_result(OtherStream.try_into())
                            {
                            ::std::result::Result::Err(err) // `err` replaced with `_` here!
                            =>

                                #[allow(unreachable_code)]
                                return ::std::ops::Try::from_error(::std::convert::From::from(err)),
                            ::std::result::Result::Ok(val)
                            =>

                                #[allow(unreachable_code)]
                                val,
                        };
                    Ok(stream)
                };
            _t
        }
    })

I'm not sure what the correct fix is here. Replacing the binding with _ was done to prevent other ICEs, but we can't generate valid MIR without the local info.

More fundamentally: We're building MIR during typeck because this is an async fn. In the past we probably never would have gotten to this stage.

Backtrace: <details>

thread 'rustc' panicked at 'no entry found for key', src/librustc_mir_build/build/mod.rs:354:9
stack backtrace:
   0: std::backtrace_rs::backtrace::libunwind::trace
             at ./src/libstd/../backtrace/src/backtrace/libunwind.rs:96
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at ./src/libstd/../backtrace/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at ./src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at ./src/libstd/sys_common/backtrace.rs:58
   4: core::fmt::write
             at ./src/libcore/fmt/mod.rs:1117
   5: std::io::Write::write_fmt
             at ./src/libstd/io/mod.rs:1508
   6: std::sys_common::backtrace::_print
             at ./src/libstd/sys_common/backtrace.rs:61
   7: std::sys_common::backtrace::print
             at ./src/libstd/sys_common/backtrace.rs:48
   8: std::panicking::default_hook::{{closure}}
             at ./src/libstd/panicking.rs:198
   9: std::panicking::default_hook
             at ./src/libstd/panicking.rs:217
  10: <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call
             at ./src/liballoc/boxed.rs:1095
  11: rustc_driver::report_ice
             at ./src/librustc_driver/lib.rs:1158
  12: std::panicking::rust_panic_with_hook
             at ./src/libstd/panicking.rs:530
  13: rust_begin_unwind
             at ./src/libstd/panicking.rs:437
  14: core::panicking::panic_fmt
             at ./src/libcore/panicking.rs:85
  15: core::option::expect_failed
             at ./src/libcore/option.rs:1265
  16: core::option::Option<T>::expect
             at ./src/libcore/option.rs:347
  17: <std::collections::hash::map::HashMap<K,V,S> as core::ops::index::Index<&Q>>::index
             at ./src/libstd/collections/hash/map.rs:1004
  18: rustc_mir_build::build::Builder::var_local_id
             at ./src/librustc_mir_build/build/mod.rs:354
  19: rustc_mir_build::build::expr::as_place::<impl rustc_mir_build::build::Builder>::expr_as_place
             at ./src/librustc_mir_build/build/expr/as_place.rs:169
  20: rustc_mir_build::build::expr::as_place::<impl rustc_mir_build::build::Builder>::as_place_builder
             at ./src/librustc_mir_build/build/expr/as_place.rs:84
  21: rustc_mir_build::build::expr::as_place::<impl rustc_mir_build::build::Builder>::as_place
             at ./src/librustc_mir_build/build/expr/as_place.rs:73
  22: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:408
  23: <rustc_mir_build::hair::Expr as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:53
  24: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  25: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::expr_as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:112
  26: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp::{{closure}}
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  27: stacker::maybe_grow
             at /usr/local/google/home/tmandry/.cargo/registry/src/github.com-1ecc6299db9ec823/stacker-0.1.9/src/lib.rs:52
  28: rustc_data_structures::stack::ensure_sufficient_stack
             at ./src/librustc_data_structures/stack.rs:16
  29: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  30: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:143
  31: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:196
  32: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:116
  33: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand::{{closure}}
             at ./src/librustc_mir_build/build/expr/as_operand.rs:162
  34: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
  35: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:161
  36: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:116
  37: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_local_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:82
  38: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:200
  39: core::iter::adapters::map_fold::{{closure}}
             at ./src/libcore/iter/adapters/mod.rs:833
  40: core::iter::traits::iterator::Iterator::fold
             at ./src/libcore/iter/traits/iterator.rs:2003
  41: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
             at ./src/libcore/iter/adapters/mod.rs:873
  42: core::iter::traits::iterator::Iterator::for_each
             at ./src/libcore/iter/traits/iterator.rs:649
  43: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::spec_extend
             at ./src/liballoc/vec.rs:2140
  44: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
             at ./src/liballoc/vec.rs:2120
  45: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at ./src/liballoc/vec.rs:1995
  46: core::iter::traits::iterator::Iterator::collect
             at ./src/libcore/iter/traits/iterator.rs:1652
  47: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:198
  48: <rustc_mir_build::hair::Expr as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:53
  49: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  50: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::expr_as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:112
  51: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp::{{closure}}
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  52: stacker::maybe_grow
             at /usr/local/google/home/tmandry/.cargo/registry/src/github.com-1ecc6299db9ec823/stacker-0.1.9/src/lib.rs:52
  53: rustc_data_structures::stack::ensure_sufficient_stack
             at ./src/librustc_data_structures/stack.rs:16
  54: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  55: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:143
  56: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:196
  57: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:116
  58: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand::{{closure}}
             at ./src/librustc_mir_build/build/expr/as_operand.rs:162
  59: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
  60: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::expr_as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:161
  61: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:116
  62: rustc_mir_build::build::expr::as_operand::<impl rustc_mir_build::build::Builder>::as_local_call_operand
             at ./src/librustc_mir_build/build/expr/as_operand.rs:82
  63: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:200
  64: core::iter::adapters::map_fold::{{closure}}
             at ./src/libcore/iter/adapters/mod.rs:833
  65: core::iter::traits::iterator::Iterator::fold
             at ./src/libcore/iter/traits/iterator.rs:2003
  66: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
             at ./src/libcore/iter/adapters/mod.rs:873
  67: core::iter::traits::iterator::Iterator::for_each
             at ./src/libcore/iter/traits/iterator.rs:649
  68: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::spec_extend
             at ./src/liballoc/vec.rs:2140
  69: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
             at ./src/liballoc/vec.rs:2120
  70: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at ./src/liballoc/vec.rs:1995
  71: core::iter::traits::iterator::Iterator::collect
             at ./src/libcore/iter/traits/iterator.rs:1652
  72: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:198
  73: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
  74: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  75: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
  76: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
  77: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
  78: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
  79: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  80: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::break_scope
             at ./src/librustc_mir_build/build/scope.rs:523
  81: rustc_mir_build::build::expr::stmt::<impl rustc_mir_build::build::Builder>::stmt_expr
             at ./src/librustc_mir_build/build/expr/stmt.rs:97
  82: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:396
  83: <rustc_mir_build::hair::Expr as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:53
  84: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  85: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::expr_as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:112
  86: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp::{{closure}}
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  87: stacker::maybe_grow
             at /usr/local/google/home/tmandry/.cargo/registry/src/github.com-1ecc6299db9ec823/stacker-0.1.9/src/lib.rs:52
  88: rustc_data_structures::stack::ensure_sufficient_stack
             at ./src/librustc_data_structures/stack.rs:16
  89: rustc_mir_build::build::expr::as_temp::<impl rustc_mir_build::build::Builder>::as_temp
             at ./src/librustc_mir_build/build/expr/as_temp.rs:29
  90: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:63
  91: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
  92: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  93: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
  94: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
  95: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
  96: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
  97: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
  98: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
  99: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 100: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 101: <rustc_mir_build::hair::Expr as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:53
 102: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 103: rustc_mir_build::build::matches::<impl rustc_mir_build::build::Builder>::lower_match_arms::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/matches/mod.rs:260
 104: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 105: rustc_mir_build::build::matches::<impl rustc_mir_build::build::Builder>::lower_match_arms::{{closure}}
             at ./src/librustc_mir_build/build/matches/mod.rs:237
 106: core::iter::adapters::map_fold::{{closure}}
             at ./src/libcore/iter/adapters/mod.rs:833
 107: core::iter::traits::iterator::Iterator::fold
             at ./src/libcore/iter/traits/iterator.rs:2003
 108: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
             at ./src/libcore/iter/adapters/mod.rs:873
 109: core::iter::traits::iterator::Iterator::for_each
             at ./src/libcore/iter/traits/iterator.rs:649
 110: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::spec_extend
             at ./src/liballoc/vec.rs:2140
 111: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
             at ./src/liballoc/vec.rs:2120
 112: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at ./src/liballoc/vec.rs:1995
 113: core::iter::traits::iterator::Iterator::collect
             at ./src/libcore/iter/traits/iterator.rs:1652
 114: rustc_mir_build::build::matches::<impl rustc_mir_build::build::Builder>::lower_match_arms
             at ./src/librustc_mir_build/build/matches/mod.rs:230
 115: rustc_mir_build::build::matches::<impl rustc_mir_build::build::Builder>::match_expr
             at ./src/librustc_mir_build/build/matches/mod.rs:105
 116: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:52
 117: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 118: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 119: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 120: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 121: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 122: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 123: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 124: rustc_mir_build::build::matches::<impl rustc_mir_build::build::Builder>::expr_into_pattern
             at ./src/librustc_mir_build/build/matches/mod.rs:402
 125: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block_stmts::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:131
 126: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 127: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block_stmts::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:123
 128: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_opt_scope
             at ./src/librustc_mir_build/build/scope.rs:411
 129: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block_stmts
             at ./src/librustc_mir_build/build/block.rs:119
 130: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:40
 131: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 132: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:29
 133: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_opt_scope
             at ./src/librustc_mir_build/build/scope.rs:411
 134: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block
             at ./src/librustc_mir_build/build/block.rs:28
 135: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:49
 136: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 137: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 138: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 139: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 140: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 141: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 142: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 143: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 144: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 145: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 146: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 147: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 148: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:232
 149: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 150: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 151: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 152: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 153: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 154: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 155: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 156: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block_stmts
             at ./src/librustc_mir_build/build/block.rs:184
 157: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:40
 158: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 159: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block::{{closure}}
             at ./src/librustc_mir_build/build/block.rs:29
 160: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_opt_scope
             at ./src/librustc_mir_build/build/scope.rs:411
 161: rustc_mir_build::build::block::<impl rustc_mir_build::build::Builder>::ast_block
             at ./src/librustc_mir_build/build/block.rs:28
 162: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:49
 163: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 164: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 165: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 166: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 167: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 168: <rustc_mir_build::hair::ExprRef as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:42
 169: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 170: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr::{{closure}}
             at ./src/librustc_mir_build/build/expr/into.rs:46
 171: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 172: rustc_mir_build::build::expr::into::<impl rustc_mir_build::build::Builder>::into_expr
             at ./src/librustc_mir_build/build/expr/into.rs:46
 173: <rustc_mir_build::hair::Expr as rustc_mir_build::build::into::EvalInto>::eval_into
             at ./src/librustc_mir_build/build/into.rs:53
 174: rustc_mir_build::build::into::<impl rustc_mir_build::build::Builder>::into
             at ./src/librustc_mir_build/build/into.rs:30
 175: rustc_mir_build::build::Builder::args_and_body
             at ./src/librustc_mir_build/build/mod.rs:959
 176: rustc_mir_build::build::construct_fn::{{closure}}::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/mod.rs:621
 177: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 178: rustc_mir_build::build::construct_fn::{{closure}}::{{closure}}
             at ./src/librustc_mir_build/build/mod.rs:620
 179: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_breakable_scope
             at ./src/librustc_mir_build/build/scope.rs:392
 180: rustc_mir_build::build::construct_fn::{{closure}}
             at ./src/librustc_mir_build/build/mod.rs:615
 181: rustc_mir_build::build::scope::<impl rustc_mir_build::build::Builder>::in_scope
             at ./src/librustc_mir_build/build/scope.rs:455
 182: rustc_mir_build::build::construct_fn
             at ./src/librustc_mir_build/build/mod.rs:606
 183: rustc_mir_build::build::mir_build::{{closure}}
             at ./src/librustc_mir_build/build/mod.rs:163
 184: rustc_infer::infer::InferCtxtBuilder::enter
             at ./src/librustc_infer/infer/mod.rs:621
 185: rustc_mir_build::build::mir_build
             at ./src/librustc_mir_build/build/mod.rs:72
 186: rustc_mir_build::build::mir_built
             at ./src/librustc_mir_build/build/mod.rs:34
 187: rustc_middle::ty::query::<impl rustc_query_system::query::config::QueryAccessors<rustc_middle::ty::context::TyCtxt> for rustc_middle::ty::query::queries::mir_built>::compute
             at ./src/librustc_middle/ty/query/plumbing.rs:381
 188: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task_impl
             at ./src/librustc_query_system/dep_graph/graph.rs:303
 189: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task
             at ./src/librustc_query_system/dep_graph/graph.rs:200
 190: rustc_query_system::query::plumbing::force_query_with_job::{{closure}}::{{closure}}
             at ./src/librustc_query_system/query/plumbing.rs:599
 191: rustc_middle::ty::query::plumbing::<impl rustc_query_system::query::QueryContext for rustc_middle::ty::context::TyCtxt>::start_query::{{closure}}::{{closure}}::{{closure}}
             at ./src/librustc_middle/ty/query/plumbing.rs:72
 192: stacker::maybe_grow
             at /usr/local/google/home/tmandry/.cargo/registry/src/github.com-1ecc6299db9ec823/stacker-0.1.9/src/lib.rs:52
 193: rustc_data_structures::stack::ensure_sufficient_stack
             at ./src/librustc_data_structures/stack.rs:16
 194: rustc_middle::ty::query::plumbing::<impl rustc_query_system::query::QueryContext for rustc_middle::ty::context::TyCtxt>::start_query::{{closure}}::{{closure}}
             at ./src/librustc_middle/ty/query/plumbing.rs:72
 195: rustc_middle::ty::context::tls::enter_context::{{closure}}
             at ./src/librustc_middle/ty/context.rs:1721
 196: rustc_middle::ty::context::tls::set_tlv
             at ./src/librustc_middle/ty/context.rs:1705
 197: rustc_middle::ty::context::tls::enter_context
             at ./src/librustc_middle/ty/context.rs:1721
 198: rustc_middle::ty::query::plumbing::<impl rustc_query_system::query::QueryContext for rustc_middle::ty::context::TyCtxt>::start_query::{{closure}}
             at ./src/librustc_middle/ty/query/plumbing.rs:71
 199: rustc_middle::ty::context::tls::with_related_context::{{closure}}
             at ./src/librustc_middle/ty/context.rs:1809
 200: rustc_middle::ty::context::tls::with_context::{{closure}}
             at ./src/librustc_middle/ty/context.rs:1793
 201: rustc_middle::ty::context::tls::with_context_opt
             at ./src/librustc_middle/ty/context.rs:1782
 202: rustc_middle::ty::context::tls::with_context
             at ./src/librustc_middle/ty/context.rs:1793
 203: rustc_middle::ty::context::tls::with_related_context
             at ./src/librustc_middle/ty/context.rs:1806
 204: rustc_middle::ty::query::plumbing::<impl rustc_query_system::query::QueryContext for rustc_middle::ty::context::TyCtxt>::start_query
             at ./src/librustc_middle/ty/query/plumbing.rs:60
 205: rustc_query_system::query::plumbing::force_query_with_job::{{closure}}
             at ./src/librustc_query_system/query/plumbing.rs:589
 206: rustc_query_system::query::plumbing::with_diagnostics
             at ./src/librustc_query_system/query/plumbing.rs:296
 207: rustc_query_system::query::plumbing::force_query_with_job
             at ./src/librustc_query_system/query/plumbing.rs:588
 208: rustc_query_system::query::plumbing::try_execute_query
             at ./src/librustc_query_system/query/plumbing.rs:415
 209: rustc_query_system::query::plumbing::get_query_impl::{{closure}}
             at ./src/librustc_query_system/query/plumbing.rs:639
 210: <rustc_query_system::query::caches::DefaultCache<K,V> as rustc_query_system::query::caches::QueryCache>::lookup
             at ./src/librustc_query_system/query/caches.rs:111
 211: rustc_query_system::query::plumbing::try_get_cached
             at ./src/librustc_query_system/query/plumbing.rs:369
 212: rustc_query_system::query::plumbing::get_query_impl
             at ./src/librustc_query_system/query/plumbing.rs:631
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.47.0-dev running on x86_64-unknown-linux-gnu

note: compiler flags: --crate-type lib

query stack during panic:
#0 [mir_built] building MIR for `connect::{{closure}}#0`
#1 [unsafety_check_result] unsafety-checking `connect::{{closure}}#0`
#2 [unsafety_check_result] unsafety-checking `connect`
#3 [mir_const] processing MIR for `connect`
#4 [mir_validated] processing `connect`
#5 [mir_borrowck] borrow-checking `connect`
#6 [type_of] computing type of `connect::{{opaque}}#0`
#7 [check_mod_item_types] checking item types in top-level module
#8 [analysis] running analysis passes on this crate
end of query stack

</details>

sbosnick

comment created time in 12 days

PR opened rust-lang/rust

Normalize bounds fully when checking defaulted types

When checking <T as X>::Y in this example:

trait X { type Y: PartialEq<<Self as X>::Y> }
impl X for T { default type Y = S; }

We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case we want <T as X>::Y to normalize to S. This is valid because we are checking the default value specifically here. Add <T as X>::Y = S to the ParamEnv for normalization only.

Fixes #73818.


I noticed that adding this to the env for bounds checking didn't break any tests. Not sure if this is because we can't rely on it to prove anything, or because of missing test coverage.

r? @matthewjasper, @nikomatsakis

+58 -3

0 comment

2 changed files

pr created time in 13 days

create barnchtmandry/rust

branch : issue-73818

created branch time in 13 days

issue commentrust-lang/rust

Regression in associated type checking for default impls

It looks like the problem stems from the bound predicate not being normalized properly when checking the defaulted associated type. From my reproducer above:

compare_projection_bounds: normalized predicate =
    Binder(TraitPredicate(<Never as std::cmp::PartialEq<<T as Foo>::Assoc>>))

which should instead be <Never as std::cmp::PartialEq<Never>>.

I'm not certain yet how this ought to be implemented. Perhaps a pass after normalization that looks for occurrences of the defaulted type (<T as Foo>::Assoc in this case) and replaces it with the defaulted type. Seems simple enough, in theory :) But maybe there are cases I'm not thinking of.

anvil777

comment created time in 14 days

issue commentrust-lang/rust

`rustfmt` no longer builds after rust-lang/rust#74073

Thanks for working on that and for clarifying! I figured there was probably a secondary issue here.

I guess the toolstate site only sees nightlies so that's why it thinks it's been red since the 5th and never opened a new issue 🤔

rust-highfive

comment created time in 14 days

IssuesEvent

issue commentrust-lang/rust

`rustfmt` no longer builds after rust-lang/rust#74073

Reopening: rustfmt still appears to be broken

rust-highfive

comment created time in 14 days

IssuesEvent

issue commentrust-lang/rust

`rls` no longer builds after rust-lang/rust#74073

The build appears to be broken still. I'm seeing the following failure:

error[E0635]: unknown feature `const_transmute`
  --> /home/swarming/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc-ap-rustc_ast-664.0.0/lib.rs:13:12
   |
13 | #![feature(const_transmute)]
   |            ^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0635`.
error: could not compile `rustc-ap-rustc_ast`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed
command did not execute successfully: "/b/s/w/ir/k/recipe_cleanup/rustLjFjLE/build/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-Zbinary-dep-depinfo" "-j" "32" "--release" "--manifest-path" "/b/s/w/ir/k/rust/src/tools/rls/Cargo.toml" "--features" "clippy, rustc-workspace-hack/all-static" "--message-format" "json-render-diagnostics"
expected success, got: exit code: 101
thread 'main' panicked at 'Unable to build RLS', src/bootstrap/dist.rs:66:9
rust-highfive

comment created time in 14 days

pull request commentrust-lang/wg-async-foundations

Draft RFC to add a `must_not_await` lint

I don't think the yielding from the sync mutex creates that much of a problem though. I thought the yield is mostly a hint to the scheduler.

I think @betamos is referring to the contended case where your thread sleeps until the mutex is unlocked again. In that case the cost is high (and all progress on async tasks stops on your thread, of course).

This is because the cost of creating the waker is a bit more expensive. (There may be opportunity here to investigate and make it faster).

I agree there probably is; you should only need to create the waker in a contended case, in which case it should be less expensive than a futex.

LucioFranco

comment created time in 15 days

pull request commentrust-lang/wg-async-foundations

Draft RFC to add a `must_not_await` lint

I have yet to see a use-case for this, beyond "you should just use an async awaire one".

Even async-aware mutexes can deadlock if you hold their guard across an await, no?

In any case I think @betamos has identified another possible failure mode: locking a non-async-aware mutex anywhere in an async context (even if you don't hold its guard across an await). I think this is something we want to warn against, but mechanistically it works differently from what's being proposed in this RFC draft.

If we do, in fact, want both of these, we should decide how we'd name the attributes to reduce confusion.

LucioFranco

comment created time in 15 days

pull request commentrust-lang/rfcs

RFC: Add JSON backend to Rustdoc

I've been working with @P1n3appl3 on this and have to say that I've been very impressed with how much attention to detail they put into it. This is definitely one of the most well-documented RFCs I've seen, which of course is fitting for a rustdoc RFC :)

P1n3appl3

comment created time in 15 days

pull request commentrust-lang/rust

Refactor librustdoc html backend

Perhaps another person on @rust-lang/rustdoc can give this a once-over. I nominate...

r? @Manishearth

P1n3appl3

comment created time in 18 days

pull request commentrust-lang/rust

Generating the coverage map

@bors r+

I'll remove if there are more failures, but comfortable doing this for now.

richkadel

comment created time in 19 days

Pull request review commentrust-lang/async-book

Added FuturesUnordered chapter

+# `FuturesUnordered`++The `FuturesUnordered` struct is a set of futures which may be completed in any order.++```rust,edition2018,ignore+{{#include ../../examples/06_05_futuresunordered/src/lib.rs:simple}}+```++Because `FuturesUnordered` implements the `Stream` trait using `.next()` +on it will return a `Future` which returns the return value from one of+the futures inside of an `Option`.+It will return `None` when all futures are completed.

I think this could be even more concise, something like

`FuturesUnordered` implements a `Stream` trait over the
output of the futures in any order.

The example implies how to use that Stream (and hopefully we have dedicated docs for that too).

capnhawkbill

comment created time in 19 days

pull request commentrust-lang/wg-async-foundations

Draft RFC to add a deny await lint

Do people have any opinions on calling this #[deny_await]? It feels short enough but conveys the correct message.

deny is already an attribute that takes a parameter, which would make it confusing to explain when talking aloud. I think someone pointed out above that you might be left with things like #[allow(deny_await)], which isn't the end of the world but can contribute to the confusion.

Another point of confusion is that it sounds like the thing you're trying to avoid is awaiting the object itself, instead of holding the object across an await point.

Still, I haven't seen a name that I really like yet, and this is short enough and gets the point across pretty well.

Other ideas:

  • #[must_not_await] (to go along with #[must_use])
  • #[lint_on_await]
  • #[never_suspend]
LucioFranco

comment created time in 19 days

Pull request review commentrust-lang/wg-async-foundations

Update stream rfc

 the current task to be re-awoken when the data is ready. ```rust // Defined in std::stream module pub trait Stream {+    // Core items:     type Item;-         fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;     +    // Optional optimization hint, just like with iterators:     #[inline]     fn size_hint(&self) -> (usize, Option<usize>) {         (0, None)     }++    // Convenience methods (covered later on in the RFC):+    fn next(&mut self) -> Next<'_, Self>+    where+        Self: Unpin;

Just to make your third idea more concrete, for my own sake:

trait PinIterator {
  type Item;
  fn next(self: Pin<&mut Self>) -> Self::Item;
  // combinators can go here (duplicating Iterator for the most part)
}
impl<I: PinIterator, P: Deref<Target = I> + DerefMut> Iterator for Pin<P> {
  type Item = <I as PinIterator>::Item;
  fn next(&mut self) -> Self::Item { self.as_mut().next() }
}

// this would be nice.. but would lead to name resolution ambiguity for our combinators 😬 
default impl<T: Iterator> PinIterator for T { .. }
nellshamrell

comment created time in 19 days

pull request commentrust-lang/rust

Stabilize the Wake trait

Looks good to me!

r? @dtolnay for libs team FCP

yoshuawuyts

comment created time in 20 days

pull request commentrust-lang/rust

Generating the coverage map

@bors r+ rollup=never

richkadel

comment created time in 20 days

push eventtmandry/trybuild

Tyler Mandry

commit sha 3e4efe516490502a2cb8aea1d5d83c7b2674e80a

Add Strategy API

view details

Tyler Mandry

commit sha 4baf5ed71996275b26f7943db4336257699bc7a9

normalize: Support emtpy context strings

view details

push time in 20 days

push eventtmandry/trybuild

Tyler Mandry

commit sha 2e65ed859072764a4520269e5a6e8ebd2a45dc4a

Add Strategy API

view details

Tyler Mandry

commit sha 8917cf33d8ffd3f685a33bea65f23834056fa2c1

normalize: Support emtpy context strings

view details

push time in 20 days

Pull request review commentrust-lang/rust

Generating the coverage map

 impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {         args: &Vec<Operand<'tcx>>,         caller_instance: ty::Instance<'tcx>,     ) -> bool {-        match intrinsic {-            "count_code_region" => {-                use coverage::count_code_region_args::*;-                self.add_counter_region(-                    caller_instance,-                    op_to_u32(&args[COUNTER_INDEX]),-                    op_to_u32(&args[START_BYTE_POS]),-                    op_to_u32(&args[END_BYTE_POS]),-                );-                true // Also inject the counter increment in the backend-            }-            "coverage_counter_add" | "coverage_counter_subtract" => {-                use coverage::coverage_counter_expression_args::*;-                self.add_counter_expression_region(-                    caller_instance,-                    op_to_u32(&args[COUNTER_EXPRESSION_INDEX]),-                    op_to_u32(&args[LEFT_INDEX]),-                    if intrinsic == "coverage_counter_add" {-                        CounterOp::Add-                    } else {-                        CounterOp::Subtract-                    },-                    op_to_u32(&args[RIGHT_INDEX]),-                    op_to_u32(&args[START_BYTE_POS]),-                    op_to_u32(&args[END_BYTE_POS]),-                );-                false // Does not inject backend code-            }-            "coverage_unreachable" => {-                use coverage::coverage_unreachable_args::*;-                self.add_unreachable_region(-                    caller_instance,-                    op_to_u32(&args[START_BYTE_POS]),-                    op_to_u32(&args[END_BYTE_POS]),-                );-                false // Does not inject backend code+        if !self.tcx.sess.opts.debugging_opts.instrument_coverage {

Yeah, a bit. I think what was most confusing was the return value.

richkadel

comment created time in 20 days

pull request commentrust-lang/rust

Generating the coverage map

@bors try

richkadel

comment created time in 21 days

pull request commentrust-lang/rust

Generating the coverage map

In the meantime, can't hurt to

@bors try

richkadel

comment created time in 21 days

pull request commentrust-lang/rust

Generating the coverage map

@richkadel Whoops, I did manage to reproduce the segfault on my windows box. I had forgotten to checkout after fetching the source 😬

Here's a screenshot showing the exception and a backtrace. The program as written has finished by this point . MSVC didn't know how to find the sources in these frames so there wasn't any other information really.

Annotation 2020-07-14 214141

richkadel

comment created time in 21 days

issue commentrust-lang/rust

Tests using resume_unwind fail with -Cpanic=abort and -Zpanic_abort_tests

panic=abort changes the semantics of your program, so that's expected in some cases.

I think that'd be reasonable, but as far as I know there isn't a conditional compilation flag for panic behavior (I believe there's an issue for this floating around somewhere). In Fuchsia we manually added a --cfg flag for it to our build. I'd support an effort to add a standard one.

davidhewitt

comment created time in 21 days

pull request commentrust-lang/rust

Generating the coverage map

I think the most reliable thing would be to write a structured diff tool in python or something (or use an existing one).

Good suggestion. I think the current approach, using the --summary-only flag is going to work and should be reliable, BUT if you don't like this and want something more in line with a structured diff, I would suggest just extending the current prettify_json.py tool I bundled with the test to support the specific output schema, sort each array myself, and then dump the prettified JSON again, but with reliable sorting.

That's obviously a bit more work, but I'm willing if that's preferred.

Ah I think I misunderstood originally, what you have should indeed be reliable. I'm fine keeping it this way then.

richkadel

comment created time in 21 days

Pull request review commentrust-lang/rust

Generating the coverage map

+//! Demangles rustc mangled names.

No preference from me, really.

richkadel

comment created time in 21 days

Pull request review commentrust-lang/rust

Generating the coverage map

 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {         end_byte_pos: u32,     ) {         debug!(-            "adding unreachable code to coverage map: instance={:?}, byte range {}..{}",+            "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}",             instance, start_byte_pos, end_byte_pos,         );-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();-        coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos);+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();+        coverage_regions+            .entry(instance)+            .or_insert_with(|| {+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))+            })+            .add_unreachable(start_byte_pos, end_byte_pos);+    }+}++pub struct SmallVectorCounterExpression<'a> {

Could you add a doc comment explaining what this is for?

richkadel

comment created time in 21 days

Pull request review commentrust-lang/rust

Generating the coverage map

 pub fn build_session_options(matches: &getopts::Matches) -> Options {         );     } +    if debugging_opts.instrument_coverage {+        if cg.profile_generate.enabled() || cg.profile_use.is_some() {+            early_error(+                error_format,+                "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \+                or `-C profile-generate`",+            );+        }++        // `-Z instrument-coverage implies:+        //   * `-Z symbol-mangling-version=v0` - to ensure consistent and reversable name mangling

It would still be usable without this, just not as nice, right?

richkadel

comment created time in 21 days

Pull request review commentrust-lang/rust

Generating the coverage map

 fn common_inputs_stamp(config: &Config) -> Stamp {         stamp.add_path(&rustdoc_path);         stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));     }+    // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the+    // stamp here as well?

I think you might want to add your python script in here somewhere. Compiled dependencies seem to be handled spearately.

richkadel

comment created time in 21 days

Pull request review commentrust-lang/rust

Generating the coverage map

 fn validate_commandline_args_with_session_available(sess: &Session) {         && sess.panic_strategy() == PanicStrategy::Unwind         && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs)     {+        // FIXME(richkadel): Discover if tcx.sess.opts.debugging_opts.instrument_coverage+        // might also "not yet work in conjuction with `-Cpanic=unwind` on Windows when targeting+        // MSVC". If so, add it to the `if` condition above.

Flagging this so we don't forget

richkadel

comment created time in 21 days

more