Auto merge of #65422 - tmandry:rollup-r5u3mlc, r=tmandry
Rollup of 10 pull requests Successful merges: - #65170 (rustc_metadata: Privatize private code and remove dead code) - #65260 (Optimize `LexicalResolve::expansion`.) - #65261 (Remove `Option` from `TokenStream`) - #65332 (std::fmt: reorder docs) - #65340 (Several changes to the codegen backend organization) - #65365 (Include const generic arguments in metadata) - #65398 (Bring attention to suggestions when the only difference is capitalization) - #65410 (syntax: add parser recovery for intersection- / and-patterns `p1 @ p2`) - #65415 (Remove an outdated test output file) - #65416 (Minor sync changes) Failed merges: r? @ghost
This commit is contained in:
commit
e369d87b01
98 changed files with 1149 additions and 1099 deletions
|
@ -80,250 +80,6 @@
|
|||
//! arguments which have names. Like with positional parameters, it is not
|
||||
//! valid to provide named parameters that are unused by the format string.
|
||||
//!
|
||||
//! ## Argument types
|
||||
//!
|
||||
//! Each argument's type is dictated by the format string.
|
||||
//! There are various parameters which require a particular type, however.
|
||||
//! An example is the `{:.*}` syntax, which sets the number of decimal places
|
||||
//! in floating-point types:
|
||||
//!
|
||||
//! ```
|
||||
//! let formatted_number = format!("{:.*}", 2, 1.234567);
|
||||
//!
|
||||
//! assert_eq!("1.23", formatted_number)
|
||||
//! ```
|
||||
//!
|
||||
//! If this syntax is used, then the number of characters to print precedes the
|
||||
//! actual object being formatted, and the number of characters must have the
|
||||
//! type [`usize`].
|
||||
//!
|
||||
//! ## Formatting traits
|
||||
//!
|
||||
//! When requesting that an argument be formatted with a particular type, you
|
||||
//! are actually requesting that an argument ascribes to a particular trait.
|
||||
//! This allows multiple actual types to be formatted via `{:x}` (like [`i8`] as
|
||||
//! well as [`isize`]). The current mapping of types to traits is:
|
||||
//!
|
||||
//! * *nothing* ⇒ [`Display`]
|
||||
//! * `?` ⇒ [`Debug`]
|
||||
//! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers
|
||||
//! * `X?` ⇒ [`Debug`] with upper-case hexadecimal integers
|
||||
//! * `o` ⇒ [`Octal`](trait.Octal.html)
|
||||
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
|
||||
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
|
||||
//! * `p` ⇒ [`Pointer`](trait.Pointer.html)
|
||||
//! * `b` ⇒ [`Binary`]
|
||||
//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html)
|
||||
//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html)
|
||||
//!
|
||||
//! What this means is that any type of argument which implements the
|
||||
//! [`fmt::Binary`][`Binary`] trait can then be formatted with `{:b}`. Implementations
|
||||
//! are provided for these traits for a number of primitive types by the
|
||||
//! standard library as well. If no format is specified (as in `{}` or `{:6}`),
|
||||
//! then the format trait used is the [`Display`] trait.
|
||||
//!
|
||||
//! When implementing a format trait for your own type, you will have to
|
||||
//! implement a method of the signature:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(dead_code)]
|
||||
//! # use std::fmt;
|
||||
//! # struct Foo; // our custom type
|
||||
//! # impl fmt::Display for Foo {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! # write!(f, "testing, testing")
|
||||
//! # } }
|
||||
//! ```
|
||||
//!
|
||||
//! Your type will be passed as `self` by-reference, and then the function
|
||||
//! should emit output into the `f.buf` stream. It is up to each format trait
|
||||
//! implementation to correctly adhere to the requested formatting parameters.
|
||||
//! The values of these parameters will be listed in the fields of the
|
||||
//! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also
|
||||
//! provides some helper methods.
|
||||
//!
|
||||
//! Additionally, the return value of this function is [`fmt::Result`] which is a
|
||||
//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
|
||||
//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
|
||||
//! calling [`write!`]). However, they should never return errors spuriously. That
|
||||
//! is, a formatting implementation must and may only return an error if the
|
||||
//! passed-in [`Formatter`] returns an error. This is because, contrary to what
|
||||
//! the function signature might suggest, string formatting is an infallible
|
||||
//! operation. This function only returns a result because writing to the
|
||||
//! underlying stream might fail and it must provide a way to propagate the fact
|
||||
//! that an error has occurred back up the stack.
|
||||
//!
|
||||
//! An example of implementing the formatting traits would look
|
||||
//! like:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::fmt;
|
||||
//!
|
||||
//! #[derive(Debug)]
|
||||
//! struct Vector2D {
|
||||
//! x: isize,
|
||||
//! y: isize,
|
||||
//! }
|
||||
//!
|
||||
//! impl fmt::Display for Vector2D {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! // The `f` value implements the `Write` trait, which is what the
|
||||
//! // write! macro is expecting. Note that this formatting ignores the
|
||||
//! // various flags provided to format strings.
|
||||
//! write!(f, "({}, {})", self.x, self.y)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Different traits allow different forms of output of a type. The meaning
|
||||
//! // of this format is to print the magnitude of a vector.
|
||||
//! impl fmt::Binary for Vector2D {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! let magnitude = (self.x * self.x + self.y * self.y) as f64;
|
||||
//! let magnitude = magnitude.sqrt();
|
||||
//!
|
||||
//! // Respect the formatting flags by using the helper method
|
||||
//! // `pad_integral` on the Formatter object. See the method
|
||||
//! // documentation for details, and the function `pad` can be used
|
||||
//! // to pad strings.
|
||||
//! let decimals = f.precision().unwrap_or(3);
|
||||
//! let string = format!("{:.*}", decimals, magnitude);
|
||||
//! f.pad_integral(true, "", &string)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let myvector = Vector2D { x: 3, y: 4 };
|
||||
//!
|
||||
//! println!("{}", myvector); // => "(3, 4)"
|
||||
//! println!("{:?}", myvector); // => "Vector2D {x: 3, y:4}"
|
||||
//! println!("{:10.3b}", myvector); // => " 5.000"
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### `fmt::Display` vs `fmt::Debug`
|
||||
//!
|
||||
//! These two formatting traits have distinct purposes:
|
||||
//!
|
||||
//! - [`fmt::Display`][`Display`] implementations assert that the type can be faithfully
|
||||
//! represented as a UTF-8 string at all times. It is **not** expected that
|
||||
//! all types implement the [`Display`] trait.
|
||||
//! - [`fmt::Debug`][`Debug`] implementations should be implemented for **all** public types.
|
||||
//! Output will typically represent the internal state as faithfully as possible.
|
||||
//! The purpose of the [`Debug`] trait is to facilitate debugging Rust code. In
|
||||
//! most cases, using `#[derive(Debug)]` is sufficient and recommended.
|
||||
//!
|
||||
//! Some examples of the output from both traits:
|
||||
//!
|
||||
//! ```
|
||||
//! assert_eq!(format!("{} {:?}", 3, 4), "3 4");
|
||||
//! assert_eq!(format!("{} {:?}", 'a', 'b'), "a 'b'");
|
||||
//! assert_eq!(format!("{} {:?}", "foo\n", "bar\n"), "foo\n \"bar\\n\"");
|
||||
//! ```
|
||||
//!
|
||||
//! ## Related macros
|
||||
//!
|
||||
//! There are a number of related macros in the [`format!`] family. The ones that
|
||||
//! are currently implemented are:
|
||||
//!
|
||||
//! ```ignore (only-for-syntax-highlight)
|
||||
//! format! // described above
|
||||
//! write! // first argument is a &mut io::Write, the destination
|
||||
//! writeln! // same as write but appends a newline
|
||||
//! print! // the format string is printed to the standard output
|
||||
//! println! // same as print but appends a newline
|
||||
//! eprint! // the format string is printed to the standard error
|
||||
//! eprintln! // same as eprint but appends a newline
|
||||
//! format_args! // described below.
|
||||
//! ```
|
||||
//!
|
||||
//! ### `write!`
|
||||
//!
|
||||
//! This and [`writeln!`] are two macros which are used to emit the format string
|
||||
//! to a specified stream. This is used to prevent intermediate allocations of
|
||||
//! format strings and instead directly write the output. Under the hood, this
|
||||
//! function is actually invoking the [`write_fmt`] function defined on the
|
||||
//! [`std::io::Write`] trait. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::io::Write;
|
||||
//! let mut w = Vec::new();
|
||||
//! write!(&mut w, "Hello {}!", "world");
|
||||
//! ```
|
||||
//!
|
||||
//! ### `print!`
|
||||
//!
|
||||
//! This and [`println!`] emit their output to stdout. Similarly to the [`write!`]
|
||||
//! macro, the goal of these macros is to avoid intermediate allocations when
|
||||
//! printing output. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! print!("Hello {}!", "world");
|
||||
//! println!("I have a newline {}", "character at the end");
|
||||
//! ```
|
||||
//! ### `eprint!`
|
||||
//!
|
||||
//! The [`eprint!`] and [`eprintln!`] macros are identical to
|
||||
//! [`print!`] and [`println!`], respectively, except they emit their
|
||||
//! output to stderr.
|
||||
//!
|
||||
//! ### `format_args!`
|
||||
//!
|
||||
//! This is a curious macro which is used to safely pass around
|
||||
//! an opaque object describing the format string. This object
|
||||
//! does not require any heap allocations to create, and it only
|
||||
//! references information on the stack. Under the hood, all of
|
||||
//! the related macros are implemented in terms of this. First
|
||||
//! off, some example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::fmt;
|
||||
//! use std::io::{self, Write};
|
||||
//!
|
||||
//! let mut some_writer = io::stdout();
|
||||
//! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro"));
|
||||
//!
|
||||
//! fn my_fmt_fn(args: fmt::Arguments) {
|
||||
//! write!(&mut io::stdout(), "{}", args);
|
||||
//! }
|
||||
//! my_fmt_fn(format_args!(", or a {} too", "function"));
|
||||
//! ```
|
||||
//!
|
||||
//! The result of the [`format_args!`] macro is a value of type [`fmt::Arguments`].
|
||||
//! This structure can then be passed to the [`write`] and [`format`] functions
|
||||
//! inside this module in order to process the format string.
|
||||
//! The goal of this macro is to even further prevent intermediate allocations
|
||||
//! when dealing formatting strings.
|
||||
//!
|
||||
//! For example, a logging library could use the standard formatting syntax, but
|
||||
//! it would internally pass around this structure until it has been determined
|
||||
//! where output should go to.
|
||||
//!
|
||||
//! # Syntax
|
||||
//!
|
||||
//! The syntax for the formatting language used is drawn from other languages,
|
||||
//! so it should not be too alien. Arguments are formatted with Python-like
|
||||
//! syntax, meaning that arguments are surrounded by `{}` instead of the C-like
|
||||
//! `%`. The actual grammar for the formatting syntax is:
|
||||
//!
|
||||
//! ```text
|
||||
//! format_string := <text> [ maybe-format <text> ] *
|
||||
//! maybe-format := '{' '{' | '}' '}' | <format>
|
||||
//! format := '{' [ argument ] [ ':' format_spec ] '}'
|
||||
//! argument := integer | identifier
|
||||
//!
|
||||
//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
|
||||
//! fill := character
|
||||
//! align := '<' | '^' | '>'
|
||||
//! sign := '+' | '-'
|
||||
//! width := count
|
||||
//! precision := count | '*'
|
||||
//! type := identifier | '?' | ''
|
||||
//! count := parameter | integer
|
||||
//! parameter := argument '$'
|
||||
//! ```
|
||||
//!
|
||||
//! # Formatting Parameters
|
||||
//!
|
||||
//! Each argument being formatted can be transformed by a number of formatting
|
||||
|
@ -479,6 +235,234 @@
|
|||
//! them with the same character. For example, the `{` character is escaped with
|
||||
//! `{{` and the `}` character is escaped with `}}`.
|
||||
//!
|
||||
//! # Syntax
|
||||
//!
|
||||
//! To summarize, you can find the full grammar of format strings.
|
||||
//! The syntax for the formatting language used is drawn from other languages,
|
||||
//! so it should not be too alien. Arguments are formatted with Python-like
|
||||
//! syntax, meaning that arguments are surrounded by `{}` instead of the C-like
|
||||
//! `%`. The actual grammar for the formatting syntax is:
|
||||
//!
|
||||
//! ```text
|
||||
//! format_string := <text> [ maybe-format <text> ] *
|
||||
//! maybe-format := '{' '{' | '}' '}' | <format>
|
||||
//! format := '{' [ argument ] [ ':' format_spec ] '}'
|
||||
//! argument := integer | identifier
|
||||
//!
|
||||
//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
|
||||
//! fill := character
|
||||
//! align := '<' | '^' | '>'
|
||||
//! sign := '+' | '-'
|
||||
//! width := count
|
||||
//! precision := count | '*'
|
||||
//! type := identifier | '?' | ''
|
||||
//! count := parameter | integer
|
||||
//! parameter := argument '$'
|
||||
//! ```
|
||||
//!
|
||||
//! # Formatting traits
|
||||
//!
|
||||
//! When requesting that an argument be formatted with a particular type, you
|
||||
//! are actually requesting that an argument ascribes to a particular trait.
|
||||
//! This allows multiple actual types to be formatted via `{:x}` (like [`i8`] as
|
||||
//! well as [`isize`]). The current mapping of types to traits is:
|
||||
//!
|
||||
//! * *nothing* ⇒ [`Display`]
|
||||
//! * `?` ⇒ [`Debug`]
|
||||
//! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers
|
||||
//! * `X?` ⇒ [`Debug`] with upper-case hexadecimal integers
|
||||
//! * `o` ⇒ [`Octal`](trait.Octal.html)
|
||||
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
|
||||
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
|
||||
//! * `p` ⇒ [`Pointer`](trait.Pointer.html)
|
||||
//! * `b` ⇒ [`Binary`]
|
||||
//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html)
|
||||
//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html)
|
||||
//!
|
||||
//! What this means is that any type of argument which implements the
|
||||
//! [`fmt::Binary`][`Binary`] trait can then be formatted with `{:b}`. Implementations
|
||||
//! are provided for these traits for a number of primitive types by the
|
||||
//! standard library as well. If no format is specified (as in `{}` or `{:6}`),
|
||||
//! then the format trait used is the [`Display`] trait.
|
||||
//!
|
||||
//! When implementing a format trait for your own type, you will have to
|
||||
//! implement a method of the signature:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(dead_code)]
|
||||
//! # use std::fmt;
|
||||
//! # struct Foo; // our custom type
|
||||
//! # impl fmt::Display for Foo {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! # write!(f, "testing, testing")
|
||||
//! # } }
|
||||
//! ```
|
||||
//!
|
||||
//! Your type will be passed as `self` by-reference, and then the function
|
||||
//! should emit output into the `f.buf` stream. It is up to each format trait
|
||||
//! implementation to correctly adhere to the requested formatting parameters.
|
||||
//! The values of these parameters will be listed in the fields of the
|
||||
//! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also
|
||||
//! provides some helper methods.
|
||||
//!
|
||||
//! Additionally, the return value of this function is [`fmt::Result`] which is a
|
||||
//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
|
||||
//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
|
||||
//! calling [`write!`]). However, they should never return errors spuriously. That
|
||||
//! is, a formatting implementation must and may only return an error if the
|
||||
//! passed-in [`Formatter`] returns an error. This is because, contrary to what
|
||||
//! the function signature might suggest, string formatting is an infallible
|
||||
//! operation. This function only returns a result because writing to the
|
||||
//! underlying stream might fail and it must provide a way to propagate the fact
|
||||
//! that an error has occurred back up the stack.
|
||||
//!
|
||||
//! An example of implementing the formatting traits would look
|
||||
//! like:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::fmt;
|
||||
//!
|
||||
//! #[derive(Debug)]
|
||||
//! struct Vector2D {
|
||||
//! x: isize,
|
||||
//! y: isize,
|
||||
//! }
|
||||
//!
|
||||
//! impl fmt::Display for Vector2D {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! // The `f` value implements the `Write` trait, which is what the
|
||||
//! // write! macro is expecting. Note that this formatting ignores the
|
||||
//! // various flags provided to format strings.
|
||||
//! write!(f, "({}, {})", self.x, self.y)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Different traits allow different forms of output of a type. The meaning
|
||||
//! // of this format is to print the magnitude of a vector.
|
||||
//! impl fmt::Binary for Vector2D {
|
||||
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! let magnitude = (self.x * self.x + self.y * self.y) as f64;
|
||||
//! let magnitude = magnitude.sqrt();
|
||||
//!
|
||||
//! // Respect the formatting flags by using the helper method
|
||||
//! // `pad_integral` on the Formatter object. See the method
|
||||
//! // documentation for details, and the function `pad` can be used
|
||||
//! // to pad strings.
|
||||
//! let decimals = f.precision().unwrap_or(3);
|
||||
//! let string = format!("{:.*}", decimals, magnitude);
|
||||
//! f.pad_integral(true, "", &string)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let myvector = Vector2D { x: 3, y: 4 };
|
||||
//!
|
||||
//! println!("{}", myvector); // => "(3, 4)"
|
||||
//! println!("{:?}", myvector); // => "Vector2D {x: 3, y:4}"
|
||||
//! println!("{:10.3b}", myvector); // => " 5.000"
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### `fmt::Display` vs `fmt::Debug`
|
||||
//!
|
||||
//! These two formatting traits have distinct purposes:
|
||||
//!
|
||||
//! - [`fmt::Display`][`Display`] implementations assert that the type can be faithfully
|
||||
//! represented as a UTF-8 string at all times. It is **not** expected that
|
||||
//! all types implement the [`Display`] trait.
|
||||
//! - [`fmt::Debug`][`Debug`] implementations should be implemented for **all** public types.
|
||||
//! Output will typically represent the internal state as faithfully as possible.
|
||||
//! The purpose of the [`Debug`] trait is to facilitate debugging Rust code. In
|
||||
//! most cases, using `#[derive(Debug)]` is sufficient and recommended.
|
||||
//!
|
||||
//! Some examples of the output from both traits:
|
||||
//!
|
||||
//! ```
|
||||
//! assert_eq!(format!("{} {:?}", 3, 4), "3 4");
|
||||
//! assert_eq!(format!("{} {:?}", 'a', 'b'), "a 'b'");
|
||||
//! assert_eq!(format!("{} {:?}", "foo\n", "bar\n"), "foo\n \"bar\\n\"");
|
||||
//! ```
|
||||
//!
|
||||
//! # Related macros
|
||||
//!
|
||||
//! There are a number of related macros in the [`format!`] family. The ones that
|
||||
//! are currently implemented are:
|
||||
//!
|
||||
//! ```ignore (only-for-syntax-highlight)
|
||||
//! format! // described above
|
||||
//! write! // first argument is a &mut io::Write, the destination
|
||||
//! writeln! // same as write but appends a newline
|
||||
//! print! // the format string is printed to the standard output
|
||||
//! println! // same as print but appends a newline
|
||||
//! eprint! // the format string is printed to the standard error
|
||||
//! eprintln! // same as eprint but appends a newline
|
||||
//! format_args! // described below.
|
||||
//! ```
|
||||
//!
|
||||
//! ### `write!`
|
||||
//!
|
||||
//! This and [`writeln!`] are two macros which are used to emit the format string
|
||||
//! to a specified stream. This is used to prevent intermediate allocations of
|
||||
//! format strings and instead directly write the output. Under the hood, this
|
||||
//! function is actually invoking the [`write_fmt`] function defined on the
|
||||
//! [`std::io::Write`] trait. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::io::Write;
|
||||
//! let mut w = Vec::new();
|
||||
//! write!(&mut w, "Hello {}!", "world");
|
||||
//! ```
|
||||
//!
|
||||
//! ### `print!`
|
||||
//!
|
||||
//! This and [`println!`] emit their output to stdout. Similarly to the [`write!`]
|
||||
//! macro, the goal of these macros is to avoid intermediate allocations when
|
||||
//! printing output. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! print!("Hello {}!", "world");
|
||||
//! println!("I have a newline {}", "character at the end");
|
||||
//! ```
|
||||
//! ### `eprint!`
|
||||
//!
|
||||
//! The [`eprint!`] and [`eprintln!`] macros are identical to
|
||||
//! [`print!`] and [`println!`], respectively, except they emit their
|
||||
//! output to stderr.
|
||||
//!
|
||||
//! ### `format_args!`
|
||||
//!
|
||||
//! This is a curious macro which is used to safely pass around
|
||||
//! an opaque object describing the format string. This object
|
||||
//! does not require any heap allocations to create, and it only
|
||||
//! references information on the stack. Under the hood, all of
|
||||
//! the related macros are implemented in terms of this. First
|
||||
//! off, some example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::fmt;
|
||||
//! use std::io::{self, Write};
|
||||
//!
|
||||
//! let mut some_writer = io::stdout();
|
||||
//! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro"));
|
||||
//!
|
||||
//! fn my_fmt_fn(args: fmt::Arguments) {
|
||||
//! write!(&mut io::stdout(), "{}", args);
|
||||
//! }
|
||||
//! my_fmt_fn(format_args!(", or a {} too", "function"));
|
||||
//! ```
|
||||
//!
|
||||
//! The result of the [`format_args!`] macro is a value of type [`fmt::Arguments`].
|
||||
//! This structure can then be passed to the [`write`] and [`format`] functions
|
||||
//! inside this module in order to process the format string.
|
||||
//! The goal of this macro is to even further prevent intermediate allocations
|
||||
//! when dealing formatting strings.
|
||||
//!
|
||||
//! For example, a logging library could use the standard formatting syntax, but
|
||||
//! it would internally pass around this structure until it has been determined
|
||||
//! where output should go to.
|
||||
//!
|
||||
//! [`usize`]: ../../std/primitive.usize.html
|
||||
//! [`isize`]: ../../std/primitive.isize.html
|
||||
//! [`i8`]: ../../std/primitive.i8.html
|
||||
|
|
|
@ -304,7 +304,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
|
||||
self.iterate_until_fixed_point("Expansion", |constraint| {
|
||||
self.iterate_until_fixed_point(|constraint| {
|
||||
debug!("expansion: constraint={:?}", constraint);
|
||||
let (a_region, b_vid, b_data, retain) = match *constraint {
|
||||
Constraint::RegSubVar(a_region, b_vid) => {
|
||||
|
@ -360,13 +360,21 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
// Identical scopes can show up quite often, if the fixed point
|
||||
// iteration converges slowly, skip them
|
||||
// iteration converges slowly. Skip them. This is purely an
|
||||
// optimization.
|
||||
if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
|
||||
if a_scope == cur_scope {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a specialized version of the `lub_concrete_regions`
|
||||
// check below for a common case, here purely as an
|
||||
// optimization.
|
||||
if let ReEmpty = a_region {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
if lub == cur_region {
|
||||
return false;
|
||||
|
@ -407,8 +415,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
/// Returns the smallest region `c` such that `a <= c` and `b <= c`.
|
||||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
match (a, b) {
|
||||
(&ty::ReClosureBound(..), _)
|
||||
| (_, &ty::ReClosureBound(..))
|
||||
|
@ -468,7 +474,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
// otherwise, we don't know what the free region is,
|
||||
// so we must conservatively say the LUB is static:
|
||||
tcx.lifetimes.re_static
|
||||
self.tcx().lifetimes.re_static
|
||||
}
|
||||
|
||||
(&ReScope(a_id), &ReScope(b_id)) => {
|
||||
|
@ -476,7 +482,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// subtype of the region corresponding to an inner
|
||||
// block.
|
||||
let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id);
|
||||
tcx.mk_region(ReScope(lub))
|
||||
self.tcx().mk_region(ReScope(lub))
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_))
|
||||
|
@ -490,7 +496,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
if a == b {
|
||||
a
|
||||
} else {
|
||||
tcx.lifetimes.re_static
|
||||
self.tcx().lifetimes.re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -860,7 +866,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
|
||||
fn iterate_until_fixed_point<F>(&self, mut body: F)
|
||||
where
|
||||
F: FnMut(&Constraint<'tcx>) -> (bool, bool),
|
||||
{
|
||||
|
@ -870,7 +876,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
while changed {
|
||||
changed = false;
|
||||
iteration += 1;
|
||||
debug!("---- {} Iteration {}{}", "#", tag, iteration);
|
||||
debug!("---- Expansion iteration {}", iteration);
|
||||
constraints.retain(|constraint| {
|
||||
let (edge_changed, retain) = body(constraint);
|
||||
if edge_changed {
|
||||
|
@ -880,7 +886,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
retain
|
||||
});
|
||||
}
|
||||
debug!("---- {} Complete after {} iteration(s)", tag, iteration);
|
||||
debug!("---- Expansion complete after {} iteration(s)", iteration);
|
||||
}
|
||||
|
||||
fn bound_is_met(
|
||||
|
|
|
@ -32,6 +32,12 @@ pub struct CrateSource {
|
|||
pub rmeta: Option<(PathBuf, PathKind)>,
|
||||
}
|
||||
|
||||
impl CrateSource {
|
||||
pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {
|
||||
self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Copy, Clone,
|
||||
Ord, PartialOrd, Eq, PartialEq, Debug, HashStable)]
|
||||
pub enum DepKind {
|
||||
|
@ -208,7 +214,6 @@ pub trait CrateStore {
|
|||
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
|
||||
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
|
||||
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
|
||||
fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
|
||||
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
|
||||
fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use syntax::feature_gate::UnstableFeatures;
|
|||
use syntax::source_map::SourceMap;
|
||||
|
||||
use errors::emitter::HumanReadableErrorType;
|
||||
use errors::{ColorConfig, FatalError, Handler};
|
||||
use errors::{ColorConfig, FatalError, Handler, SourceMapperDyn};
|
||||
|
||||
use getopts;
|
||||
|
||||
|
@ -1857,6 +1857,7 @@ struct NullEmitter;
|
|||
|
||||
impl errors::emitter::Emitter for NullEmitter {
|
||||
fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {}
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None }
|
||||
}
|
||||
|
||||
// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
|
||||
|
|
|
@ -43,7 +43,7 @@ use crate::ty::subst::{UserSubsts, GenericArgKind};
|
|||
use crate::ty::{BoundVar, BindingMode};
|
||||
use crate::ty::CanonicalPolyFnSig;
|
||||
use crate::util::common::ErrorReported;
|
||||
use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet};
|
||||
use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet, NodeMap};
|
||||
use crate::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use crate::util::profiling::SelfProfilerRef;
|
||||
|
||||
|
@ -1051,6 +1051,9 @@ pub struct GlobalCtxt<'tcx> {
|
|||
/// Common consts, pre-interned for your convenience.
|
||||
pub consts: CommonConsts<'tcx>,
|
||||
|
||||
/// Resolutions of `extern crate` items produced by resolver.
|
||||
extern_crate_map: NodeMap<CrateNum>,
|
||||
|
||||
/// Map indicating what traits are in scope for places where this
|
||||
/// is relevant; generated by resolve.
|
||||
trait_map: FxHashMap<DefIndex,
|
||||
|
@ -1274,6 +1277,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
types: common_types,
|
||||
lifetimes: common_lifetimes,
|
||||
consts: common_consts,
|
||||
extern_crate_map: resolutions.extern_crate_map,
|
||||
trait_map,
|
||||
export_map: resolutions.export_map.into_iter().map(|(k, v)| {
|
||||
let exports: Vec<_> = v.into_iter().map(|e| {
|
||||
|
@ -2951,7 +2955,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
|||
};
|
||||
providers.extern_mod_stmt_cnum = |tcx, id| {
|
||||
let id = tcx.hir().as_local_node_id(id).unwrap();
|
||||
tcx.cstore.extern_mod_stmt_cnum_untracked(id)
|
||||
tcx.extern_crate_map.get(&id).cloned()
|
||||
};
|
||||
providers.all_crate_nums = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
|
|
@ -28,7 +28,7 @@ use crate::ty::subst::{Subst, InternalSubsts, SubstsRef};
|
|||
use crate::ty::util::{IntTypeExt, Discr};
|
||||
use crate::ty::walk::TypeWalker;
|
||||
use crate::util::captures::Captures;
|
||||
use crate::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
|
||||
use crate::util::nodemap::{NodeMap, NodeSet, DefIdMap, FxHashMap};
|
||||
use arena::SyncDroplessArena;
|
||||
use crate::session::DataTypeKind;
|
||||
|
||||
|
@ -121,6 +121,7 @@ mod sty;
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Resolutions {
|
||||
pub extern_crate_map: NodeMap<CrateNum>,
|
||||
pub trait_map: TraitMap,
|
||||
pub maybe_unused_trait_imports: NodeSet,
|
||||
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
|
||||
|
|
|
@ -52,6 +52,7 @@ const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr();
|
|||
|
||||
impl BackendTypes for Builder<'_, 'll, 'tcx> {
|
||||
type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
|
||||
type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function;
|
||||
type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
|
||||
type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type;
|
||||
type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
|
||||
|
|
|
@ -33,7 +33,7 @@ pub fn get_fn(
|
|||
assert!(!instance.substs.has_param_types());
|
||||
|
||||
let sig = instance.fn_sig(cx.tcx());
|
||||
if let Some(&llfn) = cx.instances().borrow().get(&instance) {
|
||||
if let Some(&llfn) = cx.instances.borrow().get(&instance) {
|
||||
return llfn;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
//! Code that is useful in various codegen modules.
|
||||
|
||||
use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef};
|
||||
use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef, ConstantInt};
|
||||
use crate::abi;
|
||||
use crate::consts;
|
||||
use crate::type_::Type;
|
||||
|
@ -86,6 +86,8 @@ impl Funclet<'ll> {
|
|||
|
||||
impl BackendTypes for CodegenCx<'ll, 'tcx> {
|
||||
type Value = &'ll Value;
|
||||
type Function = &'ll Value;
|
||||
|
||||
type BasicBlock = &'ll BasicBlock;
|
||||
type Type = &'ll Type;
|
||||
type Funclet = Funclet<'ll>;
|
||||
|
@ -243,33 +245,23 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
struct_in_context(self.llcx, elts, packed)
|
||||
}
|
||||
|
||||
fn const_to_uint(&self, v: &'ll Value) -> u64 {
|
||||
unsafe {
|
||||
fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
|
||||
try_as_const_integral(v).map(|v| unsafe {
|
||||
llvm::LLVMConstIntGetZExtValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_const_integral(&self, v: &'ll Value) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsAConstantInt(v).is_some()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
|
||||
unsafe {
|
||||
if self.is_const_integral(v) {
|
||||
let (mut lo, mut hi) = (0u64, 0u64);
|
||||
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
|
||||
&mut hi, &mut lo);
|
||||
if success {
|
||||
Some(hi_lo_to_u128(lo, hi))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
try_as_const_integral(v).and_then(|v| unsafe {
|
||||
let (mut lo, mut hi) = (0u64, 0u64);
|
||||
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
|
||||
&mut hi, &mut lo);
|
||||
if success {
|
||||
Some(hi_lo_to_u128(lo, hi))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn scalar_to_backend(
|
||||
|
@ -305,7 +297,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
Some(GlobalAlloc::Function(fn_instance)) => {
|
||||
self.get_fn(fn_instance)
|
||||
self.get_fn_addr(fn_instance)
|
||||
}
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
|
@ -386,3 +378,9 @@ pub fn struct_in_context(
|
|||
fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
|
||||
((hi as u128) << 64) | (lo as u128)
|
||||
}
|
||||
|
||||
fn try_as_const_integral(v: &'ll Value) -> Option<&'ll ConstantInt> {
|
||||
unsafe {
|
||||
llvm::LLVMIsAConstantInt(v)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ use rustc::ty::layout::{
|
|||
use rustc::ty::{self, Ty, TyCtxt, Instance};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_target::spec::{HasTargetSpec, Target};
|
||||
use rustc_codegen_ssa::callee::resolve_and_get_fn;
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use crate::callee::get_fn;
|
||||
|
||||
|
@ -327,11 +326,11 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
&self.vtables
|
||||
}
|
||||
|
||||
fn instances(&self) -> &RefCell<FxHashMap<Instance<'tcx>, &'ll Value>> {
|
||||
&self.instances
|
||||
fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value {
|
||||
get_fn(self, instance)
|
||||
}
|
||||
|
||||
fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value {
|
||||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value {
|
||||
get_fn(self, instance)
|
||||
}
|
||||
|
||||
|
@ -362,7 +361,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let tcx = self.tcx;
|
||||
let llfn = match tcx.lang_items().eh_personality() {
|
||||
Some(def_id) if !wants_msvc_seh(self.sess()) => {
|
||||
resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]))
|
||||
self.get_fn_addr(
|
||||
ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
tcx.intern_substs(&[]),
|
||||
).unwrap()
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let name = if wants_msvc_seh(self.sess()) {
|
||||
|
@ -390,7 +396,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
let tcx = self.tcx;
|
||||
assert!(self.sess().target.target.options.custom_unwind_resume);
|
||||
if let Some(def_id) = tcx.lang_items().eh_unwind_resume() {
|
||||
let llfn = resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]));
|
||||
let llfn = self.get_fn_addr(
|
||||
ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
tcx.intern_substs(&[]),
|
||||
).unwrap()
|
||||
);
|
||||
unwresume.set(Some(llfn));
|
||||
return llfn;
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
register_diagnostics! {
|
||||
|
||||
E0511: r##"
|
||||
Invalid monomorphization of an intrinsic function was used. Erroneous code
|
||||
example:
|
||||
|
||||
```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
|
||||
#![feature(platform_intrinsics)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe { simd_add(0, 1); }
|
||||
// error: invalid monomorphization of `simd_add` intrinsic
|
||||
}
|
||||
```
|
||||
|
||||
The generic type has to be a SIMD type. Example:
|
||||
|
||||
```
|
||||
#![feature(repr_simd)]
|
||||
#![feature(platform_intrinsics)]
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
|
||||
unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
|
@ -20,9 +20,9 @@ use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
|||
use rustc::hir;
|
||||
use syntax::ast::{self, FloatTy};
|
||||
|
||||
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
||||
use rustc::session::Session;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
@ -1026,10 +1026,6 @@ fn get_rust_try_fn<'ll, 'tcx>(
|
|||
rust_try
|
||||
}
|
||||
|
||||
fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
|
||||
span_err!(a, b, E0511, "{}", c);
|
||||
}
|
||||
|
||||
fn generic_simd_intrinsic(
|
||||
bx: &mut Builder<'a, 'll, 'tcx>,
|
||||
name: &str,
|
||||
|
|
|
@ -38,7 +38,7 @@ extern crate rustc_fs_util;
|
|||
extern crate rustc_driver as _;
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc_errors as errors;
|
||||
|
||||
|
@ -64,8 +64,6 @@ use rustc::util::common::ErrorReported;
|
|||
use rustc_codegen_ssa::ModuleCodegen;
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
|
||||
mod error_codes;
|
||||
|
||||
mod back {
|
||||
pub mod archive;
|
||||
pub mod bytecode;
|
||||
|
@ -258,10 +256,6 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
llvm_util::print_version();
|
||||
}
|
||||
|
||||
fn diagnostics(&self) -> &[(&'static str, &'static str)] {
|
||||
&error_codes::DIAGNOSTICS
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session) -> Vec<Symbol> {
|
||||
target_features(sess)
|
||||
}
|
||||
|
@ -271,15 +265,10 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
}
|
||||
|
||||
fn provide(&self, providers: &mut ty::query::Providers<'_>) {
|
||||
rustc_codegen_utils::symbol_names::provide(providers);
|
||||
rustc_codegen_ssa::back::symbol_export::provide(providers);
|
||||
rustc_codegen_ssa::base::provide_both(providers);
|
||||
attributes::provide(providers);
|
||||
}
|
||||
|
||||
fn provide_extern(&self, providers: &mut ty::query::Providers<'_>) {
|
||||
rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
|
||||
rustc_codegen_ssa::base::provide_both(providers);
|
||||
attributes::provide_extern(providers);
|
||||
}
|
||||
|
||||
|
|
|
@ -510,6 +510,7 @@ extern { pub type Module; }
|
|||
extern { pub type Context; }
|
||||
extern { pub type Type; }
|
||||
extern { pub type Value; }
|
||||
extern { pub type ConstantInt; }
|
||||
extern { pub type Metadata; }
|
||||
extern { pub type BasicBlock; }
|
||||
#[repr(C)]
|
||||
|
@ -719,8 +720,8 @@ extern "C" {
|
|||
pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
|
||||
pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value;
|
||||
pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
|
||||
pub fn LLVMConstIntGetZExtValue(ConstantVal: &Value) -> c_ulonglong;
|
||||
pub fn LLVMRustConstInt128Get(ConstantVal: &Value, SExt: bool,
|
||||
pub fn LLVMConstIntGetZExtValue(ConstantVal: &ConstantInt) -> c_ulonglong;
|
||||
pub fn LLVMRustConstInt128Get(ConstantVal: &ConstantInt, SExt: bool,
|
||||
high: &mut u64, low: &mut u64) -> bool;
|
||||
|
||||
|
||||
|
@ -1666,7 +1667,7 @@ extern "C" {
|
|||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
|
||||
|
||||
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&Value>;
|
||||
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
|
||||
|
||||
pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
|
||||
pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
|
||||
|
|
|
@ -84,7 +84,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
{
|
||||
fn new_block<'b>(
|
||||
cx: &'a Self::CodegenCx,
|
||||
llfn: Self::Value,
|
||||
llfn: Self::Function,
|
||||
name: &'b str
|
||||
) -> Self;
|
||||
/* ... */
|
||||
|
|
|
@ -22,7 +22,8 @@ use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry};
|
|||
use rustc::util::profiling::SelfProfilerRef;
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_errors::{Handler, Level, FatalError, DiagnosticId};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Handler, Level, FatalError, DiagnosticId, SourceMapperDyn};
|
||||
use rustc_errors::emitter::{Emitter};
|
||||
use rustc_target::spec::MergeFunctions;
|
||||
use syntax::attr;
|
||||
|
@ -1681,6 +1682,9 @@ impl Emitter for SharedEmitter {
|
|||
}
|
||||
drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
|
||||
}
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl SharedEmitterMain {
|
||||
|
|
|
@ -36,7 +36,6 @@ use crate::mir::place::PlaceRef;
|
|||
use crate::back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm,
|
||||
submit_post_lto_module_to_llvm};
|
||||
use crate::{MemFlags, CrateInfo};
|
||||
use crate::callee;
|
||||
use crate::common::{RealPredicate, TypeKind, IntPredicate};
|
||||
use crate::meth;
|
||||
use crate::mir;
|
||||
|
@ -377,8 +376,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let sig = instance.fn_sig(cx.tcx());
|
||||
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
|
||||
|
||||
let lldecl = cx.instances().borrow().get(&instance).cloned().unwrap_or_else(||
|
||||
bug!("Instance `{:?}` not already declared", instance));
|
||||
let lldecl = cx.get_fn(instance);
|
||||
|
||||
let mir = cx.tcx().instance_mir(instance.def);
|
||||
mir::codegen_mir::<Bx>(cx, lldecl, &mir, instance, sig);
|
||||
|
@ -400,7 +398,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
|
|||
return;
|
||||
}
|
||||
|
||||
let main_llfn = cx.get_fn(instance);
|
||||
let main_llfn = cx.get_fn_addr(instance);
|
||||
|
||||
let et = cx.tcx().entry_fn(LOCAL_CRATE).map(|e| e.1);
|
||||
match et {
|
||||
|
@ -455,10 +453,13 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
|
|||
|
||||
let (start_fn, args) = if use_start_lang_item {
|
||||
let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None);
|
||||
let start_fn = callee::resolve_and_get_fn(
|
||||
cx,
|
||||
start_def_id,
|
||||
cx.tcx().intern_substs(&[main_ret_ty.into()]),
|
||||
let start_fn = cx.get_fn_addr(
|
||||
ty::Instance::resolve(
|
||||
cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
start_def_id,
|
||||
cx.tcx().intern_substs(&[main_ret_ty.into()]),
|
||||
).unwrap()
|
||||
);
|
||||
(start_fn, vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())),
|
||||
arg_argc, arg_argv])
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
use crate::traits::*;
|
||||
use rustc::ty;
|
||||
use rustc::ty::subst::SubstsRef;
|
||||
use rustc::hir::def_id::DefId;
|
||||
|
||||
pub fn resolve_and_get_fn<'tcx, Cx: CodegenMethods<'tcx>>(
|
||||
cx: &Cx,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Cx::Value {
|
||||
cx.get_fn(
|
||||
ty::Instance::resolve(
|
||||
cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs
|
||||
).unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_and_get_fn_for_ptr<'tcx,
|
||||
Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx>
|
||||
>(
|
||||
cx: &Cx,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Cx::Value {
|
||||
cx.get_fn(
|
||||
ty::Instance::resolve_for_fn_ptr(
|
||||
cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs
|
||||
).unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_and_get_fn_for_vtable<'tcx,
|
||||
Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx>
|
||||
>(
|
||||
cx: &Cx,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Cx::Value {
|
||||
cx.get_fn(
|
||||
ty::Instance::resolve_for_vtable(
|
||||
cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs
|
||||
).unwrap()
|
||||
)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(non_camel_case_types, non_snake_case)]
|
||||
|
||||
use rustc::ty::{Ty, TyCtxt};
|
||||
use rustc::session::Session;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
|
@ -200,3 +201,7 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
_ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
|
||||
span_err!(a, b, E0511, "{}", c);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,40 @@
|
|||
syntax::register_diagnostics! {
|
||||
|
||||
E0511: r##"
|
||||
Invalid monomorphization of an intrinsic function was used. Erroneous code
|
||||
example:
|
||||
|
||||
```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
|
||||
#![feature(platform_intrinsics)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe { simd_add(0, 1); }
|
||||
// error: invalid monomorphization of `simd_add` intrinsic
|
||||
}
|
||||
```
|
||||
|
||||
The generic type has to be a SIMD type. Example:
|
||||
|
||||
```
|
||||
#![feature(repr_simd)]
|
||||
#![feature(platform_intrinsics)]
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
|
||||
unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0668: r##"
|
||||
Malformed inline assembly rejected by LLVM.
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ use rustc::dep_graph::WorkProduct;
|
|||
use rustc::session::config::{OutputFilenames, OutputType};
|
||||
use rustc::middle::lang_items::LangItem;
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
|
@ -41,7 +42,6 @@ pub mod traits;
|
|||
pub mod mir;
|
||||
pub mod debuginfo;
|
||||
pub mod base;
|
||||
pub mod callee;
|
||||
pub mod glue;
|
||||
pub mod meth;
|
||||
pub mod mono_item;
|
||||
|
@ -156,3 +156,13 @@ pub struct CodegenResults {
|
|||
pub linker_info: back::linker::LinkerInfo,
|
||||
pub crate_info: CrateInfo,
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
crate::back::symbol_export::provide(providers);
|
||||
crate::base::provide_both(providers);
|
||||
}
|
||||
|
||||
pub fn provide_extern(providers: &mut Providers<'_>) {
|
||||
crate::back::symbol_export::provide_extern(providers);
|
||||
crate::base::provide_both(providers);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_target::abi::call::FnType;
|
||||
|
||||
use crate::callee;
|
||||
use crate::traits::*;
|
||||
|
||||
use rustc::ty::{self, Ty, Instance};
|
||||
|
@ -92,7 +91,14 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
|||
|
||||
let methods = methods.cloned().map(|opt_mth| {
|
||||
opt_mth.map_or(nullptr, |(def_id, substs)| {
|
||||
callee::resolve_and_get_fn_for_vtable(cx, def_id, substs)
|
||||
cx.get_fn_addr(
|
||||
ty::Instance::resolve_for_vtable(
|
||||
cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs,
|
||||
).unwrap()
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -102,7 +108,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
|||
// `get_vtable` in rust_mir/interpret/traits.rs
|
||||
// /////////////////////////////////////////////////////////////////////////////////////////////
|
||||
let components: Vec<_> = [
|
||||
cx.get_fn(Instance::resolve_drop_in_place(cx.tcx(), ty)),
|
||||
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
|
||||
cx.const_usize(layout.size.bytes()),
|
||||
cx.const_usize(layout.align.abi.bytes())
|
||||
].iter().cloned().chain(methods).collect();
|
||||
|
|
|
@ -358,7 +358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
(meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
|
||||
}
|
||||
_ => {
|
||||
(bx.get_fn(drop_fn),
|
||||
(bx.get_fn_addr(drop_fn),
|
||||
FnType::of_instance(&bx, drop_fn))
|
||||
}
|
||||
};
|
||||
|
@ -460,7 +460,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let fn_ty = FnType::of_instance(&bx, instance);
|
||||
let llfn = bx.get_fn(instance);
|
||||
let llfn = bx.get_fn_addr(instance);
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
helper.do_call(self, &mut bx, fn_ty, llfn, &args, None, cleanup);
|
||||
|
@ -576,7 +576,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let fn_ty = FnType::of_instance(&bx, instance);
|
||||
let llfn = bx.get_fn(instance);
|
||||
let llfn = bx.get_fn_addr(instance);
|
||||
|
||||
if let Some((_, target)) = destination.as_ref() {
|
||||
helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
|
||||
|
@ -793,7 +793,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
let fn_ptr = match (llfn, instance) {
|
||||
(Some(llfn), _) => llfn,
|
||||
(None, Some(instance)) => bx.get_fn(instance),
|
||||
(None, Some(instance)) => bx.get_fn_addr(instance),
|
||||
_ => span_bug!(span, "no llfn for call"),
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
|
||||
debug_context: FunctionDebugContext<Bx::DIScope>,
|
||||
|
||||
llfn: Bx::Value,
|
||||
llfn: Bx::Function,
|
||||
|
||||
cx: &'a Bx::CodegenCx,
|
||||
|
||||
|
@ -183,7 +183,7 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> {
|
|||
|
||||
pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
cx: &'a Bx::CodegenCx,
|
||||
llfn: Bx::Value,
|
||||
llfn: Bx::Function,
|
||||
mir: &'a Body<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
|
|
|
@ -394,8 +394,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
// Statically compute the offset if we can, otherwise just use the element size,
|
||||
// as this will yield the lowest alignment.
|
||||
let layout = self.layout.field(bx, 0);
|
||||
let offset = if bx.is_const_integral(llindex) {
|
||||
layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size)
|
||||
let offset = if let Some(llindex) = bx.const_to_opt_uint(llindex) {
|
||||
layout.size.checked_mul(llindex, bx).unwrap_or(layout.size)
|
||||
} else {
|
||||
layout.size
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@ use syntax::source_map::{DUMMY_SP, Span};
|
|||
|
||||
use crate::base;
|
||||
use crate::MemFlags;
|
||||
use crate::callee;
|
||||
use crate::common::{self, RealPredicate, IntPredicate};
|
||||
|
||||
use crate::traits::*;
|
||||
|
@ -95,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let size = bx.const_usize(dest.layout.size.bytes());
|
||||
|
||||
// Use llvm.memset.p0i8.* to initialize all zero arrays
|
||||
if bx.cx().is_const_integral(v) && bx.cx().const_to_uint(v) == 0 {
|
||||
if bx.cx().const_to_opt_uint(v) == Some(0) {
|
||||
let fill = bx.cx().const_u8(0);
|
||||
bx.memset(start, fill, size, dest.align, MemFlags::empty());
|
||||
return bx;
|
||||
|
@ -190,7 +189,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bug!("reifying a fn ptr that requires const arguments");
|
||||
}
|
||||
OperandValue::Immediate(
|
||||
callee::resolve_and_get_fn_for_ptr(bx.cx(), def_id, substs))
|
||||
bx.get_fn_addr(
|
||||
ty::Instance::resolve_for_fn_ptr(
|
||||
bx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs
|
||||
).unwrap()
|
||||
)
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
bug!("{} cannot be reified to a fn ptr", operand.layout.ty)
|
||||
|
@ -205,7 +212,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
def_id,
|
||||
substs,
|
||||
ty::ClosureKind::FnOnce);
|
||||
OperandValue::Immediate(bx.cx().get_fn(instance))
|
||||
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
|
||||
}
|
||||
_ => {
|
||||
bug!("{} cannot be cast to a fn ptr", operand.layout.ty)
|
||||
|
@ -488,7 +495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
};
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let r = bx.cx().get_fn(instance);
|
||||
let r = bx.cx().get_fn_addr(instance);
|
||||
let call = bx.call(r, &[llsize, llalign], None);
|
||||
let val = bx.pointercast(call, llty_ptr);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ use syntax_pos::symbol::InternedString;
|
|||
|
||||
pub trait BackendTypes {
|
||||
type Value: CodegenObject;
|
||||
type Function: CodegenObject;
|
||||
|
||||
type BasicBlock: Copy;
|
||||
type Type: CodegenObject;
|
||||
type Funclet;
|
||||
|
|
|
@ -34,7 +34,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
+ HasTargetSpec
|
||||
|
||||
{
|
||||
fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
|
||||
fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &'b str) -> Self;
|
||||
fn with_cx(cx: &'a Self::CodegenCx) -> Self;
|
||||
fn build_sibling_block(&self, name: &str) -> Self;
|
||||
fn cx(&self) -> &Self::CodegenCx;
|
||||
|
|
|
@ -21,11 +21,9 @@ pub trait ConstMethods<'tcx>: BackendTypes {
|
|||
|
||||
fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
|
||||
|
||||
fn const_to_uint(&self, v: Self::Value) -> u64;
|
||||
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
|
||||
fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
|
||||
|
||||
fn is_const_integral(&self, v: Self::Value) -> bool;
|
||||
|
||||
fn scalar_to_backend(
|
||||
&self,
|
||||
cv: Scalar,
|
||||
|
|
|
@ -20,7 +20,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
|||
&self,
|
||||
instance: Instance<'tcx>,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
llfn: Self::Value,
|
||||
llfn: Self::Function,
|
||||
mir: &mir::Body<'_>,
|
||||
) -> FunctionDebugContext<Self::DIScope>;
|
||||
|
||||
|
|
|
@ -17,13 +17,13 @@ pub trait DeclareMethods<'tcx>: BackendTypes {
|
|||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Value;
|
||||
fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function;
|
||||
|
||||
/// Declare a Rust function.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_fn(&self, name: &str, sig: ty::PolyFnSig<'tcx>) -> Self::Value;
|
||||
fn declare_fn(&self, name: &str, sig: ty::PolyFnSig<'tcx>) -> Self::Function;
|
||||
|
||||
/// Declare a global with an intention to define it.
|
||||
///
|
||||
|
|
|
@ -11,14 +11,14 @@ pub trait MiscMethods<'tcx>: BackendTypes {
|
|||
&self,
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
|
||||
fn check_overflow(&self) -> bool;
|
||||
fn instances(&self) -> &RefCell<FxHashMap<Instance<'tcx>, Self::Value>>;
|
||||
fn get_fn(&self, instance: Instance<'tcx>) -> Self::Value;
|
||||
fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function;
|
||||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value;
|
||||
fn eh_personality(&self) -> Self::Value;
|
||||
fn eh_unwind_resume(&self) -> Self::Value;
|
||||
fn sess(&self) -> &Session;
|
||||
fn codegen_unit(&self) -> &Arc<CodegenUnit<'tcx>>;
|
||||
fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
|
||||
fn set_frame_pointer_elimination(&self, llfn: Self::Value);
|
||||
fn apply_target_cpu_attr(&self, llfn: Self::Value);
|
||||
fn set_frame_pointer_elimination(&self, llfn: Self::Function);
|
||||
fn apply_target_cpu_attr(&self, llfn: Self::Function);
|
||||
fn create_used_variable(&self);
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ pub trait HasCodegen<'tcx>:
|
|||
type CodegenCx: CodegenMethods<'tcx>
|
||||
+ BackendTypes<
|
||||
Value = Self::Value,
|
||||
Function = Self::Function,
|
||||
BasicBlock = Self::BasicBlock,
|
||||
Type = Self::Type,
|
||||
Funclet = Self::Funclet,
|
||||
|
|
|
@ -25,7 +25,6 @@ pub trait CodegenBackend {
|
|||
fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
|
||||
fn print_passes(&self) {}
|
||||
fn print_version(&self) {}
|
||||
fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] }
|
||||
|
||||
fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync>;
|
||||
fn provide(&self, _providers: &mut Providers<'_>);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
extern crate rustc;
|
||||
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
use syntax::symbol::sym;
|
||||
|
||||
|
@ -37,3 +38,7 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
crate::symbol_names::provide(providers);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This module defines types which are thread safe if cfg!(parallel_compiler) is true.
|
||||
//!
|
||||
//! `Lrc` is an alias of either Rc or Arc.
|
||||
//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise.
|
||||
//!
|
||||
//! `Lock` is a mutex.
|
||||
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true,
|
||||
|
@ -12,7 +12,7 @@
|
|||
//!
|
||||
//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false.
|
||||
//!
|
||||
//! `MTRef` is a immutable reference if cfg!(parallel_compiler), and an mutable reference otherwise.
|
||||
//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise.
|
||||
//!
|
||||
//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
|
||||
//! depending on the value of cfg!(parallel_compiler).
|
||||
|
@ -23,29 +23,6 @@ use std::marker::PhantomData;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use crate::owning_ref::{Erased, OwningRef};
|
||||
|
||||
pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
|
||||
where A: FnOnce() -> RA,
|
||||
B: FnOnce() -> RB
|
||||
{
|
||||
(oper_a(), oper_b())
|
||||
}
|
||||
|
||||
pub struct SerialScope;
|
||||
|
||||
impl SerialScope {
|
||||
pub fn spawn<F>(&self, f: F)
|
||||
where F: FnOnce(&SerialScope)
|
||||
{
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serial_scope<F, R>(f: F) -> R
|
||||
where F: FnOnce(&SerialScope) -> R
|
||||
{
|
||||
f(&SerialScope)
|
||||
}
|
||||
|
||||
pub use std::sync::atomic::Ordering::SeqCst;
|
||||
pub use std::sync::atomic::Ordering;
|
||||
|
||||
|
@ -176,8 +153,28 @@ cfg_if! {
|
|||
pub type AtomicU32 = Atomic<u32>;
|
||||
pub type AtomicU64 = Atomic<u64>;
|
||||
|
||||
pub use self::serial_join as join;
|
||||
pub use self::serial_scope as scope;
|
||||
pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
|
||||
where A: FnOnce() -> RA,
|
||||
B: FnOnce() -> RB
|
||||
{
|
||||
(oper_a(), oper_b())
|
||||
}
|
||||
|
||||
pub struct SerialScope;
|
||||
|
||||
impl SerialScope {
|
||||
pub fn spawn<F>(&self, f: F)
|
||||
where F: FnOnce(&SerialScope)
|
||||
{
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope<F, R>(f: F) -> R
|
||||
where F: FnOnce(&SerialScope) -> R
|
||||
{
|
||||
f(&SerialScope)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! parallel {
|
||||
|
|
|
@ -616,7 +616,7 @@ impl RustcDefaultCalls {
|
|||
let mut v = Vec::new();
|
||||
locator::list_file_metadata(&sess.target.target,
|
||||
path,
|
||||
&*cstore.metadata_loader,
|
||||
cstore,
|
||||
&mut v)
|
||||
.unwrap();
|
||||
println!("{}", String::from_utf8(v).unwrap());
|
||||
|
|
|
@ -49,6 +49,10 @@ impl Emitter for AnnotateSnippetEmitterWriter {
|
|||
&suggestions);
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
|
||||
self.source_map.as_ref()
|
||||
}
|
||||
|
||||
fn should_show_explain(&self) -> bool {
|
||||
!self.short_message
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use syntax_pos::{SourceFile, Span, MultiSpan};
|
|||
|
||||
use crate::{
|
||||
Level, CodeSuggestion, Diagnostic, SubDiagnostic,
|
||||
SuggestionStyle, SourceMapperDyn, DiagnosticId,
|
||||
SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId,
|
||||
};
|
||||
use crate::Level::Error;
|
||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
|
||||
|
@ -192,6 +192,8 @@ pub trait Emitter {
|
|||
true
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>>;
|
||||
|
||||
/// Formats the substitutions of the primary_span
|
||||
///
|
||||
/// The are a lot of conditions to this method, but in short:
|
||||
|
@ -204,7 +206,7 @@ pub trait Emitter {
|
|||
/// we return the original `primary_span` and the original suggestions.
|
||||
fn primary_span_formatted<'a>(
|
||||
&mut self,
|
||||
db: &'a Diagnostic
|
||||
db: &'a Diagnostic,
|
||||
) -> (MultiSpan, &'a [CodeSuggestion]) {
|
||||
let mut primary_span = db.span.clone();
|
||||
if let Some((sugg, rest)) = db.suggestions.split_first() {
|
||||
|
@ -234,7 +236,20 @@ pub trait Emitter {
|
|||
format!("help: {}", sugg.msg)
|
||||
} else {
|
||||
// Show the default suggestion text with the substitution
|
||||
format!("help: {}: `{}`", sugg.msg, substitution)
|
||||
format!(
|
||||
"help: {}{}: `{}`",
|
||||
sugg.msg,
|
||||
if self.source_map().map(|sm| is_case_difference(
|
||||
&**sm,
|
||||
substitution,
|
||||
sugg.substitutions[0].parts[0].span,
|
||||
)).unwrap_or(false) {
|
||||
" (notice the capitalization)"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
substitution,
|
||||
)
|
||||
};
|
||||
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
|
||||
|
||||
|
@ -382,6 +397,10 @@ pub trait Emitter {
|
|||
}
|
||||
|
||||
impl Emitter for EmitterWriter {
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
|
||||
self.sm.as_ref()
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, db: &Diagnostic) {
|
||||
let mut children = db.children.clone();
|
||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
|
||||
|
@ -1461,7 +1480,9 @@ impl EmitterWriter {
|
|||
let suggestions = suggestion.splice_lines(&**sm);
|
||||
|
||||
let mut row_num = 2;
|
||||
for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) {
|
||||
let mut notice_capitalization = false;
|
||||
for (complete, parts, only_capitalization) in suggestions.iter().take(MAX_SUGGESTIONS) {
|
||||
notice_capitalization |= only_capitalization;
|
||||
// Only show underline if the suggestion spans a single line and doesn't cover the
|
||||
// entirety of the code output. If you have multiple replacements in the same line
|
||||
// of code, show the underline.
|
||||
|
@ -1552,7 +1573,10 @@ impl EmitterWriter {
|
|||
}
|
||||
if suggestions.len() > MAX_SUGGESTIONS {
|
||||
let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
|
||||
buffer.puts(row_num, 0, &msg, Style::NoStyle);
|
||||
buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
|
||||
} else if notice_capitalization {
|
||||
let msg = "notice the capitalization difference";
|
||||
buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
|
||||
}
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
|
||||
Ok(())
|
||||
|
@ -2034,3 +2058,18 @@ impl<'a> Drop for WritableDst<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
|
||||
pub fn is_case_difference(sm: &dyn SourceMapper, suggested: &str, sp: Span) -> bool {
|
||||
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
|
||||
let found = sm.span_to_snippet(sp).unwrap();
|
||||
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
// All the chars that differ in capitalization are confusable (above):
|
||||
let confusable = found.chars().zip(suggested.chars()).filter(|(f, s)| f != s).all(|(f, s)| {
|
||||
(ascii_confusables.contains(&f) || ascii_confusables.contains(&s))
|
||||
});
|
||||
confusable && found.to_lowercase() == suggested.to_lowercase()
|
||||
// FIXME: We sometimes suggest the same thing we already have, which is a
|
||||
// bug, but be defensive against that here.
|
||||
&& found != suggested
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub use emitter::ColorConfig;
|
|||
|
||||
use Level::*;
|
||||
|
||||
use emitter::{Emitter, EmitterWriter};
|
||||
use emitter::{Emitter, EmitterWriter, is_case_difference};
|
||||
use registry::Registry;
|
||||
|
||||
use rustc_data_structures::sync::{self, Lrc, Lock};
|
||||
|
@ -37,13 +37,16 @@ pub mod registry;
|
|||
mod styled_buffer;
|
||||
mod lock;
|
||||
|
||||
use syntax_pos::{BytePos,
|
||||
Loc,
|
||||
FileLinesResult,
|
||||
SourceFile,
|
||||
FileName,
|
||||
MultiSpan,
|
||||
Span};
|
||||
use syntax_pos::{
|
||||
BytePos,
|
||||
FileLinesResult,
|
||||
FileName,
|
||||
Loc,
|
||||
MultiSpan,
|
||||
SourceFile,
|
||||
Span,
|
||||
SpanSnippetError,
|
||||
};
|
||||
|
||||
/// Indicates the confidence in the correctness of a suggestion.
|
||||
///
|
||||
|
@ -147,6 +150,7 @@ pub trait SourceMapper {
|
|||
fn lookup_char_pos(&self, pos: BytePos) -> Loc;
|
||||
fn span_to_lines(&self, sp: Span) -> FileLinesResult;
|
||||
fn span_to_string(&self, sp: Span) -> String;
|
||||
fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError>;
|
||||
fn span_to_filename(&self, sp: Span) -> FileName;
|
||||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
|
||||
fn call_span_if_macro(&self, sp: Span) -> Span;
|
||||
|
@ -155,9 +159,12 @@ pub trait SourceMapper {
|
|||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
/// Returns the assembled code suggestions and whether they should be shown with an underline.
|
||||
pub fn splice_lines(&self, cm: &SourceMapperDyn)
|
||||
-> Vec<(String, Vec<SubstitutionPart>)> {
|
||||
/// Returns the assembled code suggestions, whether they should be shown with an underline
|
||||
/// and whether the substitution only differs in capitalization.
|
||||
pub fn splice_lines(
|
||||
&self,
|
||||
cm: &SourceMapperDyn,
|
||||
) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
|
||||
use syntax_pos::{CharPos, Pos};
|
||||
|
||||
fn push_trailing(buf: &mut String,
|
||||
|
@ -232,6 +239,7 @@ impl CodeSuggestion {
|
|||
prev_hi = cm.lookup_char_pos(part.span.hi());
|
||||
prev_line = fm.get_line(prev_hi.line - 1);
|
||||
}
|
||||
let only_capitalization = is_case_difference(cm, &buf, bounding_span);
|
||||
// if the replacement already ends with a newline, don't print the next line
|
||||
if !buf.ends_with('\n') {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
|
@ -240,7 +248,7 @@ impl CodeSuggestion {
|
|||
while buf.ends_with('\n') {
|
||||
buf.pop();
|
||||
}
|
||||
(buf, substitution.parts)
|
||||
(buf, substitution.parts, only_capitalization)
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ pub fn configure_and_expand(
|
|||
let crate_name = crate_name.to_string();
|
||||
let (result, resolver) = BoxedResolver::new(static move || {
|
||||
let sess = &*sess;
|
||||
let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name);
|
||||
let crate_loader = CrateLoader::new(sess, &*cstore, &crate_name);
|
||||
let resolver_arenas = Resolver::arenas();
|
||||
let res = configure_and_expand_inner(
|
||||
sess,
|
||||
|
@ -138,7 +138,7 @@ pub fn configure_and_expand(
|
|||
krate,
|
||||
&crate_name,
|
||||
&resolver_arenas,
|
||||
&mut crate_loader,
|
||||
&crate_loader,
|
||||
plugin_info,
|
||||
);
|
||||
let mut resolver = match res {
|
||||
|
@ -169,6 +169,7 @@ impl ExpansionResult {
|
|||
ExpansionResult {
|
||||
defs: Steal::new(resolver.definitions),
|
||||
resolutions: Steal::new(Resolutions {
|
||||
extern_crate_map: resolver.extern_crate_map,
|
||||
export_map: resolver.export_map,
|
||||
trait_map: resolver.trait_map,
|
||||
glob_map: resolver.glob_map,
|
||||
|
@ -187,6 +188,7 @@ impl ExpansionResult {
|
|||
ExpansionResult {
|
||||
defs: Steal::new(resolver.definitions.clone()),
|
||||
resolutions: Steal::new(Resolutions {
|
||||
extern_crate_map: resolver.extern_crate_map.clone(),
|
||||
export_map: resolver.export_map.clone(),
|
||||
trait_map: resolver.trait_map.clone(),
|
||||
glob_map: resolver.glob_map.clone(),
|
||||
|
@ -319,7 +321,7 @@ fn configure_and_expand_inner<'a>(
|
|||
mut krate: ast::Crate,
|
||||
crate_name: &str,
|
||||
resolver_arenas: &'a ResolverArenas<'a>,
|
||||
crate_loader: &'a mut CrateLoader<'a>,
|
||||
crate_loader: &'a CrateLoader<'a>,
|
||||
plugin_info: PluginInfo,
|
||||
) -> Result<(ast::Crate, Resolver<'a>)> {
|
||||
time(sess, "pre-AST-expansion lint checks", || {
|
||||
|
@ -663,16 +665,15 @@ fn write_out_deps(compiler: &Compiler, outputs: &OutputFilenames, out_filenames:
|
|||
|
||||
if sess.binary_dep_depinfo() {
|
||||
for cnum in compiler.cstore.crates_untracked() {
|
||||
let metadata = compiler.cstore.crate_data_as_rc_any(cnum);
|
||||
let metadata = metadata.downcast_ref::<cstore::CrateMetadata>().unwrap();
|
||||
if let Some((path, _)) = &metadata.source.dylib {
|
||||
files.push(escape_dep_filename(&FileName::Real(path.clone())));
|
||||
let source = compiler.cstore.crate_source_untracked(cnum);
|
||||
if let Some((path, _)) = source.dylib {
|
||||
files.push(escape_dep_filename(&FileName::Real(path)));
|
||||
}
|
||||
if let Some((path, _)) = &metadata.source.rlib {
|
||||
files.push(escape_dep_filename(&FileName::Real(path.clone())));
|
||||
if let Some((path, _)) = source.rlib {
|
||||
files.push(escape_dep_filename(&FileName::Real(path)));
|
||||
}
|
||||
if let Some((path, _)) = &metadata.source.rmeta {
|
||||
files.push(escape_dep_filename(&FileName::Real(path.clone())));
|
||||
if let Some((path, _)) = source.rmeta {
|
||||
files.push(escape_dep_filename(&FileName::Real(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -790,10 +791,13 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
|
|||
cstore::provide(providers);
|
||||
lint::provide(providers);
|
||||
rustc_lint::provide(providers);
|
||||
rustc_codegen_utils::provide(providers);
|
||||
rustc_codegen_ssa::provide(providers);
|
||||
}
|
||||
|
||||
pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
|
||||
cstore::provide_extern(providers);
|
||||
rustc_codegen_ssa::provide_extern(providers);
|
||||
}
|
||||
|
||||
declare_box_region_type!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Validates all used crates and extern libraries and loads their metadata
|
||||
|
||||
use crate::cstore::{self, CStore, CrateSource, MetadataBlob};
|
||||
use crate::cstore::{self, CStore, MetadataBlob};
|
||||
use crate::locator::{self, CratePaths};
|
||||
use crate::schema::{CrateRoot, CrateDep};
|
||||
use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell};
|
||||
|
@ -14,7 +14,7 @@ use rustc::session::{Session, CrateDisambiguator};
|
|||
use rustc::session::config::{Sanitizer, self};
|
||||
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
||||
use rustc::session::search_paths::PathKind;
|
||||
use rustc::middle::cstore::{ExternCrate, ExternCrateSource};
|
||||
use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource};
|
||||
use rustc::util::common::record_time;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::hir::map::Definitions;
|
||||
|
@ -33,15 +33,13 @@ use syntax_pos::{Span, DUMMY_SP};
|
|||
use log::{debug, info, log_enabled};
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
|
||||
pub struct Library {
|
||||
pub dylib: Option<(PathBuf, PathKind)>,
|
||||
pub rlib: Option<(PathBuf, PathKind)>,
|
||||
pub rmeta: Option<(PathBuf, PathKind)>,
|
||||
crate struct Library {
|
||||
pub source: CrateSource,
|
||||
pub metadata: MetadataBlob,
|
||||
}
|
||||
|
||||
pub struct CrateLoader<'a> {
|
||||
pub sess: &'a Session,
|
||||
sess: &'a Session,
|
||||
cstore: &'a CStore,
|
||||
local_crate_name: Symbol,
|
||||
}
|
||||
|
@ -189,7 +187,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn register_crate(
|
||||
&mut self,
|
||||
&self,
|
||||
host_lib: Option<Library>,
|
||||
root: Option<&CratePaths>,
|
||||
span: Span,
|
||||
|
@ -197,10 +195,10 @@ impl<'a> CrateLoader<'a> {
|
|||
dep_kind: DepKind,
|
||||
name: Symbol
|
||||
) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
|
||||
let _prof_timer =
|
||||
self.sess.prof.generic_activity("metadata_register_crate");
|
||||
let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
|
||||
|
||||
let crate_root = lib.metadata.get_root();
|
||||
let Library { source, metadata } = lib;
|
||||
let crate_root = metadata.get_root();
|
||||
self.verify_no_symbol_conflicts(span, &crate_root);
|
||||
|
||||
let private_dep = self.sess.opts.externs.get(&name.as_str())
|
||||
|
@ -218,28 +216,22 @@ impl<'a> CrateLoader<'a> {
|
|||
let root = if let Some(root) = root {
|
||||
root
|
||||
} else {
|
||||
crate_paths = CratePaths {
|
||||
ident: crate_root.name.to_string(),
|
||||
dylib: lib.dylib.clone().map(|p| p.0),
|
||||
rlib: lib.rlib.clone().map(|p| p.0),
|
||||
rmeta: lib.rmeta.clone().map(|p| p.0),
|
||||
};
|
||||
crate_paths = CratePaths { name: crate_root.name, source: source.clone() };
|
||||
&crate_paths
|
||||
};
|
||||
|
||||
let Library { dylib, rlib, rmeta, metadata } = lib;
|
||||
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
|
||||
|
||||
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
|
||||
|
||||
let raw_proc_macros = crate_root.proc_macro_data.map(|_| {
|
||||
let temp_root;
|
||||
let (dlsym_dylib, dlsym_root) = match &host_lib {
|
||||
let (dlsym_source, dlsym_root) = match &host_lib {
|
||||
Some(host_lib) =>
|
||||
(&host_lib.dylib, { temp_root = host_lib.metadata.get_root(); &temp_root }),
|
||||
None => (&dylib, &crate_root),
|
||||
(&host_lib.source, { temp_root = host_lib.metadata.get_root(); &temp_root }),
|
||||
None => (&source, &crate_root),
|
||||
};
|
||||
let dlsym_dylib = dlsym_dylib.as_ref().expect("no dylib for a proc-macro crate");
|
||||
let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
|
||||
self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator, span)
|
||||
});
|
||||
|
||||
|
@ -268,13 +260,8 @@ impl<'a> CrateLoader<'a> {
|
|||
source_map_import_info: RwLock::new(vec![]),
|
||||
alloc_decoding_state: AllocDecodingState::new(interpret_alloc_index),
|
||||
dep_kind: Lock::new(dep_kind),
|
||||
source: cstore::CrateSource {
|
||||
dylib,
|
||||
rlib,
|
||||
rmeta,
|
||||
},
|
||||
source,
|
||||
private_dep,
|
||||
span,
|
||||
raw_proc_macros,
|
||||
dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
|
||||
};
|
||||
|
@ -285,7 +272,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn load_proc_macro<'b>(
|
||||
&mut self,
|
||||
&self,
|
||||
locate_ctxt: &mut locator::Context<'b>,
|
||||
path_kind: PathKind,
|
||||
) -> Option<(LoadResult, Option<Library>)>
|
||||
|
@ -340,7 +327,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn resolve_crate<'b>(
|
||||
&'b mut self,
|
||||
&'b self,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
dep_kind: DepKind,
|
||||
|
@ -350,7 +337,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn maybe_resolve_crate<'b>(
|
||||
&'b mut self,
|
||||
&'b self,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
mut dep_kind: DepKind,
|
||||
|
@ -410,7 +397,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn load(&mut self, locate_ctxt: &mut locator::Context<'_>) -> Option<LoadResult> {
|
||||
fn load(&self, locate_ctxt: &mut locator::Context<'_>) -> Option<LoadResult> {
|
||||
let library = locate_ctxt.maybe_load_library_crate()?;
|
||||
|
||||
// In the case that we're loading a crate, but not matching
|
||||
|
@ -437,7 +424,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_extern_crate(&mut self,
|
||||
fn update_extern_crate(&self,
|
||||
cnum: CrateNum,
|
||||
mut extern_crate: ExternCrate,
|
||||
visited: &mut FxHashSet<(CrateNum, bool)>)
|
||||
|
@ -479,7 +466,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
// Go through the crate metadata and load any crates that it references
|
||||
fn resolve_crate_deps(&mut self,
|
||||
fn resolve_crate_deps(&self,
|
||||
root: &CratePaths,
|
||||
crate_root: &CrateRoot<'_>,
|
||||
metadata: &MetadataBlob,
|
||||
|
@ -509,7 +496,7 @@ impl<'a> CrateLoader<'a> {
|
|||
})).collect()
|
||||
}
|
||||
|
||||
fn read_extension_crate(&mut self, name: Symbol, span: Span) -> ExtensionCrate {
|
||||
fn read_extension_crate(&self, name: Symbol, span: Span) -> ExtensionCrate {
|
||||
info!("read extension crate `{}`", name);
|
||||
let target_triple = self.sess.opts.target_triple.clone();
|
||||
let host_triple = TargetTriple::from_triple(config::host_triple());
|
||||
|
@ -559,7 +546,7 @@ impl<'a> CrateLoader<'a> {
|
|||
(data.source.dylib.clone(), PMDSource::Registered(data))
|
||||
}
|
||||
LoadResult::Loaded(library) => {
|
||||
let dylib = library.dylib.clone();
|
||||
let dylib = library.source.dylib.clone();
|
||||
let metadata = PMDSource::Owned(library);
|
||||
(dylib, metadata)
|
||||
}
|
||||
|
@ -605,7 +592,7 @@ impl<'a> CrateLoader<'a> {
|
|||
|
||||
/// Look for a plugin registrar. Returns library path, crate
|
||||
/// SVH and DefIndex of the registrar function.
|
||||
pub fn find_plugin_registrar(&mut self,
|
||||
pub fn find_plugin_registrar(&self,
|
||||
span: Span,
|
||||
name: Symbol)
|
||||
-> Option<(PathBuf, CrateDisambiguator)> {
|
||||
|
@ -638,7 +625,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
|
||||
fn inject_panic_runtime(&self, krate: &ast::Crate) {
|
||||
// If we're only compiling an rlib, then there's no need to select a
|
||||
// panic runtime, so we just skip this section entirely.
|
||||
let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
|
||||
|
@ -719,7 +706,7 @@ impl<'a> CrateLoader<'a> {
|
|||
&|data| data.root.needs_panic_runtime);
|
||||
}
|
||||
|
||||
fn inject_sanitizer_runtime(&mut self) {
|
||||
fn inject_sanitizer_runtime(&self) {
|
||||
if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
|
||||
// Sanitizers can only be used on some tested platforms with
|
||||
// executables linked to `std`
|
||||
|
@ -817,7 +804,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn inject_profiler_runtime(&mut self) {
|
||||
fn inject_profiler_runtime(&self) {
|
||||
if self.sess.opts.debugging_opts.profile ||
|
||||
self.sess.opts.cg.profile_generate.enabled()
|
||||
{
|
||||
|
@ -834,7 +821,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
|
||||
fn inject_allocator_crate(&self, krate: &ast::Crate) {
|
||||
let has_global_allocator = match &*global_allocator_spans(krate) {
|
||||
[span1, span2, ..] => {
|
||||
self.sess.struct_span_err(*span2, "cannot define multiple global allocators")
|
||||
|
@ -973,7 +960,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
impl<'a> CrateLoader<'a> {
|
||||
pub fn postprocess(&mut self, krate: &ast::Crate) {
|
||||
pub fn postprocess(&self, krate: &ast::Crate) {
|
||||
self.inject_sanitizer_runtime();
|
||||
self.inject_profiler_runtime();
|
||||
self.inject_allocator_crate(krate);
|
||||
|
@ -984,9 +971,7 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn process_extern_crate(
|
||||
&mut self, item: &ast::Item, definitions: &Definitions,
|
||||
) -> CrateNum {
|
||||
pub fn process_extern_crate(&self, item: &ast::Item, definitions: &Definitions) -> CrateNum {
|
||||
match item.kind {
|
||||
ast::ItemKind::ExternCrate(orig_name) => {
|
||||
debug!("resolving extern crate stmt. ident: {} orig_name: {:?}",
|
||||
|
@ -1019,18 +1004,13 @@ impl<'a> CrateLoader<'a> {
|
|||
},
|
||||
&mut FxHashSet::default(),
|
||||
);
|
||||
self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
|
||||
cnum
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_path_extern(
|
||||
&mut self,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
) -> CrateNum {
|
||||
pub fn process_path_extern(&self, name: Symbol, span: Span) -> CrateNum {
|
||||
let cnum = self.resolve_crate(name, span, DepKind::Explicit, None).0;
|
||||
|
||||
self.update_extern_crate(
|
||||
|
@ -1048,11 +1028,7 @@ impl<'a> CrateLoader<'a> {
|
|||
cnum
|
||||
}
|
||||
|
||||
pub fn maybe_process_path_extern(
|
||||
&mut self,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
) -> Option<CrateNum> {
|
||||
pub fn maybe_process_path_extern(&self, name: Symbol, span: Span) -> Option<CrateNum> {
|
||||
let cnum = self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()?.0;
|
||||
|
||||
self.update_extern_crate(
|
||||
|
|
|
@ -5,19 +5,15 @@ use crate::schema;
|
|||
use rustc::dep_graph::DepNodeIndex;
|
||||
use rustc::hir::def_id::{CrateNum, DefIndex};
|
||||
use rustc::hir::map::definitions::DefPathTable;
|
||||
use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
|
||||
use rustc::middle::cstore::{CrateSource, DepKind, ExternCrate, MetadataLoader};
|
||||
use rustc::mir::interpret::AllocDecodingState;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc::util::nodemap::{FxHashMap, NodeMap};
|
||||
|
||||
use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::sync::{Lrc, RwLock, Lock, MetadataRef, AtomicCell};
|
||||
use syntax::ast;
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax_pos;
|
||||
|
||||
pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
|
||||
pub use rustc::middle::cstore::NativeLibraryKind::*;
|
||||
pub use rustc::middle::cstore::{CrateSource, LibSource, ForeignModule};
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
|
||||
pub use crate::cstore_impl::{provide, provide_extern};
|
||||
|
||||
|
@ -25,17 +21,13 @@ pub use crate::cstore_impl::{provide, provide_extern};
|
|||
// local crate numbers (as generated during this session). Each external
|
||||
// crate may refer to types in other external crates, and each has their
|
||||
// own crate numbers.
|
||||
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||
crate type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||
|
||||
pub use rustc_data_structures::sync::MetadataRef;
|
||||
use syntax_pos::Span;
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
|
||||
pub struct MetadataBlob(pub MetadataRef);
|
||||
crate struct MetadataBlob(pub MetadataRef);
|
||||
|
||||
/// Holds information about a syntax_pos::SourceFile imported from another crate.
|
||||
/// See `imported_source_files()` for more information.
|
||||
pub struct ImportedSourceFile {
|
||||
crate struct ImportedSourceFile {
|
||||
/// This SourceFile's byte-offset within the source_map of its original crate
|
||||
pub original_start_pos: syntax_pos::BytePos,
|
||||
/// The end of this SourceFile within the source_map of its original crate
|
||||
|
@ -45,59 +37,66 @@ pub struct ImportedSourceFile {
|
|||
}
|
||||
|
||||
pub struct CrateMetadata {
|
||||
/// Information about the extern crate that caused this crate to
|
||||
/// be loaded. If this is `None`, then the crate was injected
|
||||
/// (e.g., by the allocator)
|
||||
pub extern_crate: Lock<Option<ExternCrate>>,
|
||||
/// The primary crate data - binary metadata blob.
|
||||
crate blob: MetadataBlob,
|
||||
|
||||
pub blob: MetadataBlob,
|
||||
pub cnum_map: CrateNumMap,
|
||||
pub cnum: CrateNum,
|
||||
pub dependencies: Lock<Vec<CrateNum>>,
|
||||
pub source_map_import_info: RwLock<Vec<ImportedSourceFile>>,
|
||||
|
||||
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
|
||||
pub alloc_decoding_state: AllocDecodingState,
|
||||
|
||||
// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
|
||||
// lifetime is only used behind `Lazy`, and therefore acts like an
|
||||
// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
|
||||
// is being used to decode those values.
|
||||
pub root: schema::CrateRoot<'static>,
|
||||
// --- Some data pre-decoded from the metadata blob, usually for performance ---
|
||||
|
||||
/// Properties of the whole crate.
|
||||
/// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
|
||||
/// lifetime is only used behind `Lazy`, and therefore acts like an
|
||||
/// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
|
||||
/// is being used to decode those values.
|
||||
crate root: schema::CrateRoot<'static>,
|
||||
/// For each definition in this crate, we encode a key. When the
|
||||
/// crate is loaded, we read all the keys and put them in this
|
||||
/// hashmap, which gives the reverse mapping. This allows us to
|
||||
/// quickly retrace a `DefPath`, which is needed for incremental
|
||||
/// compilation support.
|
||||
pub def_path_table: Lrc<DefPathTable>,
|
||||
|
||||
pub trait_impls: FxHashMap<(u32, DefIndex), schema::Lazy<[DefIndex]>>,
|
||||
|
||||
pub dep_kind: Lock<DepKind>,
|
||||
pub source: CrateSource,
|
||||
|
||||
/// Whether or not this crate should be consider a private dependency
|
||||
/// for purposes of the 'exported_private_dependencies' lint
|
||||
pub private_dep: bool,
|
||||
|
||||
pub span: Span,
|
||||
|
||||
pub raw_proc_macros: Option<&'static [ProcMacro]>,
|
||||
|
||||
crate def_path_table: Lrc<DefPathTable>,
|
||||
/// Trait impl data.
|
||||
/// FIXME: Used only from queries and can use query cache,
|
||||
/// so pre-decoding can probably be avoided.
|
||||
crate trait_impls: FxHashMap<(u32, DefIndex), schema::Lazy<[DefIndex]>>,
|
||||
/// Proc macro descriptions for this crate, if it's a proc macro crate.
|
||||
crate raw_proc_macros: Option<&'static [ProcMacro]>,
|
||||
/// Source maps for code from the crate.
|
||||
crate source_map_import_info: RwLock<Vec<ImportedSourceFile>>,
|
||||
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
|
||||
crate alloc_decoding_state: AllocDecodingState,
|
||||
/// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
|
||||
/// It is initialized on the first access in `get_crate_dep_node_index()`.
|
||||
/// Do not access the value directly, as it might not have been initialized
|
||||
/// yet.
|
||||
/// Do not access the value directly, as it might not have been initialized yet.
|
||||
/// The field must always be initialized to `DepNodeIndex::INVALID`.
|
||||
pub(super) dep_node_index: AtomicCell<DepNodeIndex>,
|
||||
crate dep_node_index: AtomicCell<DepNodeIndex>,
|
||||
|
||||
// --- Other significant crate properties ---
|
||||
|
||||
/// ID of this crate, from the current compilation session's point of view.
|
||||
crate cnum: CrateNum,
|
||||
/// Maps crate IDs as they are were seen from this crate's compilation sessions into
|
||||
/// IDs as they are seen from the current compilation session.
|
||||
crate cnum_map: CrateNumMap,
|
||||
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
|
||||
crate dependencies: Lock<Vec<CrateNum>>,
|
||||
/// How to link (or not link) this crate to the currently compiled crate.
|
||||
crate dep_kind: Lock<DepKind>,
|
||||
/// Filesystem location of this crate.
|
||||
crate source: CrateSource,
|
||||
/// Whether or not this crate should be consider a private dependency
|
||||
/// for purposes of the 'exported_private_dependencies' lint
|
||||
crate private_dep: bool,
|
||||
|
||||
// --- Data used only for improving diagnostics ---
|
||||
|
||||
/// Information about the `extern crate` item or path that caused this crate to be loaded.
|
||||
/// If this is `None`, then the crate was injected (e.g., by the allocator).
|
||||
crate extern_crate: Lock<Option<ExternCrate>>,
|
||||
}
|
||||
|
||||
pub struct CStore {
|
||||
metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
|
||||
/// Map from NodeId's of local extern crate statements to crate numbers
|
||||
extern_mod_crate_map: Lock<NodeMap<CrateNum>>,
|
||||
pub metadata_loader: Box<dyn MetadataLoader + Sync>,
|
||||
crate metadata_loader: Box<dyn MetadataLoader + Sync>,
|
||||
}
|
||||
|
||||
pub enum LoadedMacro {
|
||||
|
@ -113,30 +112,29 @@ impl CStore {
|
|||
// corresponding `CrateNum`. This first entry will always remain
|
||||
// `None`.
|
||||
metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
|
||||
extern_mod_crate_map: Default::default(),
|
||||
metadata_loader,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
|
||||
crate fn alloc_new_crate_num(&self) -> CrateNum {
|
||||
let mut metas = self.metas.borrow_mut();
|
||||
let cnum = CrateNum::new(metas.len());
|
||||
metas.push(None);
|
||||
cnum
|
||||
}
|
||||
|
||||
pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
|
||||
crate fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
|
||||
self.metas.borrow()[cnum].clone()
|
||||
.unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum))
|
||||
}
|
||||
|
||||
pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
|
||||
crate fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
|
||||
let mut metas = self.metas.borrow_mut();
|
||||
assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
|
||||
metas[cnum] = Some(data);
|
||||
}
|
||||
|
||||
pub(super) fn iter_crate_data<I>(&self, mut i: I)
|
||||
crate fn iter_crate_data<I>(&self, mut i: I)
|
||||
where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
|
||||
{
|
||||
for (k, v) in self.metas.borrow().iter_enumerated() {
|
||||
|
@ -146,16 +144,14 @@ impl CStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
|
||||
crate fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
|
||||
let mut ordering = Vec::new();
|
||||
self.push_dependencies_in_postorder(&mut ordering, krate);
|
||||
ordering.reverse();
|
||||
ordering
|
||||
}
|
||||
|
||||
pub(super) fn push_dependencies_in_postorder(&self,
|
||||
ordering: &mut Vec<CrateNum>,
|
||||
krate: CrateNum) {
|
||||
crate fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
|
||||
if ordering.contains(&krate) {
|
||||
return;
|
||||
}
|
||||
|
@ -170,7 +166,7 @@ impl CStore {
|
|||
ordering.push(krate);
|
||||
}
|
||||
|
||||
pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
|
||||
crate fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
|
||||
let mut ordering = Vec::new();
|
||||
for (num, v) in self.metas.borrow().iter_enumerated() {
|
||||
if let &Some(_) = v {
|
||||
|
@ -179,12 +175,4 @@ impl CStore {
|
|||
}
|
||||
return ordering
|
||||
}
|
||||
|
||||
pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
|
||||
self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
|
||||
}
|
||||
|
||||
pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
|
||||
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@ use crate::foreign_modules;
|
|||
use crate::schema;
|
||||
|
||||
use rustc::ty::query::QueryConfig;
|
||||
use rustc::middle::cstore::{CrateStore, DepKind,
|
||||
EncodedMetadata, NativeLibraryKind};
|
||||
use rustc::middle::cstore::{CrateSource, CrateStore, DepKind, EncodedMetadata, NativeLibraryKind};
|
||||
use rustc::middle::exported_symbols::ExportedSymbol;
|
||||
use rustc::middle::stability::DeprecationEntry;
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
|
@ -414,12 +413,6 @@ impl cstore::CStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind {
|
||||
let data = self.get_crate_data(cnum);
|
||||
let r = *data.dep_kind.lock();
|
||||
r
|
||||
}
|
||||
|
||||
pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition {
|
||||
self.get_crate_data(cnum).root.edition
|
||||
}
|
||||
|
@ -428,14 +421,6 @@ impl cstore::CStore {
|
|||
self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
|
||||
}
|
||||
|
||||
pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind {
|
||||
self.get_crate_data(def.krate).get_ctor_kind(def.index)
|
||||
}
|
||||
|
||||
pub fn item_attrs_untracked(&self, def: DefId, sess: &Session) -> Lrc<[ast::Attribute]> {
|
||||
self.get_crate_data(def.krate).get_item_attrs(def.index, sess)
|
||||
}
|
||||
|
||||
pub fn item_children_untracked(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
|
@ -493,6 +478,10 @@ impl cstore::CStore {
|
|||
pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssocItem {
|
||||
self.get_crate_data(def.krate).get_associated_item(def.index)
|
||||
}
|
||||
|
||||
pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
|
||||
self.get_crate_data(cnum).source.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateStore for cstore::CStore {
|
||||
|
@ -549,11 +538,6 @@ impl CrateStore for cstore::CStore {
|
|||
result
|
||||
}
|
||||
|
||||
fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>
|
||||
{
|
||||
self.do_extern_mod_stmt_cnum(emod_id)
|
||||
}
|
||||
|
||||
fn postorder_cnums_untracked(&self) -> Vec<CrateNum> {
|
||||
self.do_postorder_cnums_untracked()
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// Decoding metadata from a single crate's metadata
|
||||
|
||||
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
|
||||
use crate::cstore::{self, CrateMetadata, MetadataBlob};
|
||||
use crate::schema::*;
|
||||
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_data_structures::sync::{Lrc, ReadGuard};
|
||||
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
|
||||
use rustc::hir;
|
||||
use rustc::middle::cstore::LinkagePreference;
|
||||
use rustc::middle::cstore::{LinkagePreference, NativeLibrary, ForeignModule};
|
||||
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
||||
use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
|
@ -38,7 +38,7 @@ use log::debug;
|
|||
use proc_macro::bridge::client::ProcMacro;
|
||||
use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
|
||||
|
||||
pub struct DecodeContext<'a, 'tcx> {
|
||||
crate struct DecodeContext<'a, 'tcx> {
|
||||
opaque: opaque::Decoder<'a>,
|
||||
cdata: Option<&'a CrateMetadata>,
|
||||
sess: Option<&'tcx Session>,
|
||||
|
@ -54,7 +54,7 @@ pub struct DecodeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Abstract over the various ways one can create metadata decoders.
|
||||
pub trait Metadata<'a, 'tcx>: Copy {
|
||||
crate trait Metadata<'a, 'tcx>: Copy {
|
||||
fn raw_bytes(self) -> &'a [u8];
|
||||
fn cdata(self) -> Option<&'a CrateMetadata> { None }
|
||||
fn sess(self) -> Option<&'tcx Session> { None }
|
||||
|
@ -130,7 +130,7 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx, T: Decodable> Lazy<T> {
|
||||
pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
|
||||
crate fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
|
||||
let mut dcx = meta.decoder(self.position);
|
||||
dcx.lazy_state = LazyState::NodeStart(self.position);
|
||||
T::decode(&mut dcx).unwrap()
|
||||
|
@ -138,7 +138,7 @@ impl<'a, 'tcx, T: Decodable> Lazy<T> {
|
|||
}
|
||||
|
||||
impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> {
|
||||
pub fn decode<M: Metadata<'a, 'tcx>>(
|
||||
crate fn decode<M: Metadata<'a, 'tcx>>(
|
||||
self,
|
||||
meta: M,
|
||||
) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
|
||||
|
@ -149,11 +149,11 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
|
||||
pub fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx.expect("missing TyCtxt in DecodeContext")
|
||||
}
|
||||
|
||||
pub fn cdata(&self) -> &'a CrateMetadata {
|
||||
fn cdata(&self) -> &'a CrateMetadata {
|
||||
self.cdata.expect("missing CrateMetadata in DecodeContext")
|
||||
}
|
||||
|
||||
|
@ -379,15 +379,15 @@ for DecodeContext<'a, 'tcx> {
|
|||
implement_ty_decoder!( DecodeContext<'a, 'tcx> );
|
||||
|
||||
impl<'tcx> MetadataBlob {
|
||||
pub fn is_compatible(&self) -> bool {
|
||||
crate fn is_compatible(&self) -> bool {
|
||||
self.raw_bytes().starts_with(METADATA_HEADER)
|
||||
}
|
||||
|
||||
pub fn get_rustc_version(&self) -> String {
|
||||
crate fn get_rustc_version(&self) -> String {
|
||||
Lazy::<String>::from_position(METADATA_HEADER.len() + 4).decode(self)
|
||||
}
|
||||
|
||||
pub fn get_root(&self) -> CrateRoot<'tcx> {
|
||||
crate fn get_root(&self) -> CrateRoot<'tcx> {
|
||||
let slice = self.raw_bytes();
|
||||
let offset = METADATA_HEADER.len();
|
||||
let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) |
|
||||
|
@ -396,7 +396,7 @@ impl<'tcx> MetadataBlob {
|
|||
Lazy::<CrateRoot<'tcx>>::from_position(pos).decode(self)
|
||||
}
|
||||
|
||||
pub fn list_crate_metadata(&self,
|
||||
crate fn list_crate_metadata(&self,
|
||||
out: &mut dyn io::Write) -> io::Result<()> {
|
||||
write!(out, "=External Dependencies=\n")?;
|
||||
let root = self.get_root();
|
||||
|
@ -449,7 +449,7 @@ impl<'tcx> EntryKind<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> CrateMetadata {
|
||||
pub fn is_proc_macro_crate(&self) -> bool {
|
||||
crate fn is_proc_macro_crate(&self) -> bool {
|
||||
self.root.proc_macro_decls_static.is_some()
|
||||
}
|
||||
|
||||
|
@ -499,7 +499,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
&self.raw_proc_macros.unwrap()[pos]
|
||||
}
|
||||
|
||||
pub fn item_name(&self, item_index: DefIndex) -> Symbol {
|
||||
crate fn item_name(&self, item_index: DefIndex) -> Symbol {
|
||||
if !self.is_proc_macro(item_index) {
|
||||
self.def_key(item_index)
|
||||
.disambiguated_data
|
||||
|
@ -512,7 +512,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
|
||||
crate fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
|
||||
if !self.is_proc_macro(index) {
|
||||
self.entry(index).kind.def_kind()
|
||||
} else {
|
||||
|
@ -522,7 +522,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
|
||||
crate fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
|
||||
self.entry(index).span.decode((self, sess))
|
||||
}
|
||||
|
||||
|
@ -556,7 +556,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||
crate fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||
match self.entry(item_id).kind {
|
||||
EntryKind::Trait(data) => {
|
||||
let data = data.decode((self, sess));
|
||||
|
@ -622,7 +622,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
|
||||
crate fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
|
||||
let item = self.entry(item_id);
|
||||
let did = self.local_def_id(item_id);
|
||||
|
||||
|
@ -647,7 +647,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
tcx.alloc_adt_def(did, kind, variants, repr)
|
||||
}
|
||||
|
||||
pub fn get_predicates(
|
||||
crate fn get_predicates(
|
||||
&self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -655,7 +655,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.entry(item_id).predicates.unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
pub fn get_predicates_defined_on(
|
||||
crate fn get_predicates_defined_on(
|
||||
&self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -663,7 +663,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
pub fn get_super_predicates(
|
||||
crate fn get_super_predicates(
|
||||
&self,
|
||||
item_id: DefIndex,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -677,30 +677,27 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
super_predicates.decode((self, tcx))
|
||||
}
|
||||
|
||||
pub fn get_generics(&self,
|
||||
item_id: DefIndex,
|
||||
sess: &Session)
|
||||
-> ty::Generics {
|
||||
crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
self.entry(item_id).generics.unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
crate fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.entry(id).ty.unwrap().decode((self, tcx))
|
||||
}
|
||||
|
||||
pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
crate fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
match self.is_proc_macro(id) {
|
||||
true => self.root.proc_macro_stability.clone(),
|
||||
false => self.entry(id).stability.map(|stab| stab.decode(self)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
|
||||
crate fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
|
||||
self.entry_unless_proc_macro(id)
|
||||
.and_then(|entry| entry.deprecation.map(|depr| depr.decode(self)))
|
||||
}
|
||||
|
||||
pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
|
||||
crate fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
|
||||
match self.is_proc_macro(id) {
|
||||
true => ty::Visibility::Public,
|
||||
false => self.entry(id).visibility.decode(self),
|
||||
|
@ -714,30 +711,31 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
|
||||
crate fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
|
||||
self.get_impl_data(id).parent_impl
|
||||
}
|
||||
|
||||
pub fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
|
||||
crate fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
|
||||
self.get_impl_data(id).polarity
|
||||
}
|
||||
|
||||
pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
|
||||
crate fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
|
||||
self.get_impl_data(id).defaultness
|
||||
}
|
||||
|
||||
pub fn get_coerce_unsized_info(&self,
|
||||
id: DefIndex)
|
||||
-> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||
crate fn get_coerce_unsized_info(
|
||||
&self,
|
||||
id: DefIndex,
|
||||
) -> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||
self.get_impl_data(id).coerce_unsized_info
|
||||
}
|
||||
|
||||
pub fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
|
||||
crate fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
|
||||
self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx)))
|
||||
}
|
||||
|
||||
/// Iterates over all the stability attributes in the given crate.
|
||||
pub fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(ast::Name, Option<ast::Name>)] {
|
||||
crate fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(ast::Name, Option<ast::Name>)] {
|
||||
// FIXME: For a proc macro crate, not sure whether we should return the "host"
|
||||
// features or an empty Vec. Both don't cause ICEs.
|
||||
tcx.arena.alloc_from_iter(self.root
|
||||
|
@ -746,7 +744,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
/// Iterates over the language items in the given crate.
|
||||
pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
|
||||
crate fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not export any lang-items to the target.
|
||||
&[]
|
||||
|
@ -759,7 +757,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
/// Iterates over the diagnostic items in the given crate.
|
||||
pub fn get_diagnostic_items(
|
||||
crate fn get_diagnostic_items(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx FxHashMap<Symbol, DefId> {
|
||||
|
@ -776,7 +774,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
/// Iterates over each child of the given item.
|
||||
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
|
||||
crate fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
|
||||
where F: FnMut(def::Export<hir::HirId>)
|
||||
{
|
||||
if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) {
|
||||
|
@ -911,12 +909,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
|
||||
crate fn is_item_mir_available(&self, id: DefIndex) -> bool {
|
||||
!self.is_proc_macro(id) &&
|
||||
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
|
||||
}
|
||||
|
||||
pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
crate fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
self.entry_unless_proc_macro(id)
|
||||
.and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx))))
|
||||
.unwrap_or_else(|| {
|
||||
|
@ -924,7 +922,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_promoted_mir(
|
||||
crate fn get_promoted_mir(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
|
@ -936,7 +934,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
|
||||
crate fn mir_const_qualif(&self, id: DefIndex) -> u8 {
|
||||
match self.entry(id).kind {
|
||||
EntryKind::Const(qualif, _) |
|
||||
EntryKind::AssocConst(AssocContainer::ImplDefault, qualif, _) |
|
||||
|
@ -947,7 +945,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
|
||||
crate fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
|
||||
let item = self.entry(id);
|
||||
let def_key = self.def_key(id);
|
||||
let parent = self.local_def_id(def_key.parent.unwrap());
|
||||
|
@ -981,11 +979,11 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
|
||||
crate fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
|
||||
self.entry(id).variances.decode(self).collect()
|
||||
}
|
||||
|
||||
pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
|
||||
crate fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
|
||||
match self.entry(node_id).kind {
|
||||
EntryKind::Struct(data, _) |
|
||||
EntryKind::Union(data, _) |
|
||||
|
@ -994,7 +992,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
|
||||
crate fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
|
||||
match self.entry(node_id).kind {
|
||||
EntryKind::Struct(data, _) => {
|
||||
data.decode(self).ctor.map(|index| self.local_def_id(index))
|
||||
|
@ -1006,8 +1004,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
|
||||
crate fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
|
||||
// The attributes for a tuple struct/variant are attached to the definition, not the ctor;
|
||||
// we assume that someone passing in a tuple struct ctor is actually wanting to
|
||||
// look at the definition
|
||||
|
@ -1022,7 +1019,11 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
Lrc::from(self.get_attributes(&item, sess))
|
||||
}
|
||||
|
||||
pub fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<ast::Name>> {
|
||||
crate fn get_struct_field_names(
|
||||
&self,
|
||||
id: DefIndex,
|
||||
sess: &Session,
|
||||
) -> Vec<Spanned<ast::Name>> {
|
||||
self.entry(id)
|
||||
.children
|
||||
.decode(self)
|
||||
|
@ -1049,7 +1050,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn get_inherent_implementations_for_type(
|
||||
crate fn get_inherent_implementations_for_type(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: DefIndex,
|
||||
|
@ -1060,7 +1061,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
.map(|index| self.local_def_id(index)))
|
||||
}
|
||||
|
||||
pub fn get_implementations_for_trait(
|
||||
crate fn get_implementations_for_trait(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
filter: Option<DefId>,
|
||||
|
@ -1091,7 +1092,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
|
||||
crate fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
|
||||
let def_key = self.def_key(id);
|
||||
match def_key.disambiguated_data.data {
|
||||
DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
|
||||
|
@ -1108,7 +1109,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
|
||||
pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
|
||||
crate fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* native libraries.
|
||||
vec![]
|
||||
|
@ -1117,7 +1118,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
|
||||
crate fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not have any *target* foreign modules.
|
||||
&[]
|
||||
|
@ -1126,7 +1127,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_dylib_dependency_formats(
|
||||
crate fn get_dylib_dependency_formats(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx [(CrateNum, LinkagePreference)] {
|
||||
|
@ -1140,7 +1141,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}))
|
||||
}
|
||||
|
||||
pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
|
||||
crate fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
|
||||
if self.is_proc_macro_crate() {
|
||||
// Proc macro crates do not depend on any target weak lang-items.
|
||||
&[]
|
||||
|
@ -1151,7 +1152,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_fn_param_names(&self, id: DefIndex) -> Vec<ast::Name> {
|
||||
crate fn get_fn_param_names(&self, id: DefIndex) -> Vec<ast::Name> {
|
||||
let param_names = match self.entry(id).kind {
|
||||
EntryKind::Fn(data) |
|
||||
EntryKind::ForeignFn(data) => data.decode(self).param_names,
|
||||
|
@ -1161,7 +1162,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
param_names.decode(self).collect()
|
||||
}
|
||||
|
||||
pub fn exported_symbols(
|
||||
crate fn exported_symbols(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
|
||||
|
@ -1174,7 +1175,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_rendered_const(&self, id: DefIndex) -> String {
|
||||
crate fn get_rendered_const(&self, id: DefIndex) -> String {
|
||||
match self.entry(id).kind {
|
||||
EntryKind::Const(_, data) |
|
||||
EntryKind::AssocConst(_, _, data) => data.decode(self).0,
|
||||
|
@ -1182,7 +1183,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_macro(&self, id: DefIndex) -> MacroDef {
|
||||
crate fn get_macro(&self, id: DefIndex) -> MacroDef {
|
||||
let entry = self.entry(id);
|
||||
match entry.kind {
|
||||
EntryKind::MacroDef(macro_def) => macro_def.decode(self),
|
||||
|
@ -1200,7 +1201,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
constness == hir::Constness::Const
|
||||
}
|
||||
|
||||
pub fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
|
||||
crate fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
|
||||
match self.entry(id).kind {
|
||||
EntryKind::Fn(data) => data.decode(self).asyncness,
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.asyncness,
|
||||
|
@ -1209,7 +1210,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_foreign_item(&self, id: DefIndex) -> bool {
|
||||
crate fn is_foreign_item(&self, id: DefIndex) -> bool {
|
||||
match self.entry(id).kind {
|
||||
EntryKind::ForeignImmStatic |
|
||||
EntryKind::ForeignMutStatic |
|
||||
|
@ -1228,7 +1229,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
crate fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
let sig = match self.entry(id).kind {
|
||||
EntryKind::Fn(data) |
|
||||
EntryKind::ForeignFn(data) => data.decode(self).sig,
|
||||
|
@ -1242,7 +1243,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn def_key(&self, index: DefIndex) -> DefKey {
|
||||
crate fn def_key(&self, index: DefIndex) -> DefKey {
|
||||
let mut key = self.def_path_table.def_key(index);
|
||||
if self.is_proc_macro(index) {
|
||||
let name = self.raw_proc_macro(index).name();
|
||||
|
@ -1252,13 +1253,13 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
// Returns the path leading to the thing with this `id`.
|
||||
pub fn def_path(&self, id: DefIndex) -> DefPath {
|
||||
crate fn def_path(&self, id: DefIndex) -> DefPath {
|
||||
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
|
||||
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
|
||||
crate fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
|
||||
self.def_path_table.def_path_hash(index)
|
||||
}
|
||||
|
||||
|
@ -1287,9 +1288,10 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
///
|
||||
/// Proc macro crates don't currently export spans, so this function does not have
|
||||
/// to work for them.
|
||||
pub fn imported_source_files(&'a self,
|
||||
local_source_map: &source_map::SourceMap)
|
||||
-> ReadGuard<'a, Vec<cstore::ImportedSourceFile>> {
|
||||
fn imported_source_files(
|
||||
&'a self,
|
||||
local_source_map: &source_map::SourceMap,
|
||||
) -> ReadGuard<'a, Vec<cstore::ImportedSourceFile>> {
|
||||
{
|
||||
let source_files = self.source_map_import_info.borrow();
|
||||
if !source_files.is_empty() {
|
||||
|
|
|
@ -60,7 +60,7 @@ use rustc::ty::TyCtxt;
|
|||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
pub fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
|
||||
crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
|
||||
tcx.sess.crate_types.borrow().iter().map(|&ty| {
|
||||
let linkage = calculate_type(tcx, ty);
|
||||
verify_ok(tcx, &linkage);
|
||||
|
|
|
@ -32,30 +32,6 @@ impl DynamicLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads a dynamic library into the global namespace (RTLD_GLOBAL on Unix)
|
||||
/// and do it now (don't use RTLD_LAZY on Unix).
|
||||
pub fn open_global_now(filename: &Path) -> Result<DynamicLibrary, String> {
|
||||
let maybe_library = dl::open_global_now(filename.as_os_str());
|
||||
match maybe_library {
|
||||
Err(err) => Err(err),
|
||||
Ok(handle) => Ok(DynamicLibrary { handle })
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the environment variable for this process's dynamic library
|
||||
/// search path
|
||||
pub fn envvar() -> &'static str {
|
||||
if cfg!(windows) {
|
||||
"PATH"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
} else if cfg!(target_os = "haiku") {
|
||||
"LIBRARY_PATH"
|
||||
} else {
|
||||
"LD_LIBRARY_PATH"
|
||||
}
|
||||
}
|
||||
|
||||
/// Accesses the value at the symbol of the dynamic library.
|
||||
pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
|
||||
// This function should have a lifetime constraint of 'a on
|
||||
|
@ -83,7 +59,7 @@ mod dl {
|
|||
use std::ptr;
|
||||
use std::str;
|
||||
|
||||
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
||||
pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
||||
check_for_errors_in(|| {
|
||||
unsafe {
|
||||
match filename {
|
||||
|
@ -94,13 +70,6 @@ mod dl {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
|
||||
check_for_errors_in(|| unsafe {
|
||||
let s = CString::new(filename.as_bytes()).unwrap();
|
||||
libc::dlopen(s.as_ptr(), libc::RTLD_GLOBAL | libc::RTLD_NOW) as *mut u8
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn open_external(filename: &OsStr) -> *mut u8 {
|
||||
let s = CString::new(filename.as_bytes()).unwrap();
|
||||
libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8
|
||||
|
@ -110,8 +79,8 @@ mod dl {
|
|||
libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8
|
||||
}
|
||||
|
||||
pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
|
||||
F: FnOnce() -> T,
|
||||
fn check_for_errors_in<T, F>(f: F) -> Result<T, String>
|
||||
where F: FnOnce() -> T,
|
||||
{
|
||||
use std::sync::{Mutex, Once};
|
||||
static INIT: Once = Once::new();
|
||||
|
@ -139,14 +108,15 @@ mod dl {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn symbol(handle: *mut u8,
|
||||
symbol: *const libc::c_char)
|
||||
-> Result<*mut u8, String> {
|
||||
pub(super) unsafe fn symbol(
|
||||
handle: *mut u8,
|
||||
symbol: *const libc::c_char,
|
||||
) -> Result<*mut u8, String> {
|
||||
check_for_errors_in(|| {
|
||||
libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8
|
||||
})
|
||||
}
|
||||
pub unsafe fn close(handle: *mut u8) {
|
||||
pub(super) unsafe fn close(handle: *mut u8) {
|
||||
libc::dlclose(handle as *mut libc::c_void); ()
|
||||
}
|
||||
}
|
||||
|
@ -178,11 +148,7 @@ mod dl {
|
|||
fn FreeLibrary(handle: HMODULE) -> BOOL;
|
||||
}
|
||||
|
||||
pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
|
||||
open(Some(filename))
|
||||
}
|
||||
|
||||
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
||||
pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
|
||||
// disable "dll load failed" error dialog.
|
||||
let prev_error_mode = unsafe {
|
||||
// SEM_FAILCRITICALERRORS 0x01
|
||||
|
@ -225,14 +191,15 @@ mod dl {
|
|||
result
|
||||
}
|
||||
|
||||
pub unsafe fn symbol(handle: *mut u8,
|
||||
symbol: *const c_char)
|
||||
-> Result<*mut u8, String> {
|
||||
pub(super) unsafe fn symbol(
|
||||
handle: *mut u8,
|
||||
symbol: *const c_char,
|
||||
) -> Result<*mut u8, String> {
|
||||
let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
|
||||
ptr_result(ptr)
|
||||
}
|
||||
|
||||
pub unsafe fn close(handle: *mut u8) {
|
||||
pub(super) unsafe fn close(handle: *mut u8) {
|
||||
FreeLibrary(handle as HMODULE);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc::middle::cstore::{LinkagePreference, NativeLibrary,
|
|||
EncodedMetadata, ForeignModule};
|
||||
use rustc::hir::def::CtorKind;
|
||||
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc::hir::GenericParamKind;
|
||||
use rustc::hir::{GenericParamKind, AnonConst};
|
||||
use rustc::hir::map::definitions::DefPathTable;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_index::vec::IndexVec;
|
||||
|
@ -42,9 +42,9 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
|||
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use rustc::hir::intravisit;
|
||||
|
||||
pub struct EncodeContext<'tcx> {
|
||||
struct EncodeContext<'tcx> {
|
||||
opaque: opaque::Encoder,
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
entries_index: Index<'tcx>,
|
||||
|
||||
|
@ -313,11 +313,12 @@ impl<'tcx> EncodeContext<'tcx> {
|
|||
/// the `Entry` (which may point to other encoded information)
|
||||
/// and will then record the `Lazy<Entry>` for use in the index.
|
||||
// FIXME(eddyb) remove this.
|
||||
pub fn record<DATA>(&mut self,
|
||||
id: DefId,
|
||||
op: impl FnOnce(&mut Self, DATA) -> Entry<'tcx>,
|
||||
data: DATA)
|
||||
{
|
||||
fn record<DATA>(
|
||||
&mut self,
|
||||
id: DefId,
|
||||
op: impl FnOnce(&mut Self, DATA) -> Entry<'tcx>,
|
||||
data: DATA,
|
||||
) {
|
||||
assert!(id.is_local());
|
||||
|
||||
let entry = op(self, data);
|
||||
|
@ -1711,6 +1712,11 @@ impl Visitor<'tcx> for EncodeContext<'tcx> {
|
|||
intravisit::walk_expr(self, ex);
|
||||
self.encode_info_for_expr(ex);
|
||||
}
|
||||
fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
|
||||
intravisit::walk_anon_const(self, c);
|
||||
let def_id = self.tcx.hir().local_def_id(c.hir_id);
|
||||
self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
|
||||
}
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
intravisit::walk_item(self, item);
|
||||
let def_id = self.tcx.hir().local_def_id(item.hir_id);
|
||||
|
@ -1728,25 +1734,10 @@ impl Visitor<'tcx> for EncodeContext<'tcx> {
|
|||
EncodeContext::encode_info_for_foreign_item,
|
||||
(def_id, ni));
|
||||
}
|
||||
fn visit_variant(&mut self,
|
||||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
id: hir::HirId) {
|
||||
intravisit::walk_variant(self, v, g, id);
|
||||
|
||||
if let Some(ref discr) = v.disr_expr {
|
||||
let def_id = self.tcx.hir().local_def_id(discr.hir_id);
|
||||
self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
|
||||
}
|
||||
}
|
||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
||||
intravisit::walk_generics(self, generics);
|
||||
self.encode_info_for_generics(generics);
|
||||
}
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
||||
intravisit::walk_ty(self, ty);
|
||||
self.encode_info_for_ty(ty);
|
||||
}
|
||||
fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
|
||||
let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
|
||||
self.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def);
|
||||
|
@ -1784,16 +1775,6 @@ impl EncodeContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
|
||||
match ty.kind {
|
||||
hir::TyKind::Array(_, ref length) => {
|
||||
let def_id = self.tcx.hir().local_def_id(length.hir_id);
|
||||
self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Closure(..) => {
|
||||
|
@ -1920,7 +1901,7 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
|
|||
// will allow us to slice the metadata to the precise length that we just
|
||||
// generated regardless of trailing bytes that end up in it.
|
||||
|
||||
pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
|
||||
crate fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
|
||||
let mut encoder = opaque::Encoder::new(vec![]);
|
||||
encoder.emit_raw_bytes(METADATA_HEADER);
|
||||
|
||||
|
@ -1962,7 +1943,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
|
|||
EncodedMetadata { raw_data: result }
|
||||
}
|
||||
|
||||
pub fn get_repr_options(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
|
||||
fn get_repr_options(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
|
||||
let ty = tcx.type_of(did);
|
||||
match ty.kind {
|
||||
ty::Adt(ref def, _) => return def.repr,
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustc::hir;
|
|||
use rustc::middle::cstore::ForeignModule;
|
||||
use rustc::ty::TyCtxt;
|
||||
|
||||
pub fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
|
||||
crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
|
||||
let mut collector = Collector {
|
||||
tcx,
|
||||
modules: Vec::new(),
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::u32;
|
|||
use log::debug;
|
||||
|
||||
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
|
||||
pub trait FixedSizeEncoding {
|
||||
trait FixedSizeEncoding {
|
||||
const BYTE_LEN: usize;
|
||||
|
||||
// FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
|
||||
|
@ -75,25 +75,25 @@ impl FixedSizeEncoding for u32 {
|
|||
/// `u32::MAX`. Whenever an index is visited, we fill in the
|
||||
/// appropriate spot by calling `record_position`. We should never
|
||||
/// visit the same index twice.
|
||||
pub struct Index<'tcx> {
|
||||
crate struct Index<'tcx> {
|
||||
positions: Vec<u8>,
|
||||
_marker: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
impl Index<'tcx> {
|
||||
pub fn new(max_index: usize) -> Self {
|
||||
crate fn new(max_index: usize) -> Self {
|
||||
Index {
|
||||
positions: vec![0xff; max_index * 4],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'tcx>>) {
|
||||
crate fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'tcx>>) {
|
||||
assert!(def_id.is_local());
|
||||
self.record_index(def_id.index, entry);
|
||||
}
|
||||
|
||||
pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'tcx>>) {
|
||||
fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'tcx>>) {
|
||||
assert!(entry.position < (u32::MAX as usize));
|
||||
let position = entry.position as u32;
|
||||
let array_index = item.index();
|
||||
|
@ -108,7 +108,7 @@ impl Index<'tcx> {
|
|||
position.write_to_bytes_at(positions, array_index)
|
||||
}
|
||||
|
||||
pub fn write_index(&self, buf: &mut Encoder) -> Lazy<[Self]> {
|
||||
crate fn write_index(&self, buf: &mut Encoder) -> Lazy<[Self]> {
|
||||
let pos = buf.position();
|
||||
|
||||
// First we write the length of the lower range ...
|
||||
|
@ -123,7 +123,7 @@ impl Lazy<[Index<'tcx>]> {
|
|||
/// Given the metadata, extract out the offset of a particular
|
||||
/// DefIndex (if any).
|
||||
#[inline(never)]
|
||||
pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
|
||||
crate fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
|
||||
let bytes = &bytes[self.position..];
|
||||
debug!("Index::lookup: index={:?} len={:?}",
|
||||
def_index,
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc::ty::TyCtxt;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::symbol::sym;
|
||||
|
||||
pub fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
|
||||
crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
|
||||
let mut collector = Collector {
|
||||
args: Vec::new(),
|
||||
};
|
||||
|
|
|
@ -212,13 +212,14 @@
|
|||
//! no means all of the necessary details. Take a look at the rest of
|
||||
//! metadata::locator or metadata::creader for all the juicy details!
|
||||
|
||||
use crate::cstore::{MetadataRef, MetadataBlob};
|
||||
use crate::cstore::{MetadataBlob, CStore};
|
||||
use crate::creader::Library;
|
||||
use crate::schema::{METADATA_HEADER, rustc_version};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc::middle::cstore::MetadataLoader;
|
||||
use rustc_data_structures::sync::MetadataRef;
|
||||
use rustc::middle::cstore::{CrateSource, MetadataLoader};
|
||||
use rustc::session::{config, Session};
|
||||
use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
|
||||
use rustc::session::search_paths::PathKind;
|
||||
|
@ -245,13 +246,13 @@ use rustc_data_structures::owning_ref::OwningRef;
|
|||
use log::{debug, info, warn};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CrateMismatch {
|
||||
crate struct CrateMismatch {
|
||||
path: PathBuf,
|
||||
got: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context<'a> {
|
||||
crate struct Context<'a> {
|
||||
pub sess: &'a Session,
|
||||
pub span: Span,
|
||||
pub crate_name: Symbol,
|
||||
|
@ -272,11 +273,9 @@ pub struct Context<'a> {
|
|||
pub metadata_loader: &'a dyn MetadataLoader,
|
||||
}
|
||||
|
||||
pub struct CratePaths {
|
||||
pub ident: String,
|
||||
pub dylib: Option<PathBuf>,
|
||||
pub rlib: Option<PathBuf>,
|
||||
pub rmeta: Option<PathBuf>,
|
||||
crate struct CratePaths {
|
||||
pub name: Symbol,
|
||||
pub source: CrateSource,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
|
@ -296,14 +295,8 @@ impl fmt::Display for CrateFlavor {
|
|||
}
|
||||
}
|
||||
|
||||
impl CratePaths {
|
||||
fn paths(&self) -> Vec<PathBuf> {
|
||||
self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn reset(&mut self) {
|
||||
crate fn reset(&mut self) {
|
||||
self.rejected_via_hash.clear();
|
||||
self.rejected_via_triple.clear();
|
||||
self.rejected_via_kind.clear();
|
||||
|
@ -311,7 +304,7 @@ impl<'a> Context<'a> {
|
|||
self.rejected_via_filename.clear();
|
||||
}
|
||||
|
||||
pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
|
||||
crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
|
||||
let mut seen_paths = FxHashSet::default();
|
||||
match self.extra_filename {
|
||||
Some(s) => self.find_library_crate(s, &mut seen_paths)
|
||||
|
@ -320,10 +313,10 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn report_errs(self) -> ! {
|
||||
crate fn report_errs(self) -> ! {
|
||||
let add = match self.root {
|
||||
None => String::new(),
|
||||
Some(r) => format!(" which `{}` depends on", r.ident),
|
||||
Some(r) => format!(" which `{}` depends on", r.name),
|
||||
};
|
||||
let mut msg = "the following crate versions were found:".to_string();
|
||||
let mut err = if !self.rejected_via_hash.is_empty() {
|
||||
|
@ -341,8 +334,8 @@ impl<'a> Context<'a> {
|
|||
match self.root {
|
||||
None => {}
|
||||
Some(r) => {
|
||||
for path in r.paths().iter() {
|
||||
msg.push_str(&format!("\ncrate `{}`: {}", r.ident, path.display()));
|
||||
for path in r.source.paths() {
|
||||
msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -534,18 +527,8 @@ impl<'a> Context<'a> {
|
|||
// search is being performed for.
|
||||
let mut libraries = FxHashMap::default();
|
||||
for (_hash, (rlibs, rmetas, dylibs)) in candidates {
|
||||
let mut slot = None;
|
||||
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
|
||||
let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
|
||||
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
|
||||
if let Some((h, m)) = slot {
|
||||
libraries.insert(h,
|
||||
Library {
|
||||
dylib,
|
||||
rlib,
|
||||
rmeta,
|
||||
metadata: m,
|
||||
});
|
||||
if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs) {
|
||||
libraries.insert(svh, lib);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,7 +546,7 @@ impl<'a> Context<'a> {
|
|||
self.crate_name);
|
||||
let candidates = libraries.iter().filter_map(|(_, lib)| {
|
||||
let crate_name = &lib.metadata.get_root().name.as_str();
|
||||
match &(&lib.dylib, &lib.rlib) {
|
||||
match &(&lib.source.dylib, &lib.source.rlib) {
|
||||
&(&Some((ref pd, _)), &Some((ref pr, _))) => {
|
||||
Some(format!("\ncrate `{}`: {}\n{:>padding$}",
|
||||
crate_name,
|
||||
|
@ -584,6 +567,21 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn extract_lib(
|
||||
&mut self,
|
||||
rlibs: FxHashMap<PathBuf, PathKind>,
|
||||
rmetas: FxHashMap<PathBuf, PathKind>,
|
||||
dylibs: FxHashMap<PathBuf, PathKind>,
|
||||
) -> Option<(Svh, Library)> {
|
||||
let mut slot = None;
|
||||
let source = CrateSource {
|
||||
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
|
||||
rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
|
||||
dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
|
||||
};
|
||||
slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
|
||||
}
|
||||
|
||||
// Attempts to extract *one* library from the set `m`. If the set has no
|
||||
// elements, `None` is returned. If the set has more than one element, then
|
||||
// the errors and notes are emitted about the set of libraries.
|
||||
|
@ -828,23 +826,8 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
// Extract the rlib/dylib pair.
|
||||
let mut slot = None;
|
||||
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
|
||||
let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
|
||||
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
|
||||
|
||||
if rlib.is_none() && rmeta.is_none() && dylib.is_none() {
|
||||
return None;
|
||||
}
|
||||
slot.map(|(_, metadata)|
|
||||
Library {
|
||||
dylib,
|
||||
rlib,
|
||||
rmeta,
|
||||
metadata,
|
||||
}
|
||||
)
|
||||
// Extract the dylib/rlib/rmeta triple.
|
||||
self.extract_lib(rlibs, rmetas, dylibs).map(|(_, lib)| lib)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -931,7 +914,7 @@ fn get_metadata_section_imp(target: &Target,
|
|||
/// A diagnostic function for dumping crate metadata to an output stream.
|
||||
pub fn list_file_metadata(target: &Target,
|
||||
path: &Path,
|
||||
loader: &dyn MetadataLoader,
|
||||
cstore: &CStore,
|
||||
out: &mut dyn io::Write)
|
||||
-> io::Result<()> {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
|
@ -942,7 +925,7 @@ pub fn list_file_metadata(target: &Target,
|
|||
} else {
|
||||
CrateFlavor::Dylib
|
||||
};
|
||||
match get_metadata_section(target, flavor, path, loader) {
|
||||
match get_metadata_section(target, flavor, path, &*cstore.metadata_loader) {
|
||||
Ok(metadata) => metadata.list_crate_metadata(out),
|
||||
Err(msg) => write!(out, "{}\n", msg),
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use syntax::feature_gate::{self, GateIssue};
|
|||
use syntax::symbol::{kw, sym, Symbol};
|
||||
use syntax::{span_err, struct_span_err};
|
||||
|
||||
pub fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
|
||||
crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
|
||||
let mut collector = Collector {
|
||||
tcx,
|
||||
libs: Vec::new(),
|
||||
|
@ -21,7 +21,7 @@ pub fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
|
|||
return collector.libs;
|
||||
}
|
||||
|
||||
pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
|
||||
crate fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
|
||||
match lib.cfg {
|
||||
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
|
||||
None => true,
|
||||
|
|
|
@ -21,7 +21,7 @@ use syntax_pos::{self, Span};
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub fn rustc_version() -> String {
|
||||
crate fn rustc_version() -> String {
|
||||
format!("rustc {}",
|
||||
option_env!("CFG_VERSION").unwrap_or("unknown version"))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn rustc_version() -> String {
|
|||
/// Metadata encoding version.
|
||||
/// N.B., increment this if you change the format of metadata such that
|
||||
/// the rustc version can't be found to compare with `rustc_version()`.
|
||||
pub const METADATA_VERSION: u8 = 4;
|
||||
const METADATA_VERSION: u8 = 4;
|
||||
|
||||
/// Metadata header which includes `METADATA_VERSION`.
|
||||
/// To get older versions of rustc to ignore this metadata,
|
||||
|
@ -39,12 +39,12 @@ pub const METADATA_VERSION: u8 = 4;
|
|||
/// This header is followed by the position of the `CrateRoot`,
|
||||
/// which is encoded as a 32-bit big-endian unsigned integer,
|
||||
/// and further followed by the rustc version string.
|
||||
pub const METADATA_HEADER: &[u8; 12] =
|
||||
crate const METADATA_HEADER: &[u8; 12] =
|
||||
&[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
|
||||
|
||||
/// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
|
||||
/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
|
||||
pub trait LazyMeta {
|
||||
crate trait LazyMeta {
|
||||
type Meta: Copy + 'static;
|
||||
|
||||
/// Returns the minimum encoded size.
|
||||
|
@ -98,7 +98,7 @@ impl<T> LazyMeta for [T] {
|
|||
#[must_use]
|
||||
// FIXME(#59875) the `Meta` parameter only exists to dodge
|
||||
// invariance wrt `T` (coming from the `meta: T::Meta` field).
|
||||
pub struct Lazy<T, Meta = <T as LazyMeta>::Meta>
|
||||
crate struct Lazy<T, Meta = <T as LazyMeta>::Meta>
|
||||
where T: ?Sized + LazyMeta<Meta = Meta>,
|
||||
Meta: 'static + Copy,
|
||||
{
|
||||
|
@ -108,7 +108,7 @@ pub struct Lazy<T, Meta = <T as LazyMeta>::Meta>
|
|||
}
|
||||
|
||||
impl<T: ?Sized + LazyMeta> Lazy<T> {
|
||||
pub fn from_position_and_meta(position: usize, meta: T::Meta) -> Lazy<T> {
|
||||
crate fn from_position_and_meta(position: usize, meta: T::Meta) -> Lazy<T> {
|
||||
Lazy {
|
||||
position,
|
||||
meta,
|
||||
|
@ -118,13 +118,13 @@ impl<T: ?Sized + LazyMeta> Lazy<T> {
|
|||
}
|
||||
|
||||
impl<T> Lazy<T> {
|
||||
pub fn from_position(position: usize) -> Lazy<T> {
|
||||
crate fn from_position(position: usize) -> Lazy<T> {
|
||||
Lazy::from_position_and_meta(position, ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lazy<[T]> {
|
||||
pub fn empty() -> Lazy<[T]> {
|
||||
crate fn empty() -> Lazy<[T]> {
|
||||
Lazy::from_position_and_meta(0, 0)
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ impl<T: ?Sized + LazyMeta> rustc_serialize::UseSpecializedDecodable for Lazy<T>
|
|||
|
||||
/// Encoding / decoding state for `Lazy`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum LazyState {
|
||||
crate enum LazyState {
|
||||
/// Outside of a metadata node.
|
||||
NoNode,
|
||||
|
||||
|
@ -156,7 +156,7 @@ pub enum LazyState {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct CrateRoot<'tcx> {
|
||||
crate struct CrateRoot<'tcx> {
|
||||
pub name: Symbol,
|
||||
pub triple: TargetTriple,
|
||||
pub extra_filename: String,
|
||||
|
@ -202,7 +202,7 @@ pub struct CrateRoot<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct CrateDep {
|
||||
crate struct CrateDep {
|
||||
pub name: ast::Name,
|
||||
pub hash: Svh,
|
||||
pub kind: DepKind,
|
||||
|
@ -210,13 +210,13 @@ pub struct CrateDep {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct TraitImpls {
|
||||
crate struct TraitImpls {
|
||||
pub trait_id: (u32, DefIndex),
|
||||
pub impls: Lazy<[DefIndex]>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct Entry<'tcx> {
|
||||
crate struct Entry<'tcx> {
|
||||
pub kind: EntryKind<'tcx>,
|
||||
pub visibility: Lazy<ty::Visibility>,
|
||||
pub span: Lazy<Span>,
|
||||
|
@ -237,7 +237,7 @@ pub struct Entry<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum EntryKind<'tcx> {
|
||||
crate enum EntryKind<'tcx> {
|
||||
Const(ConstQualif, Lazy<RenderedConst>),
|
||||
ImmStatic,
|
||||
MutStatic,
|
||||
|
@ -272,28 +272,28 @@ pub enum EntryKind<'tcx> {
|
|||
|
||||
/// Additional data for EntryKind::Const and EntryKind::AssocConst
|
||||
#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
|
||||
pub struct ConstQualif {
|
||||
crate struct ConstQualif {
|
||||
pub mir: u8,
|
||||
}
|
||||
|
||||
/// Contains a constant which has been rendered to a String.
|
||||
/// Used by rustdoc.
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct RenderedConst(pub String);
|
||||
crate struct RenderedConst(pub String);
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct ModData {
|
||||
crate struct ModData {
|
||||
pub reexports: Lazy<[def::Export<hir::HirId>]>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct MacroDef {
|
||||
crate struct MacroDef {
|
||||
pub body: String,
|
||||
pub legacy: bool,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct FnData<'tcx> {
|
||||
crate struct FnData<'tcx> {
|
||||
pub asyncness: hir::IsAsync,
|
||||
pub constness: hir::Constness,
|
||||
pub param_names: Lazy<[ast::Name]>,
|
||||
|
@ -301,7 +301,7 @@ pub struct FnData<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct VariantData<'tcx> {
|
||||
crate struct VariantData<'tcx> {
|
||||
pub ctor_kind: CtorKind,
|
||||
pub discr: ty::VariantDiscr,
|
||||
/// If this is unit or tuple-variant/struct, then this is the index of the ctor id.
|
||||
|
@ -312,7 +312,7 @@ pub struct VariantData<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct TraitData<'tcx> {
|
||||
crate struct TraitData<'tcx> {
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub paren_sugar: bool,
|
||||
pub has_auto_impl: bool,
|
||||
|
@ -321,12 +321,12 @@ pub struct TraitData<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct TraitAliasData<'tcx> {
|
||||
crate struct TraitAliasData<'tcx> {
|
||||
pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct ImplData<'tcx> {
|
||||
crate struct ImplData<'tcx> {
|
||||
pub polarity: ty::ImplPolarity,
|
||||
pub defaultness: hir::Defaultness,
|
||||
pub parent_impl: Option<DefId>,
|
||||
|
@ -341,7 +341,7 @@ pub struct ImplData<'tcx> {
|
|||
/// is a trait or an impl and whether, in a trait, it has
|
||||
/// a default, or an in impl, whether it's marked "default".
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum AssocContainer {
|
||||
crate enum AssocContainer {
|
||||
TraitRequired,
|
||||
TraitWithDefault,
|
||||
ImplDefault,
|
||||
|
@ -349,7 +349,7 @@ pub enum AssocContainer {
|
|||
}
|
||||
|
||||
impl AssocContainer {
|
||||
pub fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
|
||||
crate fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
|
||||
match *self {
|
||||
AssocContainer::TraitRequired |
|
||||
AssocContainer::TraitWithDefault => ty::TraitContainer(def_id),
|
||||
|
@ -359,7 +359,7 @@ impl AssocContainer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn defaultness(&self) -> hir::Defaultness {
|
||||
crate fn defaultness(&self) -> hir::Defaultness {
|
||||
match *self {
|
||||
AssocContainer::TraitRequired => hir::Defaultness::Default {
|
||||
has_value: false,
|
||||
|
@ -376,22 +376,22 @@ impl AssocContainer {
|
|||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct MethodData<'tcx> {
|
||||
crate struct MethodData<'tcx> {
|
||||
pub fn_data: FnData<'tcx>,
|
||||
pub container: AssocContainer,
|
||||
pub has_self: bool,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureData<'tcx> {
|
||||
crate struct ClosureData<'tcx> {
|
||||
pub sig: Lazy<ty::PolyFnSig<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct GeneratorData<'tcx> {
|
||||
crate struct GeneratorData<'tcx> {
|
||||
pub layout: mir::GeneratorLayout<'tcx>,
|
||||
}
|
||||
|
||||
// Tags used for encoding Spans:
|
||||
pub const TAG_VALID_SPAN: u8 = 0;
|
||||
pub const TAG_INVALID_SPAN: u8 = 1;
|
||||
crate const TAG_VALID_SPAN: u8 = 0;
|
||||
crate const TAG_INVALID_SPAN: u8 = 1;
|
||||
|
|
|
@ -104,8 +104,7 @@ impl<'a> Resolver<'a> {
|
|||
return self.module_map[&def_id]
|
||||
}
|
||||
|
||||
let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only();
|
||||
if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
|
||||
if let Some(&module) = self.extern_module_map.get(&def_id) {
|
||||
return module;
|
||||
}
|
||||
|
||||
|
@ -121,7 +120,7 @@ impl<'a> Resolver<'a> {
|
|||
let module = self.arenas.alloc_module(ModuleData::new(
|
||||
parent, kind, def_id, ExpnId::root(), DUMMY_SP
|
||||
));
|
||||
self.extern_module_map.insert((def_id, macros_only), module);
|
||||
self.extern_module_map.insert(def_id, module);
|
||||
module
|
||||
}
|
||||
|
||||
|
@ -618,6 +617,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
let crate_id = self.r.crate_loader.process_extern_crate(
|
||||
item, &self.r.definitions
|
||||
);
|
||||
self.r.extern_crate_map.insert(item.id, crate_id);
|
||||
self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ use rustc::session::Session;
|
|||
use rustc::lint;
|
||||
use rustc::hir::def::{self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap};
|
||||
use rustc::hir::def::Namespace::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
|
||||
use rustc::hir::{TraitMap, GlobMap};
|
||||
use rustc::ty::{self, DefIdTree};
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||
|
@ -855,6 +855,8 @@ pub struct Resolver<'a> {
|
|||
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
|
||||
label_res_map: NodeMap<NodeId>,
|
||||
|
||||
/// `CrateNum` resolutions of `extern crate` items.
|
||||
pub extern_crate_map: NodeMap<CrateNum>,
|
||||
pub export_map: ExportMap<NodeId>,
|
||||
pub trait_map: TraitMap,
|
||||
|
||||
|
@ -878,7 +880,7 @@ pub struct Resolver<'a> {
|
|||
/// language items.
|
||||
empty_module: Module<'a>,
|
||||
module_map: FxHashMap<DefId, Module<'a>>,
|
||||
extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
|
||||
extern_module_map: FxHashMap<DefId, Module<'a>>,
|
||||
binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
|
||||
|
||||
/// Maps glob imports to the names of items actually imported.
|
||||
|
@ -900,7 +902,7 @@ pub struct Resolver<'a> {
|
|||
arenas: &'a ResolverArenas<'a>,
|
||||
dummy_binding: &'a NameBinding<'a>,
|
||||
|
||||
crate_loader: &'a mut CrateLoader<'a>,
|
||||
crate_loader: &'a CrateLoader<'a>,
|
||||
macro_names: FxHashSet<Ident>,
|
||||
builtin_macros: FxHashMap<Name, SyntaxExtension>,
|
||||
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
|
@ -1070,7 +1072,7 @@ impl<'a> Resolver<'a> {
|
|||
cstore: &'a CStore,
|
||||
krate: &Crate,
|
||||
crate_name: &str,
|
||||
crate_loader: &'a mut CrateLoader<'a>,
|
||||
crate_loader: &'a CrateLoader<'a>,
|
||||
arenas: &'a ResolverArenas<'a>)
|
||||
-> Resolver<'a> {
|
||||
let root_def_id = DefId::local(CRATE_DEF_INDEX);
|
||||
|
@ -1155,6 +1157,7 @@ impl<'a> Resolver<'a> {
|
|||
partial_res_map: Default::default(),
|
||||
import_res_map: Default::default(),
|
||||
label_res_map: Default::default(),
|
||||
extern_crate_map: Default::default(),
|
||||
export_map: FxHashMap::default(),
|
||||
trait_map: Default::default(),
|
||||
empty_module,
|
||||
|
|
|
@ -551,7 +551,7 @@ impl MetaItem {
|
|||
impl MetaItemKind {
|
||||
pub fn tokens(&self, span: Span) -> TokenStream {
|
||||
match *self {
|
||||
MetaItemKind::Word => TokenStream::empty(),
|
||||
MetaItemKind::Word => TokenStream::default(),
|
||||
MetaItemKind::NameValue(ref lit) => {
|
||||
let mut vec = vec![TokenTree::token(token::Eq, span).into()];
|
||||
lit.tokens().append_to_tree_and_joint_vec(&mut vec);
|
||||
|
|
|
@ -676,12 +676,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
Some(TokenTree::Token(..)) => {}
|
||||
None => return TokenStream::empty(),
|
||||
None => return TokenStream::default(),
|
||||
}
|
||||
self.cx.span_err(span, "custom attribute invocations must be \
|
||||
of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \
|
||||
followed by a delimiter token");
|
||||
TokenStream::empty()
|
||||
TokenStream::default()
|
||||
}
|
||||
|
||||
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
|
||||
|
|
|
@ -95,7 +95,7 @@ pub(super) fn transcribe(
|
|||
) -> TokenStream {
|
||||
// Nothing for us to transcribe...
|
||||
if src.is_empty() {
|
||||
return TokenStream::empty();
|
||||
return TokenStream::default();
|
||||
}
|
||||
|
||||
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
fn mac_placeholder() -> ast::Mac {
|
||||
ast::Mac {
|
||||
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
|
||||
tts: TokenStream::empty().into(),
|
||||
tts: TokenStream::default().into(),
|
||||
delim: ast::MacDelimiter::Brace,
|
||||
span: DUMMY_SP,
|
||||
prior_type_ascription: None,
|
||||
|
@ -32,12 +32,12 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
attrs: ThinVec::new(),
|
||||
kind: ast::ExprKind::Mac(mac_placeholder()),
|
||||
});
|
||||
let ty = P(ast::Ty {
|
||||
let ty = || P(ast::Ty {
|
||||
id,
|
||||
kind: ast::TyKind::Mac(mac_placeholder()),
|
||||
span,
|
||||
});
|
||||
let pat = P(ast::Pat {
|
||||
let pat = || P(ast::Pat {
|
||||
id,
|
||||
kind: ast::PatKind::Mac(mac_placeholder()),
|
||||
span,
|
||||
|
@ -83,7 +83,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
body: expr_placeholder(),
|
||||
guard: None,
|
||||
id,
|
||||
pat,
|
||||
pat: pat(),
|
||||
span,
|
||||
is_placeholder: true,
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
id,
|
||||
ident,
|
||||
is_shorthand: false,
|
||||
pat,
|
||||
pat: pat(),
|
||||
span,
|
||||
is_placeholder: true,
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
ast::Param {
|
||||
attrs: Default::default(),
|
||||
id,
|
||||
pat,
|
||||
pat: pat(),
|
||||
span,
|
||||
ty,
|
||||
ty: ty(),
|
||||
is_placeholder: true,
|
||||
}
|
||||
]),
|
||||
|
@ -136,7 +136,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
|
|||
id,
|
||||
ident: None,
|
||||
span,
|
||||
ty,
|
||||
ty: ty(),
|
||||
vis,
|
||||
is_placeholder: true,
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ impl server::Types for Rustc<'_> {
|
|||
|
||||
impl server::TokenStream for Rustc<'_> {
|
||||
fn new(&mut self) -> Self::TokenStream {
|
||||
TokenStream::empty()
|
||||
TokenStream::default()
|
||||
}
|
||||
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
|
||||
stream.is_empty()
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
use crate::source_map::{SourceMap, FilePathMapping};
|
||||
|
||||
use errors::registry::Registry;
|
||||
use errors::{SubDiagnostic, CodeSuggestion, SourceMapper};
|
||||
use errors::{SubDiagnostic, CodeSuggestion, SourceMapper, SourceMapperDyn};
|
||||
use errors::{DiagnosticId, Applicability};
|
||||
use errors::emitter::{Emitter, HumanReadableErrorType};
|
||||
|
||||
|
@ -113,6 +113,10 @@ impl Emitter for JsonEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
|
||||
Some(&self.sm)
|
||||
}
|
||||
|
||||
fn should_show_explain(&self) -> bool {
|
||||
match self.json_rendered {
|
||||
HumanReadableErrorType::Short(_) => false,
|
||||
|
|
|
@ -610,10 +610,8 @@ pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
|
|||
}
|
||||
|
||||
pub fn noop_visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
|
||||
visit_opt(tts, |tts| {
|
||||
let tts = Lrc::make_mut(tts);
|
||||
visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
|
||||
})
|
||||
let tts = Lrc::make_mut(tts);
|
||||
visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
|
||||
}
|
||||
|
||||
// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
|
||||
|
|
|
@ -203,7 +203,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
TokenStream::from_streams(smallvec![eq.into(), tokens])
|
||||
} else {
|
||||
TokenStream::empty()
|
||||
TokenStream::default()
|
||||
};
|
||||
ast::AttrItem { path, tokens }
|
||||
})
|
||||
|
|
|
@ -1273,7 +1273,7 @@ impl<'a> Parser<'a> {
|
|||
// This can happen due to a bad interaction of two unrelated recovery mechanisms with
|
||||
// mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(`
|
||||
// (#62881).
|
||||
return Ok((ret?, TokenStream::new(vec![])));
|
||||
return Ok((ret?, TokenStream::default()));
|
||||
} else {
|
||||
&mut self.token_cursor.stack[prev].last_token
|
||||
};
|
||||
|
@ -1288,7 +1288,7 @@ impl<'a> Parser<'a> {
|
|||
// This can happen due to a bad interaction of two unrelated recovery mechanisms
|
||||
// with mismatched delimiters *and* recovery lookahead on the likely typo
|
||||
// `pub ident(` (#62895, different but similar to the case above).
|
||||
return Ok((ret?, TokenStream::new(vec![])));
|
||||
return Ok((ret?, TokenStream::default()));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -367,6 +367,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let pat = self.mk_pat(lo.to(self.prev_span), pat);
|
||||
let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
|
||||
let pat = self.recover_intersection_pat(pat)?;
|
||||
|
||||
if !allow_range_pat {
|
||||
self.ban_pat_range_if_ambiguous(&pat)?
|
||||
|
@ -375,6 +376,65 @@ impl<'a> Parser<'a> {
|
|||
Ok(pat)
|
||||
}
|
||||
|
||||
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
|
||||
///
|
||||
/// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
|
||||
/// should already have been parsed by now at this point,
|
||||
/// if the next token is `@` then we can try to parse the more general form.
|
||||
///
|
||||
/// Consult `parse_pat_ident` for the `binding` grammar.
|
||||
///
|
||||
/// The notion of intersection patterns are found in
|
||||
/// e.g. [F#][and] where they are called AND-patterns.
|
||||
///
|
||||
/// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
|
||||
fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
|
||||
if self.token.kind != token::At {
|
||||
// Next token is not `@` so it's not going to be an intersection pattern.
|
||||
return Ok(lhs);
|
||||
}
|
||||
|
||||
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
|
||||
self.bump(); // `@`
|
||||
let mut rhs = self.parse_pat(None)?;
|
||||
let sp = lhs.span.to(rhs.span);
|
||||
|
||||
if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
|
||||
// The user inverted the order, so help them fix that.
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
lhs.walk(&mut |p| match p.kind {
|
||||
// `check_match` is unhappy if the subpattern has a binding anywhere.
|
||||
PatKind::Ident(..) => {
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
false // Short-circuit.
|
||||
},
|
||||
_ => true,
|
||||
});
|
||||
|
||||
let lhs_span = lhs.span;
|
||||
// Move the LHS into the RHS as a subpattern.
|
||||
// The RHS is now the full pattern.
|
||||
*sub = Some(lhs);
|
||||
|
||||
self.struct_span_err(sp, "pattern on wrong side of `@`")
|
||||
.span_label(lhs_span, "pattern on the left, should be on the right")
|
||||
.span_label(rhs.span, "binding on the right, should be on the left")
|
||||
.span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability)
|
||||
.emit();
|
||||
} else {
|
||||
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
|
||||
rhs.kind = PatKind::Wild;
|
||||
self.struct_span_err(sp, "left-hand side of `@` must be a binding")
|
||||
.span_label(lhs.span, "interpreted as a pattern, not a binding")
|
||||
.span_label(rhs.span, "also a pattern")
|
||||
.note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`")
|
||||
.emit();
|
||||
}
|
||||
|
||||
rhs.span = sp;
|
||||
Ok(rhs)
|
||||
}
|
||||
|
||||
/// Ban a range pattern if it has an ambiguous interpretation.
|
||||
fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> {
|
||||
match pat.kind {
|
||||
|
|
|
@ -2381,7 +2381,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_ident(ident);
|
||||
if let Some(ref p) = *sub {
|
||||
self.s.word("@");
|
||||
self.s.space();
|
||||
self.s.word_space("@");
|
||||
self.print_pat(p);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -970,6 +970,9 @@ impl SourceMapper for SourceMap {
|
|||
fn span_to_string(&self, sp: Span) -> String {
|
||||
self.span_to_string(sp)
|
||||
}
|
||||
fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
||||
self.span_to_snippet(sp)
|
||||
}
|
||||
fn span_to_filename(&self, sp: Span) -> FileName {
|
||||
self.span_to_filename(sp)
|
||||
}
|
||||
|
|
|
@ -136,13 +136,8 @@ impl TokenTree {
|
|||
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
|
||||
/// instead of a representation of the abstract syntax tree.
|
||||
/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
|
||||
///
|
||||
/// The use of `Option` is an optimization that avoids the need for an
|
||||
/// allocation when the stream is empty. However, it is not guaranteed that an
|
||||
/// empty stream is represented with `None`; it may be represented as a `Some`
|
||||
/// around an empty `Vec`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TokenStream(pub Option<Lrc<Vec<TreeAndJoint>>>);
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>);
|
||||
|
||||
pub type TreeAndJoint = (TokenTree, IsJoint);
|
||||
|
||||
|
@ -163,36 +158,34 @@ impl TokenStream {
|
|||
/// separating the two arguments with a comma for diagnostic suggestions.
|
||||
pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
|
||||
// Used to suggest if a user writes `foo!(a b);`
|
||||
if let Some(ref stream) = self.0 {
|
||||
let mut suggestion = None;
|
||||
let mut iter = stream.iter().enumerate().peekable();
|
||||
while let Some((pos, ts)) = iter.next() {
|
||||
if let Some((_, next)) = iter.peek() {
|
||||
let sp = match (&ts, &next) {
|
||||
(_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue,
|
||||
((TokenTree::Token(token_left), NonJoint),
|
||||
(TokenTree::Token(token_right), _))
|
||||
if ((token_left.is_ident() && !token_left.is_reserved_ident())
|
||||
|| token_left.is_lit()) &&
|
||||
((token_right.is_ident() && !token_right.is_reserved_ident())
|
||||
|| token_right.is_lit()) => token_left.span,
|
||||
((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
|
||||
_ => continue,
|
||||
};
|
||||
let sp = sp.shrink_to_hi();
|
||||
let comma = (TokenTree::token(token::Comma, sp), NonJoint);
|
||||
suggestion = Some((pos, comma, sp));
|
||||
}
|
||||
}
|
||||
if let Some((pos, comma, sp)) = suggestion {
|
||||
let mut new_stream = vec![];
|
||||
let parts = stream.split_at(pos + 1);
|
||||
new_stream.extend_from_slice(parts.0);
|
||||
new_stream.push(comma);
|
||||
new_stream.extend_from_slice(parts.1);
|
||||
return Some((TokenStream::new(new_stream), sp));
|
||||
let mut suggestion = None;
|
||||
let mut iter = self.0.iter().enumerate().peekable();
|
||||
while let Some((pos, ts)) = iter.next() {
|
||||
if let Some((_, next)) = iter.peek() {
|
||||
let sp = match (&ts, &next) {
|
||||
(_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue,
|
||||
((TokenTree::Token(token_left), NonJoint),
|
||||
(TokenTree::Token(token_right), _))
|
||||
if ((token_left.is_ident() && !token_left.is_reserved_ident())
|
||||
|| token_left.is_lit()) &&
|
||||
((token_right.is_ident() && !token_right.is_reserved_ident())
|
||||
|| token_right.is_lit()) => token_left.span,
|
||||
((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
|
||||
_ => continue,
|
||||
};
|
||||
let sp = sp.shrink_to_hi();
|
||||
let comma = (TokenTree::token(token::Comma, sp), NonJoint);
|
||||
suggestion = Some((pos, comma, sp));
|
||||
}
|
||||
}
|
||||
if let Some((pos, comma, sp)) = suggestion {
|
||||
let mut new_stream = vec![];
|
||||
let parts = self.0.split_at(pos + 1);
|
||||
new_stream.extend_from_slice(parts.0);
|
||||
new_stream.push(comma);
|
||||
new_stream.extend_from_slice(parts.1);
|
||||
return Some((TokenStream::new(new_stream), sp));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -224,28 +217,21 @@ impl PartialEq<TokenStream> for TokenStream {
|
|||
}
|
||||
|
||||
impl TokenStream {
|
||||
pub fn len(&self) -> usize {
|
||||
if let Some(ref slice) = self.0 {
|
||||
slice.len()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> TokenStream {
|
||||
TokenStream(None)
|
||||
pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
|
||||
TokenStream(Lrc::new(streams))
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self.0 {
|
||||
None => true,
|
||||
Some(ref stream) => stream.is_empty(),
|
||||
}
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub(crate) fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
|
||||
match streams.len() {
|
||||
0 => TokenStream::empty(),
|
||||
0 => TokenStream::default(),
|
||||
1 => streams.pop().unwrap(),
|
||||
_ => {
|
||||
// We are going to extend the first stream in `streams` with
|
||||
|
@ -269,41 +255,24 @@ impl TokenStream {
|
|||
// Get the first stream. If it's `None`, create an empty
|
||||
// stream.
|
||||
let mut iter = streams.drain();
|
||||
let mut first_stream_lrc = match iter.next().unwrap().0 {
|
||||
Some(first_stream_lrc) => first_stream_lrc,
|
||||
None => Lrc::new(vec![]),
|
||||
};
|
||||
let mut first_stream_lrc = iter.next().unwrap().0;
|
||||
|
||||
// Append the elements to the first stream, after reserving
|
||||
// space for them.
|
||||
let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc);
|
||||
first_vec_mut.reserve(num_appends);
|
||||
for stream in iter {
|
||||
if let Some(stream) = stream.0 {
|
||||
first_vec_mut.extend(stream.iter().cloned());
|
||||
}
|
||||
first_vec_mut.extend(stream.0.iter().cloned());
|
||||
}
|
||||
|
||||
// Create the final `TokenStream`.
|
||||
match first_vec_mut.len() {
|
||||
0 => TokenStream(None),
|
||||
_ => TokenStream(Some(first_stream_lrc)),
|
||||
}
|
||||
TokenStream(first_stream_lrc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
|
||||
match streams.len() {
|
||||
0 => TokenStream(None),
|
||||
_ => TokenStream(Some(Lrc::new(streams))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec<TreeAndJoint>) {
|
||||
if let Some(stream) = self.0 {
|
||||
vec.extend(stream.iter().cloned());
|
||||
}
|
||||
vec.extend(self.0.iter().cloned());
|
||||
}
|
||||
|
||||
pub fn trees(&self) -> Cursor {
|
||||
|
@ -370,24 +339,22 @@ impl TokenStream {
|
|||
}
|
||||
|
||||
pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
||||
TokenStream(self.0.map(|stream| {
|
||||
Lrc::new(
|
||||
stream
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
|
||||
.collect())
|
||||
}))
|
||||
TokenStream(Lrc::new(
|
||||
self.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
|
||||
.collect()
|
||||
))
|
||||
}
|
||||
|
||||
pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
||||
TokenStream(self.0.map(|stream| {
|
||||
Lrc::new(
|
||||
stream
|
||||
.iter()
|
||||
.map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
|
||||
.collect())
|
||||
}))
|
||||
TokenStream(Lrc::new(
|
||||
self.0
|
||||
.iter()
|
||||
.map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
|
||||
.collect()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,44 +372,43 @@ impl TokenStreamBuilder {
|
|||
|
||||
// If `self` is not empty and the last tree within the last stream is a
|
||||
// token tree marked with `Joint`...
|
||||
if let Some(TokenStream(Some(ref mut last_stream_lrc))) = self.0.last_mut() {
|
||||
if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() {
|
||||
if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() {
|
||||
|
||||
// ...and `stream` is not empty and the first tree within it is
|
||||
// a token tree...
|
||||
if let TokenStream(Some(ref mut stream_lrc)) = stream {
|
||||
if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
|
||||
let TokenStream(ref mut stream_lrc) = stream;
|
||||
if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
|
||||
|
||||
// ...and the two tokens can be glued together...
|
||||
if let Some(glued_tok) = last_token.glue(&token) {
|
||||
// ...and the two tokens can be glued together...
|
||||
if let Some(glued_tok) = last_token.glue(&token) {
|
||||
|
||||
// ...then do so, by overwriting the last token
|
||||
// tree in `self` and removing the first token tree
|
||||
// from `stream`. This requires using `make_mut()`
|
||||
// on the last stream in `self` and on `stream`,
|
||||
// and in practice this doesn't cause cloning 99.9%
|
||||
// of the time.
|
||||
// ...then do so, by overwriting the last token
|
||||
// tree in `self` and removing the first token tree
|
||||
// from `stream`. This requires using `make_mut()`
|
||||
// on the last stream in `self` and on `stream`,
|
||||
// and in practice this doesn't cause cloning 99.9%
|
||||
// of the time.
|
||||
|
||||
// Overwrite the last token tree with the merged
|
||||
// token.
|
||||
let last_vec_mut = Lrc::make_mut(last_stream_lrc);
|
||||
*last_vec_mut.last_mut().unwrap() =
|
||||
(TokenTree::Token(glued_tok), *is_joint);
|
||||
// Overwrite the last token tree with the merged
|
||||
// token.
|
||||
let last_vec_mut = Lrc::make_mut(last_stream_lrc);
|
||||
*last_vec_mut.last_mut().unwrap() =
|
||||
(TokenTree::Token(glued_tok), *is_joint);
|
||||
|
||||
// Remove the first token tree from `stream`. (This
|
||||
// is almost always the only tree in `stream`.)
|
||||
let stream_vec_mut = Lrc::make_mut(stream_lrc);
|
||||
stream_vec_mut.remove(0);
|
||||
// Remove the first token tree from `stream`. (This
|
||||
// is almost always the only tree in `stream`.)
|
||||
let stream_vec_mut = Lrc::make_mut(stream_lrc);
|
||||
stream_vec_mut.remove(0);
|
||||
|
||||
// Don't push `stream` if it's empty -- that could
|
||||
// block subsequent token gluing, by getting
|
||||
// between two token trees that should be glued
|
||||
// together.
|
||||
if !stream.is_empty() {
|
||||
self.0.push(stream);
|
||||
}
|
||||
return;
|
||||
// Don't push `stream` if it's empty -- that could
|
||||
// block subsequent token gluing, by getting
|
||||
// between two token trees that should be glued
|
||||
// together.
|
||||
if !stream.is_empty() {
|
||||
self.0.push(stream);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -475,16 +441,11 @@ impl Cursor {
|
|||
}
|
||||
|
||||
pub fn next_with_joint(&mut self) -> Option<TreeAndJoint> {
|
||||
match self.stream.0 {
|
||||
None => None,
|
||||
Some(ref stream) => {
|
||||
if self.index < stream.len() {
|
||||
self.index += 1;
|
||||
Some(stream[self.index - 1].clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
if self.index < self.stream.len() {
|
||||
self.index += 1;
|
||||
Some(self.stream.0[self.index - 1].clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,16 +454,13 @@ impl Cursor {
|
|||
return;
|
||||
}
|
||||
let index = self.index;
|
||||
let stream = mem::replace(&mut self.stream, TokenStream(None));
|
||||
let stream = mem::take(&mut self.stream);
|
||||
*self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees();
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
|
||||
match self.stream.0 {
|
||||
None => None,
|
||||
Some(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()),
|
||||
}
|
||||
self.stream.0[self.index ..].get(n).map(|(tree, _)| tree.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ fn plugin_macro_def(name: Name, span: Span) -> P<Item> {
|
|||
attr::mk_word_item(Ident::new(sym::rustc_builtin_macro, span)));
|
||||
|
||||
let parens: TreeAndJoint = TokenTree::Delimited(
|
||||
DelimSpan::from_single(span), token::Paren, TokenStream::empty()
|
||||
DelimSpan::from_single(span), token::Paren, TokenStream::default()
|
||||
).into();
|
||||
let trees = vec![parens.clone(), TokenTree::token(token::FatArrow, span).into(), parens];
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#![feature(const_generics)]
|
||||
|
||||
pub struct Struct<const N: usize>(pub [u8; N]);
|
||||
|
||||
pub type Alias = Struct<2>;
|
||||
|
||||
pub fn function(value: Struct<3>) -> u8 {
|
||||
value.0[0]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// aux-build:const_generic_lib.rs
|
||||
|
||||
extern crate const_generic_lib;
|
||||
|
||||
fn main() {
|
||||
let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
|
||||
//~^ ERROR mismatched types
|
||||
let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
|
||||
//~^ ERROR mismatched types
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/const-argument-cross-crate-mismatch.rs:6:41
|
||||
|
|
||||
LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `2usize`
|
||||
|
|
||||
= note: expected type `const_generic_lib::Struct<3usize>`
|
||||
found type `const_generic_lib::Struct<_: usize>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-argument-cross-crate-mismatch.rs:8:39
|
||||
|
|
||||
LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2usize`, found `3usize`
|
||||
|
|
||||
= note: expected type `const_generic_lib::Struct<2usize>`
|
||||
found type `const_generic_lib::Struct<_: usize>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
12
src/test/ui/const-generics/const-argument-cross-crate.rs
Normal file
12
src/test/ui/const-generics/const-argument-cross-crate.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// run-pass
|
||||
// aux-build:const_generic_lib.rs
|
||||
|
||||
extern crate const_generic_lib;
|
||||
|
||||
struct Container(const_generic_lib::Alias);
|
||||
|
||||
fn main() {
|
||||
let res = const_generic_lib::function(const_generic_lib::Struct([14u8, 1u8, 2u8]));
|
||||
assert_eq!(res, 14u8);
|
||||
let _ = Container(const_generic_lib::Struct([0u8, 1u8]));
|
||||
}
|
|
@ -10,7 +10,7 @@ error: const parameter `x` should have an upper case name
|
|||
--> $DIR/const-parameter-uppercase-lint.rs:6:15
|
||||
|
|
||||
LL | fn noop<const x: u32>() {
|
||||
| ^ help: convert the identifier to upper case: `X`
|
||||
| ^ help: convert the identifier to upper case (notice the capitalization): `X`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/const-parameter-uppercase-lint.rs:4:9
|
||||
|
|
|
@ -55,7 +55,7 @@ LL | let z = ManyVariants::Three();
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
LL | let z = ManyVariants::Four();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
and 6 other candidates
|
||||
and 6 other candidates
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ LL | fn setup() -> Determine { Set }
|
|||
| ^^^^^^^^^
|
||||
LL | fn setup() -> PutDown { Set }
|
||||
| ^^^^^^^
|
||||
and 3 other candidates
|
||||
and 3 other candidates
|
||||
|
||||
error[E0425]: cannot find value `Set` in this scope
|
||||
--> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21
|
||||
|
@ -30,7 +30,7 @@ LL | use Determine::Set;
|
|||
|
|
||||
LL | use PutDown::Set;
|
||||
|
|
||||
and 3 other candidates
|
||||
and 3 other candidates
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ LL | let f = Foo();
|
|||
| ^^^
|
||||
| |
|
||||
| did you mean `Foo { /* fields */ }`?
|
||||
| help: a function with a similar name exists: `foo`
|
||||
| help: a function with a similar name exists (notice the capitalization): `foo`
|
||||
|
||||
error[E0423]: expected value, found struct `T`
|
||||
--> $DIR/E0423.rs:14:8
|
||||
|
|
|
@ -2,7 +2,7 @@ error: variable `X` should have a snake case name
|
|||
--> $DIR/expr_attr_paren_order.rs:19:17
|
||||
|
|
||||
LL | let X = 0;
|
||||
| ^ help: convert the identifier to snake case: `x`
|
||||
| ^ help: convert the identifier to snake case (notice the capitalization): `x`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/expr_attr_paren_order.rs:17:17
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
||||
--> $DIR/feature-gate-exhaustive-patterns.rs:7:9
|
||||
|
|
||||
LL | let Ok(_x) = foo();
|
||||
| ^^^^^^ pattern `Err(_)` not covered
|
||||
|
|
||||
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
|
||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||
|
|
||||
LL | if let Ok(_x) = foo() { /* */ }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0005`.
|
|
@ -34,7 +34,7 @@ LL | use foo::test2::test::g;
|
|||
|
|
||||
LL | use foo::test::g;
|
||||
|
|
||||
and 2 other candidates
|
||||
and 2 other candidates
|
||||
|
||||
error[E0425]: cannot find function `f` in this scope
|
||||
--> $DIR/globs.rs:61:12
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0425]: cannot find value `Opaque` in this scope
|
|||
--> $DIR/rustc-macro-transparency.rs:26:5
|
||||
|
|
||||
LL | Opaque;
|
||||
| ^^^^^^ help: a local variable with a similar name exists: `opaque`
|
||||
| ^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `opaque`
|
||||
|
||||
error[E0423]: expected value, found macro `semitransparent`
|
||||
--> $DIR/rustc-macro-transparency.rs:29:5
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0532]: expected tuple struct/variant, found function `foo`
|
|||
--> $DIR/issue-10200.rs:6:9
|
||||
|
|
||||
LL | foo(x)
|
||||
| ^^^ help: a tuple struct with a similar name exists: `Foo`
|
||||
| ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ LL | use std::prelude::v1::Result;
|
|||
|
|
||||
LL | use std::result::Result;
|
||||
|
|
||||
and 1 other candidates
|
||||
and 1 other candidates
|
||||
|
||||
error[E0573]: expected type, found variant `Result`
|
||||
--> $DIR/issue-17546.rs:28:13
|
||||
|
@ -44,7 +44,7 @@ LL | use std::prelude::v1::Result;
|
|||
|
|
||||
LL | use std::result::Result;
|
||||
|
|
||||
and 1 other candidates
|
||||
and 1 other candidates
|
||||
|
||||
error[E0573]: expected type, found variant `NoResult`
|
||||
--> $DIR/issue-17546.rs:33:15
|
||||
|
|
|
@ -15,7 +15,7 @@ error: constant `foo` should have an upper case name
|
|||
--> $DIR/issue-17718-const-naming.rs:4:7
|
||||
|
|
||||
LL | const foo: isize = 3;
|
||||
| ^^^ help: convert the identifier to upper case: `FOO`
|
||||
| ^^^ help: convert the identifier to upper case (notice the capitalization): `FOO`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/issue-17718-const-naming.rs:2:9
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0422]: cannot find struct, variant or union type `TyUInt` in this scope
|
|||
--> $DIR/issue-46332.rs:9:5
|
||||
|
|
||||
LL | TyUInt {};
|
||||
| ^^^^^^ help: a struct with a similar name exists: `TyUint`
|
||||
| ^^^^^^ help: a struct with a similar name exists (notice the capitalization): `TyUint`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -14,25 +14,25 @@ error: type `foo` should have an upper camel case name
|
|||
--> $DIR/lint-non-camel-case-types.rs:7:8
|
||||
|
|
||||
LL | struct foo {
|
||||
| ^^^ help: convert the identifier to upper camel case: `Foo`
|
||||
| ^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo`
|
||||
|
||||
error: type `foo2` should have an upper camel case name
|
||||
--> $DIR/lint-non-camel-case-types.rs:11:6
|
||||
|
|
||||
LL | enum foo2 {
|
||||
| ^^^^ help: convert the identifier to upper camel case: `Foo2`
|
||||
| ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo2`
|
||||
|
||||
error: type `foo3` should have an upper camel case name
|
||||
--> $DIR/lint-non-camel-case-types.rs:15:8
|
||||
|
|
||||
LL | struct foo3 {
|
||||
| ^^^^ help: convert the identifier to upper camel case: `Foo3`
|
||||
| ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo3`
|
||||
|
||||
error: type `foo4` should have an upper camel case name
|
||||
--> $DIR/lint-non-camel-case-types.rs:19:6
|
||||
|
|
||||
LL | type foo4 = isize;
|
||||
| ^^^^ help: convert the identifier to upper camel case: `Foo4`
|
||||
| ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo4`
|
||||
|
||||
error: variant `bar` should have an upper camel case name
|
||||
--> $DIR/lint-non-camel-case-types.rs:22:5
|
||||
|
@ -44,7 +44,7 @@ error: trait `foo6` should have an upper camel case name
|
|||
--> $DIR/lint-non-camel-case-types.rs:25:7
|
||||
|
|
||||
LL | trait foo6 {
|
||||
| ^^^^ help: convert the identifier to upper camel case: `Foo6`
|
||||
| ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo6`
|
||||
|
||||
error: type parameter `ty` should have an upper camel case name
|
||||
--> $DIR/lint-non-camel-case-types.rs:29:6
|
||||
|
|
|
@ -38,7 +38,7 @@ error: trait method `a_b_C` should have a snake case name
|
|||
--> $DIR/lint-non-snake-case-functions.rs:25:8
|
||||
|
|
||||
LL | fn a_b_C(&self) {}
|
||||
| ^^^^^ help: convert the identifier to snake case: `a_b_c`
|
||||
| ^^^^^ help: convert the identifier to snake case (notice the capitalization): `a_b_c`
|
||||
|
||||
error: trait method `something__else` should have a snake case name
|
||||
--> $DIR/lint-non-snake-case-functions.rs:28:8
|
||||
|
@ -50,13 +50,13 @@ error: function `Cookie` should have a snake case name
|
|||
--> $DIR/lint-non-snake-case-functions.rs:38:4
|
||||
|
|
||||
LL | fn Cookie() {}
|
||||
| ^^^^^^ help: convert the identifier to snake case: `cookie`
|
||||
| ^^^^^^ help: convert the identifier to snake case (notice the capitalization): `cookie`
|
||||
|
||||
error: function `bi_S_Cuit` should have a snake case name
|
||||
--> $DIR/lint-non-snake-case-functions.rs:41:8
|
||||
|
|
||||
LL | pub fn bi_S_Cuit() {}
|
||||
| ^^^^^^^^^ help: convert the identifier to snake case: `bi_s_cuit`
|
||||
| ^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `bi_s_cuit`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error: static variable `foo` should have an upper case name
|
|||
--> $DIR/lint-non-uppercase-statics.rs:4:8
|
||||
|
|
||||
LL | static foo: isize = 1;
|
||||
| ^^^ help: convert the identifier to upper case: `FOO`
|
||||
| ^^^ help: convert the identifier to upper case (notice the capitalization): `FOO`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-non-uppercase-statics.rs:1:11
|
||||
|
|
|
@ -21,7 +21,7 @@ error: structure field `X` should have a snake case name
|
|||
--> $DIR/lint-uppercase-variables.rs:10:5
|
||||
|
|
||||
LL | X: usize
|
||||
| ^ help: convert the identifier to snake case: `x`
|
||||
| ^ help: convert the identifier to snake case (notice the capitalization): `x`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-uppercase-variables.rs:3:9
|
||||
|
@ -33,7 +33,7 @@ error: variable `Xx` should have a snake case name
|
|||
--> $DIR/lint-uppercase-variables.rs:13:9
|
||||
|
|
||||
LL | fn test(Xx: usize) {
|
||||
| ^^ help: convert the identifier to snake case: `xx`
|
||||
| ^^ help: convert the identifier to snake case (notice the capitalization): `xx`
|
||||
|
||||
error: variable `Test` should have a snake case name
|
||||
--> $DIR/lint-uppercase-variables.rs:18:9
|
||||
|
@ -45,7 +45,7 @@ error: variable `Foo` should have a snake case name
|
|||
--> $DIR/lint-uppercase-variables.rs:22:9
|
||||
|
|
||||
LL | Foo => {}
|
||||
| ^^^ help: convert the identifier to snake case: `foo`
|
||||
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -16,5 +16,5 @@ warning: unknown lint: `Warnings`
|
|||
--> $DIR/not_found.rs:10:8
|
||||
|
|
||||
LL | #[deny(Warnings)]
|
||||
| ^^^^^^^^ help: did you mean: `warnings`
|
||||
| ^^^^^^^^ help: did you mean (notice the capitalization): `warnings`
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ warning: variable `Social_exchange_psychology` should have a snake case name
|
|||
--> $DIR/reasons.rs:30:9
|
||||
|
|
||||
LL | let Social_exchange_psychology = CheaterDetectionMechanism {};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `social_exchange_psychology`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `social_exchange_psychology`
|
||||
|
|
||||
= note: people shouldn't have to change their usual style habits
|
||||
to contribute to our project
|
||||
|
|
|
@ -395,7 +395,7 @@ mod foo {
|
|||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0mand 8 other candidates\u001b[0m
|
||||
\u001b[0m and 8 other candidates\u001b[0m
|
||||
|
||||
"
|
||||
}
|
||||
|
|
40
src/test/ui/parser/intersection-patterns.rs
Normal file
40
src/test/ui/parser/intersection-patterns.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// This tests the parser recovery in `recover_intersection_pat`
|
||||
// and serves as a regression test for the diagnostics issue #65400.
|
||||
//
|
||||
// The general idea is that for `$pat_lhs @ $pat_rhs` where
|
||||
// `$pat_lhs` is not generated by `ref? mut? $ident` we want
|
||||
// to suggest either switching the order or note that intersection
|
||||
// patterns are not allowed.
|
||||
|
||||
fn main() {
|
||||
let s: Option<u8> = None;
|
||||
|
||||
match s {
|
||||
Some(x) @ y => {}
|
||||
//~^ ERROR pattern on wrong side of `@`
|
||||
//~| pattern on the left, should be on the right
|
||||
//~| binding on the right, should be on the left
|
||||
//~| HELP switch the order
|
||||
//~| SUGGESTION y @ Some(x)
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match s {
|
||||
Some(x) @ Some(y) => {}
|
||||
//~^ ERROR left-hand side of `@` must be a binding
|
||||
//~| interpreted as a pattern, not a binding
|
||||
//~| also a pattern
|
||||
//~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 2 {
|
||||
1 ..= 5 @ e => {}
|
||||
//~^ ERROR pattern on wrong side of `@`
|
||||
//~| pattern on the left, should be on the right
|
||||
//~| binding on the right, should be on the left
|
||||
//~| HELP switch the order
|
||||
//~| SUGGESTION e @ 1 ..=5
|
||||
_ => {}
|
||||
}
|
||||
}
|
33
src/test/ui/parser/intersection-patterns.stderr
Normal file
33
src/test/ui/parser/intersection-patterns.stderr
Normal file
|
@ -0,0 +1,33 @@
|
|||
error: pattern on wrong side of `@`
|
||||
--> $DIR/intersection-patterns.rs:13:9
|
||||
|
|
||||
LL | Some(x) @ y => {}
|
||||
| -------^^^-
|
||||
| | |
|
||||
| | binding on the right, should be on the left
|
||||
| pattern on the left, should be on the right
|
||||
| help: switch the order: `y @ Some(x)`
|
||||
|
||||
error: left-hand side of `@` must be a binding
|
||||
--> $DIR/intersection-patterns.rs:23:9
|
||||
|
|
||||
LL | Some(x) @ Some(y) => {}
|
||||
| -------^^^-------
|
||||
| | |
|
||||
| | also a pattern
|
||||
| interpreted as a pattern, not a binding
|
||||
|
|
||||
= note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
||||
|
||||
error: pattern on wrong side of `@`
|
||||
--> $DIR/intersection-patterns.rs:32:9
|
||||
|
|
||||
LL | 1 ..= 5 @ e => {}
|
||||
| -------^^^-
|
||||
| | |
|
||||
| | binding on the right, should be on the left
|
||||
| pattern on the left, should be on the right
|
||||
| help: switch the order: `e @ 1 ..=5`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -27,7 +27,7 @@ LL | use mul3::Mul;
|
|||
|
|
||||
LL | use mul4::Mul;
|
||||
|
|
||||
and 2 other candidates
|
||||
and 2 other candidates
|
||||
|
||||
error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
|
||||
--> $DIR/issue-21221-1.rs:63:6
|
||||
|
|
|
@ -38,13 +38,13 @@ error[E0412]: cannot find type `first` in module `m`
|
|||
--> $DIR/levenshtein.rs:28:15
|
||||
|
|
||||
LL | let b: m::first = m::second; // Misspelled item in module.
|
||||
| ^^^^^ help: a struct with a similar name exists: `First`
|
||||
| ^^^^^ help: a struct with a similar name exists (notice the capitalization): `First`
|
||||
|
||||
error[E0425]: cannot find value `second` in module `m`
|
||||
--> $DIR/levenshtein.rs:28:26
|
||||
|
|
||||
LL | let b: m::first = m::second; // Misspelled item in module.
|
||||
| ^^^^^^ help: a unit struct with a similar name exists: `Second`
|
||||
| ^^^^^^ help: a unit struct with a similar name exists (notice the capitalization): `Second`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ LL | use std::collections::hash_map::Drain;
|
|||
|
|
||||
LL | use std::collections::hash_set::Drain;
|
||||
|
|
||||
and 3 other candidates
|
||||
and 3 other candidates
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue