commit
30bfdc8720
78 changed files with 1051 additions and 655 deletions
|
@ -204,7 +204,7 @@ dependencies = [
|
||||||
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -737,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.2"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -959,7 +959,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1649,7 +1649,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "racer"
|
name = "racer"
|
||||||
version = "2.1.6"
|
version = "2.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1797,7 +1797,7 @@ dependencies = [
|
||||||
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"racer 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"racer 2.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1814,6 +1814,7 @@ dependencies = [
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1889,7 +1890,7 @@ dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fmt_macros 0.0.0",
|
"fmt_macros 0.0.0",
|
||||||
"graphviz 0.0.0",
|
"graphviz 0.0.0",
|
||||||
"jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2133,7 +2134,7 @@ dependencies = [
|
||||||
name = "rustc_codegen_utils"
|
name = "rustc_codegen_utils"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
|
@ -2276,7 +2277,7 @@ dependencies = [
|
||||||
name = "rustc_metadata"
|
name = "rustc_metadata"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc_macro 0.0.0",
|
"proc_macro 0.0.0",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
|
@ -3222,7 +3223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
|
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
|
||||||
"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
|
"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
|
||||||
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
|
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
|
||||||
"checksum flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37847f133aae7acf82bb9577ccd8bda241df836787642654286e79679826a54b"
|
"checksum flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4af030962d89d62aa52cd9492083b1cd9b2d1a77764878102a6c0f86b4d5444d"
|
||||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
@ -3319,7 +3320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
|
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
|
||||||
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
||||||
"checksum racer 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "99e820b7f7701c834c3f6f8226f388c19c0ea948a3ef79ddc96aa7398b5ba87a"
|
"checksum racer 2.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0beefbfaed799c3554021a48856113ad53862311395f6d75376192884ba5fbe6"
|
||||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||||
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
|
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
|
||||||
|
|
|
@ -1263,14 +1263,16 @@ impl Step for Clippy {
|
||||||
builder.install(&cargoclippy, &image.join("bin"), 0o755);
|
builder.install(&cargoclippy, &image.join("bin"), 0o755);
|
||||||
let doc = image.join("share/doc/clippy");
|
let doc = image.join("share/doc/clippy");
|
||||||
builder.install(&src.join("README.md"), &doc, 0o644);
|
builder.install(&src.join("README.md"), &doc, 0o644);
|
||||||
builder.install(&src.join("LICENSE"), &doc, 0o644);
|
builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||||
|
builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||||
|
|
||||||
// Prepare the overlay
|
// Prepare the overlay
|
||||||
let overlay = tmp.join("clippy-overlay");
|
let overlay = tmp.join("clippy-overlay");
|
||||||
drop(fs::remove_dir_all(&overlay));
|
drop(fs::remove_dir_all(&overlay));
|
||||||
t!(fs::create_dir_all(&overlay));
|
t!(fs::create_dir_all(&overlay));
|
||||||
builder.install(&src.join("README.md"), &overlay, 0o644);
|
builder.install(&src.join("README.md"), &overlay, 0o644);
|
||||||
builder.install(&src.join("LICENSE"), &doc, 0o644);
|
builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||||
|
builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||||
builder.create(&overlay.join("version"), &version);
|
builder.create(&overlay.join("version"), &version);
|
||||||
|
|
||||||
// Generate the installer tarball
|
// Generate the installer tarball
|
||||||
|
|
|
@ -1288,6 +1288,9 @@ impl Build {
|
||||||
t!(fs::create_dir_all(dstdir));
|
t!(fs::create_dir_all(dstdir));
|
||||||
drop(fs::remove_file(&dst));
|
drop(fs::remove_file(&dst));
|
||||||
{
|
{
|
||||||
|
if !src.exists() {
|
||||||
|
panic!("Error: File \"{}\" not found!", src.display());
|
||||||
|
}
|
||||||
let mut s = t!(fs::File::open(&src));
|
let mut s = t!(fs::File::open(&src));
|
||||||
let mut d = t!(fs::File::create(&dst));
|
let mut d = t!(fs::File::create(&dst));
|
||||||
io::copy(&mut s, &mut d).expect("failed to copy");
|
io::copy(&mut s, &mut d).expect("failed to copy");
|
||||||
|
|
|
@ -152,7 +152,7 @@
|
||||||
//! Additionally, the return value of this function is [`fmt::Result`] which is a
|
//! Additionally, the return value of this function is [`fmt::Result`] which is a
|
||||||
//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
|
//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
|
||||||
//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
|
//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
|
||||||
//! calling [`write!`]) however, they should never return errors spuriously. That
|
//! calling [`write!`]). However, they should never return errors spuriously. That
|
||||||
//! is, a formatting implementation must and may only return an error if the
|
//! 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
|
//! passed-in [`Formatter`] returns an error. This is because, contrary to what
|
||||||
//! the function signature might suggest, string formatting is an infallible
|
//! the function signature might suggest, string formatting is an infallible
|
||||||
|
|
|
@ -867,7 +867,7 @@ impl<T: ?Sized> Clone for Rc<T> {
|
||||||
///
|
///
|
||||||
/// let five = Rc::new(5);
|
/// let five = Rc::new(5);
|
||||||
///
|
///
|
||||||
/// Rc::clone(&five);
|
/// let _ = Rc::clone(&five);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Rc<T> {
|
fn clone(&self) -> Rc<T> {
|
||||||
|
@ -1304,7 +1304,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
||||||
///
|
///
|
||||||
/// let weak_five = Rc::downgrade(&Rc::new(5));
|
/// let weak_five = Rc::downgrade(&Rc::new(5));
|
||||||
///
|
///
|
||||||
/// Weak::clone(&weak_five);
|
/// let _ = Weak::clone(&weak_five);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Weak<T> {
|
fn clone(&self) -> Weak<T> {
|
||||||
|
|
|
@ -713,7 +713,7 @@ impl<T: ?Sized> Clone for Arc<T> {
|
||||||
///
|
///
|
||||||
/// let five = Arc::new(5);
|
/// let five = Arc::new(5);
|
||||||
///
|
///
|
||||||
/// Arc::clone(&five);
|
/// let _ = Arc::clone(&five);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Arc<T> {
|
fn clone(&self) -> Arc<T> {
|
||||||
|
@ -1135,7 +1135,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
||||||
///
|
///
|
||||||
/// let weak_five = Arc::downgrade(&Arc::new(5));
|
/// let weak_five = Arc::downgrade(&Arc::new(5));
|
||||||
///
|
///
|
||||||
/// Weak::clone(&weak_five);
|
/// let _ = Weak::clone(&weak_five);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Weak<T> {
|
fn clone(&self) -> Weak<T> {
|
||||||
|
|
|
@ -637,8 +637,8 @@ Erroneous code example:
|
||||||
```compile_fail,E0152
|
```compile_fail,E0152
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
|
|
||||||
#[lang = "panic_impl"]
|
#[lang = "arc"]
|
||||||
struct Foo; // error: duplicate lang item found: `panic_impl`
|
struct Foo; // error: duplicate lang item found: `arc`
|
||||||
```
|
```
|
||||||
|
|
||||||
Lang items are already implemented in the standard library. Unless you are
|
Lang items are already implemented in the standard library. Unless you are
|
||||||
|
@ -2116,6 +2116,20 @@ struct Foo;
|
||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0718: r##"
|
||||||
|
This error indicates that a `#[lang = ".."]` attribute was placed
|
||||||
|
on the wrong type of item.
|
||||||
|
|
||||||
|
Examples of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0718
|
||||||
|
#![feature(lang_items)]
|
||||||
|
|
||||||
|
#[lang = "arc"]
|
||||||
|
static X: u32 = 42;
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,40 +14,80 @@
|
||||||
//! conflicts between multiple such attributes attached to the same
|
//! conflicts between multiple such attributes attached to the same
|
||||||
//! item.
|
//! item.
|
||||||
|
|
||||||
use syntax_pos::Span;
|
|
||||||
use ty::TyCtxt;
|
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||||
|
use ty::TyCtxt;
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
use syntax_pos::Span;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum Target {
|
pub(crate) enum Target {
|
||||||
|
ExternCrate,
|
||||||
|
Use,
|
||||||
|
Static,
|
||||||
|
Const,
|
||||||
Fn,
|
Fn,
|
||||||
|
Closure,
|
||||||
|
Mod,
|
||||||
|
ForeignMod,
|
||||||
|
GlobalAsm,
|
||||||
|
Ty,
|
||||||
|
Existential,
|
||||||
|
Enum,
|
||||||
Struct,
|
Struct,
|
||||||
Union,
|
Union,
|
||||||
Enum,
|
Trait,
|
||||||
Const,
|
TraitAlias,
|
||||||
ForeignMod,
|
Impl,
|
||||||
Expression,
|
Expression,
|
||||||
Statement,
|
Statement,
|
||||||
Closure,
|
}
|
||||||
Static,
|
|
||||||
Trait,
|
impl Display for Target {
|
||||||
Other,
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", match *self {
|
||||||
|
Target::ExternCrate => "extern crate",
|
||||||
|
Target::Use => "use",
|
||||||
|
Target::Static => "static item",
|
||||||
|
Target::Const => "constant item",
|
||||||
|
Target::Fn => "function",
|
||||||
|
Target::Closure => "closure",
|
||||||
|
Target::Mod => "module",
|
||||||
|
Target::ForeignMod => "foreign module",
|
||||||
|
Target::GlobalAsm => "global asm",
|
||||||
|
Target::Ty => "type alias",
|
||||||
|
Target::Existential => "existential type",
|
||||||
|
Target::Enum => "enum",
|
||||||
|
Target::Struct => "struct",
|
||||||
|
Target::Union => "union",
|
||||||
|
Target::Trait => "trait",
|
||||||
|
Target::TraitAlias => "trait alias",
|
||||||
|
Target::Impl => "item",
|
||||||
|
Target::Expression => "expression",
|
||||||
|
Target::Statement => "statement",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
fn from_item(item: &hir::Item) -> Target {
|
pub(crate) fn from_item(item: &hir::Item) -> Target {
|
||||||
match item.node {
|
match item.node {
|
||||||
|
hir::ItemKind::ExternCrate(..) => Target::ExternCrate,
|
||||||
|
hir::ItemKind::Use(..) => Target::Use,
|
||||||
|
hir::ItemKind::Static(..) => Target::Static,
|
||||||
|
hir::ItemKind::Const(..) => Target::Const,
|
||||||
hir::ItemKind::Fn(..) => Target::Fn,
|
hir::ItemKind::Fn(..) => Target::Fn,
|
||||||
|
hir::ItemKind::Mod(..) => Target::Mod,
|
||||||
|
hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
|
||||||
|
hir::ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
||||||
|
hir::ItemKind::Ty(..) => Target::Ty,
|
||||||
|
hir::ItemKind::Existential(..) => Target::Existential,
|
||||||
|
hir::ItemKind::Enum(..) => Target::Enum,
|
||||||
hir::ItemKind::Struct(..) => Target::Struct,
|
hir::ItemKind::Struct(..) => Target::Struct,
|
||||||
hir::ItemKind::Union(..) => Target::Union,
|
hir::ItemKind::Union(..) => Target::Union,
|
||||||
hir::ItemKind::Enum(..) => Target::Enum,
|
|
||||||
hir::ItemKind::Const(..) => Target::Const,
|
|
||||||
hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
|
|
||||||
hir::ItemKind::Static(..) => Target::Static,
|
|
||||||
hir::ItemKind::Trait(..) => Target::Trait,
|
hir::ItemKind::Trait(..) => Target::Trait,
|
||||||
_ => Target::Other,
|
hir::ItemKind::TraitAlias(..) => Target::TraitAlias,
|
||||||
|
hir::ItemKind::Impl(..) => Target::Impl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
pub use self::LangItem::*;
|
pub use self::LangItem::*;
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
use hir::check_attr::Target;
|
||||||
use ty::{self, TyCtxt};
|
use ty::{self, TyCtxt};
|
||||||
use middle::weak_lang_items;
|
use middle::weak_lang_items;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::FxHashMap;
|
||||||
|
@ -36,7 +37,7 @@ use hir;
|
||||||
// So you probably just want to nip down to the end.
|
// So you probably just want to nip down to the end.
|
||||||
macro_rules! language_item_table {
|
macro_rules! language_item_table {
|
||||||
(
|
(
|
||||||
$( $variant:ident, $name:expr, $method:ident; )*
|
$( $variant:ident, $name:expr, $method:ident, $target:path; )*
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
enum_from_u32! {
|
enum_from_u32! {
|
||||||
|
@ -96,26 +97,49 @@ impl LanguageItems {
|
||||||
|
|
||||||
struct LanguageItemCollector<'a, 'tcx: 'a> {
|
struct LanguageItemCollector<'a, 'tcx: 'a> {
|
||||||
items: LanguageItems,
|
items: LanguageItems,
|
||||||
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
item_refs: FxHashMap<&'static str, (usize, Target)>,
|
||||||
item_refs: FxHashMap<&'static str, usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
|
impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &hir::Item) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
if let Some((value, span)) = extract(&item.attrs) {
|
if let Some((value, span)) = extract(&item.attrs) {
|
||||||
let item_index = self.item_refs.get(&*value.as_str()).cloned();
|
let actual_target = Target::from_item(item);
|
||||||
|
match self.item_refs.get(&*value.as_str()).cloned() {
|
||||||
if let Some(item_index) = item_index {
|
// Known lang item with attribute on correct target.
|
||||||
|
Some((item_index, expected_target)) if actual_target == expected_target => {
|
||||||
let def_id = self.tcx.hir.local_def_id(item.id);
|
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||||
self.collect_item(item_index, def_id);
|
self.collect_item(item_index, def_id);
|
||||||
} else {
|
},
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0522,
|
// Known lang item with attribute on incorrect target.
|
||||||
"definition of an unknown language item: `{}`",
|
Some((_, expected_target)) => {
|
||||||
value);
|
let mut err = struct_span_err!(
|
||||||
err.span_label(span, format!("definition of unknown language item `{}`", value));
|
self.tcx.sess, span, E0718,
|
||||||
|
"`{}` language item must be applied to a {}",
|
||||||
|
value, expected_target,
|
||||||
|
);
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"attribute should be applied to a {}, not a {}",
|
||||||
|
expected_target, actual_target,
|
||||||
|
),
|
||||||
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
},
|
||||||
|
// Unknown lang item.
|
||||||
|
_ => {
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess, span, E0522,
|
||||||
|
"definition of an unknown language item: `{}`",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("definition of unknown language item `{}`", value)
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +157,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
|
||||||
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItemCollector<'a, 'tcx> {
|
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItemCollector<'a, 'tcx> {
|
||||||
let mut item_refs = FxHashMap();
|
let mut item_refs = FxHashMap();
|
||||||
|
|
||||||
$( item_refs.insert($name, $variant as usize); )*
|
$( item_refs.insert($name, ($variant as usize, $target)); )*
|
||||||
|
|
||||||
LanguageItemCollector {
|
LanguageItemCollector {
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -210,84 +234,84 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
language_item_table! {
|
language_item_table! {
|
||||||
// Variant name, Name, Method name;
|
// Variant name, Name, Method name, Target;
|
||||||
CharImplItem, "char", char_impl;
|
CharImplItem, "char", char_impl, Target::Impl;
|
||||||
StrImplItem, "str", str_impl;
|
StrImplItem, "str", str_impl, Target::Impl;
|
||||||
SliceImplItem, "slice", slice_impl;
|
SliceImplItem, "slice", slice_impl, Target::Impl;
|
||||||
SliceU8ImplItem, "slice_u8", slice_u8_impl;
|
SliceU8ImplItem, "slice_u8", slice_u8_impl, Target::Impl;
|
||||||
StrAllocImplItem, "str_alloc", str_alloc_impl;
|
StrAllocImplItem, "str_alloc", str_alloc_impl, Target::Impl;
|
||||||
SliceAllocImplItem, "slice_alloc", slice_alloc_impl;
|
SliceAllocImplItem, "slice_alloc", slice_alloc_impl, Target::Impl;
|
||||||
SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl;
|
SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Target::Impl;
|
||||||
ConstPtrImplItem, "const_ptr", const_ptr_impl;
|
ConstPtrImplItem, "const_ptr", const_ptr_impl, Target::Impl;
|
||||||
MutPtrImplItem, "mut_ptr", mut_ptr_impl;
|
MutPtrImplItem, "mut_ptr", mut_ptr_impl, Target::Impl;
|
||||||
I8ImplItem, "i8", i8_impl;
|
I8ImplItem, "i8", i8_impl, Target::Impl;
|
||||||
I16ImplItem, "i16", i16_impl;
|
I16ImplItem, "i16", i16_impl, Target::Impl;
|
||||||
I32ImplItem, "i32", i32_impl;
|
I32ImplItem, "i32", i32_impl, Target::Impl;
|
||||||
I64ImplItem, "i64", i64_impl;
|
I64ImplItem, "i64", i64_impl, Target::Impl;
|
||||||
I128ImplItem, "i128", i128_impl;
|
I128ImplItem, "i128", i128_impl, Target::Impl;
|
||||||
IsizeImplItem, "isize", isize_impl;
|
IsizeImplItem, "isize", isize_impl, Target::Impl;
|
||||||
U8ImplItem, "u8", u8_impl;
|
U8ImplItem, "u8", u8_impl, Target::Impl;
|
||||||
U16ImplItem, "u16", u16_impl;
|
U16ImplItem, "u16", u16_impl, Target::Impl;
|
||||||
U32ImplItem, "u32", u32_impl;
|
U32ImplItem, "u32", u32_impl, Target::Impl;
|
||||||
U64ImplItem, "u64", u64_impl;
|
U64ImplItem, "u64", u64_impl, Target::Impl;
|
||||||
U128ImplItem, "u128", u128_impl;
|
U128ImplItem, "u128", u128_impl, Target::Impl;
|
||||||
UsizeImplItem, "usize", usize_impl;
|
UsizeImplItem, "usize", usize_impl, Target::Impl;
|
||||||
F32ImplItem, "f32", f32_impl;
|
F32ImplItem, "f32", f32_impl, Target::Impl;
|
||||||
F64ImplItem, "f64", f64_impl;
|
F64ImplItem, "f64", f64_impl, Target::Impl;
|
||||||
F32RuntimeImplItem, "f32_runtime", f32_runtime_impl;
|
F32RuntimeImplItem, "f32_runtime", f32_runtime_impl, Target::Impl;
|
||||||
F64RuntimeImplItem, "f64_runtime", f64_runtime_impl;
|
F64RuntimeImplItem, "f64_runtime", f64_runtime_impl, Target::Impl;
|
||||||
|
|
||||||
SizedTraitLangItem, "sized", sized_trait;
|
SizedTraitLangItem, "sized", sized_trait, Target::Trait;
|
||||||
UnsizeTraitLangItem, "unsize", unsize_trait;
|
UnsizeTraitLangItem, "unsize", unsize_trait, Target::Trait;
|
||||||
CopyTraitLangItem, "copy", copy_trait;
|
CopyTraitLangItem, "copy", copy_trait, Target::Trait;
|
||||||
CloneTraitLangItem, "clone", clone_trait;
|
CloneTraitLangItem, "clone", clone_trait, Target::Trait;
|
||||||
SyncTraitLangItem, "sync", sync_trait;
|
SyncTraitLangItem, "sync", sync_trait, Target::Trait;
|
||||||
FreezeTraitLangItem, "freeze", freeze_trait;
|
FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait;
|
||||||
|
|
||||||
DropTraitLangItem, "drop", drop_trait;
|
DropTraitLangItem, "drop", drop_trait, Target::Trait;
|
||||||
|
|
||||||
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait;
|
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
|
||||||
|
|
||||||
AddTraitLangItem, "add", add_trait;
|
AddTraitLangItem, "add", add_trait, Target::Trait;
|
||||||
SubTraitLangItem, "sub", sub_trait;
|
SubTraitLangItem, "sub", sub_trait, Target::Trait;
|
||||||
MulTraitLangItem, "mul", mul_trait;
|
MulTraitLangItem, "mul", mul_trait, Target::Trait;
|
||||||
DivTraitLangItem, "div", div_trait;
|
DivTraitLangItem, "div", div_trait, Target::Trait;
|
||||||
RemTraitLangItem, "rem", rem_trait;
|
RemTraitLangItem, "rem", rem_trait, Target::Trait;
|
||||||
NegTraitLangItem, "neg", neg_trait;
|
NegTraitLangItem, "neg", neg_trait, Target::Trait;
|
||||||
NotTraitLangItem, "not", not_trait;
|
NotTraitLangItem, "not", not_trait, Target::Trait;
|
||||||
BitXorTraitLangItem, "bitxor", bitxor_trait;
|
BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait;
|
||||||
BitAndTraitLangItem, "bitand", bitand_trait;
|
BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait;
|
||||||
BitOrTraitLangItem, "bitor", bitor_trait;
|
BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait;
|
||||||
ShlTraitLangItem, "shl", shl_trait;
|
ShlTraitLangItem, "shl", shl_trait, Target::Trait;
|
||||||
ShrTraitLangItem, "shr", shr_trait;
|
ShrTraitLangItem, "shr", shr_trait, Target::Trait;
|
||||||
AddAssignTraitLangItem, "add_assign", add_assign_trait;
|
AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait;
|
||||||
SubAssignTraitLangItem, "sub_assign", sub_assign_trait;
|
SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait;
|
||||||
MulAssignTraitLangItem, "mul_assign", mul_assign_trait;
|
MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait;
|
||||||
DivAssignTraitLangItem, "div_assign", div_assign_trait;
|
DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait;
|
||||||
RemAssignTraitLangItem, "rem_assign", rem_assign_trait;
|
RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait;
|
||||||
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait;
|
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait;
|
||||||
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait;
|
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait;
|
||||||
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait;
|
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait;
|
||||||
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait;
|
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait;
|
||||||
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait;
|
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait;
|
||||||
IndexTraitLangItem, "index", index_trait;
|
IndexTraitLangItem, "index", index_trait, Target::Trait;
|
||||||
IndexMutTraitLangItem, "index_mut", index_mut_trait;
|
IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait;
|
||||||
|
|
||||||
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type;
|
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct;
|
||||||
|
|
||||||
DerefTraitLangItem, "deref", deref_trait;
|
DerefTraitLangItem, "deref", deref_trait, Target::Trait;
|
||||||
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;
|
DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait;
|
||||||
|
|
||||||
FnTraitLangItem, "fn", fn_trait;
|
FnTraitLangItem, "fn", fn_trait, Target::Trait;
|
||||||
FnMutTraitLangItem, "fn_mut", fn_mut_trait;
|
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;
|
||||||
FnOnceTraitLangItem, "fn_once", fn_once_trait;
|
FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait;
|
||||||
|
|
||||||
GeneratorStateLangItem, "generator_state", gen_state;
|
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
|
||||||
GeneratorTraitLangItem, "generator", gen_trait;
|
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;
|
||||||
|
|
||||||
EqTraitLangItem, "eq", eq_trait;
|
EqTraitLangItem, "eq", eq_trait, Target::Trait;
|
||||||
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait;
|
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait;
|
||||||
OrdTraitLangItem, "ord", ord_trait;
|
OrdTraitLangItem, "ord", ord_trait, Target::Trait;
|
||||||
|
|
||||||
// A number of panic-related lang items. The `panic` item corresponds to
|
// A number of panic-related lang items. The `panic` item corresponds to
|
||||||
// divide-by-zero and various panic cases with `match`. The
|
// divide-by-zero and various panic cases with `match`. The
|
||||||
|
@ -298,68 +322,68 @@ language_item_table! {
|
||||||
// defined to use it, but a final product is required to define it
|
// defined to use it, but a final product is required to define it
|
||||||
// somewhere. Additionally, there are restrictions on crates that use a weak
|
// somewhere. Additionally, there are restrictions on crates that use a weak
|
||||||
// lang item, but do not have it defined.
|
// lang item, but do not have it defined.
|
||||||
PanicFnLangItem, "panic", panic_fn;
|
PanicFnLangItem, "panic", panic_fn, Target::Fn;
|
||||||
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn;
|
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn;
|
||||||
PanicInfoLangItem, "panic_info", panic_info;
|
PanicInfoLangItem, "panic_info", panic_info, Target::Struct;
|
||||||
PanicImplLangItem, "panic_impl", panic_impl;
|
PanicImplLangItem, "panic_impl", panic_impl, Target::Fn;
|
||||||
// Libstd panic entry point. Necessary for const eval to be able to catch it
|
// Libstd panic entry point. Necessary for const eval to be able to catch it
|
||||||
BeginPanicFnLangItem, "begin_panic", begin_panic_fn;
|
BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn;
|
||||||
|
|
||||||
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
|
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Target::Fn;
|
||||||
BoxFreeFnLangItem, "box_free", box_free_fn;
|
BoxFreeFnLangItem, "box_free", box_free_fn, Target::Fn;
|
||||||
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
|
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Target::Fn;
|
||||||
OomLangItem, "oom", oom;
|
OomLangItem, "oom", oom, Target::Fn;
|
||||||
AllocLayoutLangItem, "alloc_layout", alloc_layout;
|
AllocLayoutLangItem, "alloc_layout", alloc_layout, Target::Struct;
|
||||||
|
|
||||||
StartFnLangItem, "start", start_fn;
|
StartFnLangItem, "start", start_fn, Target::Fn;
|
||||||
|
|
||||||
EhPersonalityLangItem, "eh_personality", eh_personality;
|
EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn;
|
||||||
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
|
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Target::Fn;
|
||||||
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
|
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter, Target::Static;
|
||||||
|
|
||||||
OwnedBoxLangItem, "owned_box", owned_box;
|
OwnedBoxLangItem, "owned_box", owned_box, Target::Struct;
|
||||||
|
|
||||||
PhantomDataItem, "phantom_data", phantom_data;
|
PhantomDataItem, "phantom_data", phantom_data, Target::Struct;
|
||||||
|
|
||||||
ManuallyDropItem, "manually_drop", manually_drop;
|
ManuallyDropItem, "manually_drop", manually_drop, Target::Struct;
|
||||||
|
|
||||||
DebugTraitLangItem, "debug_trait", debug_trait;
|
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
|
||||||
|
|
||||||
// A lang item for each of the 128-bit operators we can optionally lower.
|
// A lang item for each of the 128-bit operators we can optionally lower.
|
||||||
I128AddFnLangItem, "i128_add", i128_add_fn;
|
I128AddFnLangItem, "i128_add", i128_add_fn, Target::Fn;
|
||||||
U128AddFnLangItem, "u128_add", u128_add_fn;
|
U128AddFnLangItem, "u128_add", u128_add_fn, Target::Fn;
|
||||||
I128SubFnLangItem, "i128_sub", i128_sub_fn;
|
I128SubFnLangItem, "i128_sub", i128_sub_fn, Target::Fn;
|
||||||
U128SubFnLangItem, "u128_sub", u128_sub_fn;
|
U128SubFnLangItem, "u128_sub", u128_sub_fn, Target::Fn;
|
||||||
I128MulFnLangItem, "i128_mul", i128_mul_fn;
|
I128MulFnLangItem, "i128_mul", i128_mul_fn, Target::Fn;
|
||||||
U128MulFnLangItem, "u128_mul", u128_mul_fn;
|
U128MulFnLangItem, "u128_mul", u128_mul_fn, Target::Fn;
|
||||||
I128DivFnLangItem, "i128_div", i128_div_fn;
|
I128DivFnLangItem, "i128_div", i128_div_fn, Target::Fn;
|
||||||
U128DivFnLangItem, "u128_div", u128_div_fn;
|
U128DivFnLangItem, "u128_div", u128_div_fn, Target::Fn;
|
||||||
I128RemFnLangItem, "i128_rem", i128_rem_fn;
|
I128RemFnLangItem, "i128_rem", i128_rem_fn, Target::Fn;
|
||||||
U128RemFnLangItem, "u128_rem", u128_rem_fn;
|
U128RemFnLangItem, "u128_rem", u128_rem_fn, Target::Fn;
|
||||||
I128ShlFnLangItem, "i128_shl", i128_shl_fn;
|
I128ShlFnLangItem, "i128_shl", i128_shl_fn, Target::Fn;
|
||||||
U128ShlFnLangItem, "u128_shl", u128_shl_fn;
|
U128ShlFnLangItem, "u128_shl", u128_shl_fn, Target::Fn;
|
||||||
I128ShrFnLangItem, "i128_shr", i128_shr_fn;
|
I128ShrFnLangItem, "i128_shr", i128_shr_fn, Target::Fn;
|
||||||
U128ShrFnLangItem, "u128_shr", u128_shr_fn;
|
U128ShrFnLangItem, "u128_shr", u128_shr_fn, Target::Fn;
|
||||||
// And overflow versions for the operators that are checkable.
|
// And overflow versions for the operators that are checkable.
|
||||||
// While MIR calls these Checked*, they return (T,bool), not Option<T>.
|
// While MIR calls these Checked*, they return (T,bool), not Option<T>.
|
||||||
I128AddoFnLangItem, "i128_addo", i128_addo_fn;
|
I128AddoFnLangItem, "i128_addo", i128_addo_fn, Target::Fn;
|
||||||
U128AddoFnLangItem, "u128_addo", u128_addo_fn;
|
U128AddoFnLangItem, "u128_addo", u128_addo_fn, Target::Fn;
|
||||||
I128SuboFnLangItem, "i128_subo", i128_subo_fn;
|
I128SuboFnLangItem, "i128_subo", i128_subo_fn, Target::Fn;
|
||||||
U128SuboFnLangItem, "u128_subo", u128_subo_fn;
|
U128SuboFnLangItem, "u128_subo", u128_subo_fn, Target::Fn;
|
||||||
I128MuloFnLangItem, "i128_mulo", i128_mulo_fn;
|
I128MuloFnLangItem, "i128_mulo", i128_mulo_fn, Target::Fn;
|
||||||
U128MuloFnLangItem, "u128_mulo", u128_mulo_fn;
|
U128MuloFnLangItem, "u128_mulo", u128_mulo_fn, Target::Fn;
|
||||||
I128ShloFnLangItem, "i128_shlo", i128_shlo_fn;
|
I128ShloFnLangItem, "i128_shlo", i128_shlo_fn, Target::Fn;
|
||||||
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn;
|
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn, Target::Fn;
|
||||||
I128ShroFnLangItem, "i128_shro", i128_shro_fn;
|
I128ShroFnLangItem, "i128_shro", i128_shro_fn, Target::Fn;
|
||||||
U128ShroFnLangItem, "u128_shro", u128_shro_fn;
|
U128ShroFnLangItem, "u128_shro", u128_shro_fn, Target::Fn;
|
||||||
|
|
||||||
// Align offset for stride != 1, must not panic.
|
// Align offset for stride != 1, must not panic.
|
||||||
AlignOffsetLangItem, "align_offset", align_offset_fn;
|
AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn;
|
||||||
|
|
||||||
TerminationTraitLangItem, "termination", termination;
|
TerminationTraitLangItem, "termination", termination, Target::Trait;
|
||||||
|
|
||||||
Arc, "arc", arc;
|
Arc, "arc", arc, Target::Struct;
|
||||||
Rc, "rc", rc;
|
Rc, "rc", rc, Target::Struct;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
|
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
|
||||||
|
|
|
@ -418,9 +418,7 @@ fn fundamental_ty(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>) -> bool {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Ref(..) => true,
|
ty::Ref(..) => true,
|
||||||
ty::Adt(def, _) => def.is_fundamental(),
|
ty::Adt(def, _) => def.is_fundamental(),
|
||||||
ty::Dynamic(ref data, ..) => {
|
ty::Dynamic(ref data, ..) => tcx.has_attr(data.principal().def_id(), "fundamental"),
|
||||||
data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental"))
|
|
||||||
}
|
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,11 +465,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||||
ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
|
ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
|
||||||
ty::Foreign(did) => def_id_is_local(did, in_crate),
|
ty::Foreign(did) => def_id_is_local(did, in_crate),
|
||||||
|
|
||||||
ty::Dynamic(ref tt, ..) => {
|
ty::Dynamic(ref tt, ..) => def_id_is_local(tt.principal().def_id(), in_crate),
|
||||||
tt.principal().map_or(false, |p|
|
|
||||||
def_id_is_local(p.def_id(), in_crate)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Error => true,
|
ty::Error => true,
|
||||||
|
|
||||||
|
|
|
@ -2088,10 +2088,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match data.principal() {
|
data.principal().with_self_ty(this.tcx(), self_ty)
|
||||||
Some(p) => p.with_self_ty(this.tcx(), self_ty),
|
|
||||||
None => return,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::Infer(ty::TyVar(_)) => {
|
ty::Infer(ty::TyVar(_)) => {
|
||||||
debug!("assemble_candidates_from_object_ty: ambiguous");
|
debug!("assemble_candidates_from_object_ty: ambiguous");
|
||||||
|
@ -2183,16 +2180,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
//
|
//
|
||||||
// We always upcast when we can because of reason
|
// We always upcast when we can because of reason
|
||||||
// #2 (region bounds).
|
// #2 (region bounds).
|
||||||
match (data_a.principal(), data_b.principal()) {
|
data_a.principal().def_id() == data_b.principal().def_id()
|
||||||
(Some(a), Some(b)) => {
|
|
||||||
a.def_id() == b.def_id()
|
|
||||||
&& data_b.auto_traits()
|
&& data_b.auto_traits()
|
||||||
// All of a's auto traits need to be in b's auto traits.
|
// All of a's auto traits need to be in b's auto traits.
|
||||||
.all(|b| data_a.auto_traits().any(|a| a == b))
|
.all(|b| data_a.auto_traits().any(|a| a == b))
|
||||||
}
|
}
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// T -> Trait.
|
// T -> Trait.
|
||||||
(_, &ty::Dynamic(..)) => true,
|
(_, &ty::Dynamic(..)) => true,
|
||||||
|
@ -2981,7 +2973,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
.shallow_resolve(*obligation.self_ty().skip_binder());
|
.shallow_resolve(*obligation.self_ty().skip_binder());
|
||||||
let poly_trait_ref = match self_ty.sty {
|
let poly_trait_ref = match self_ty.sty {
|
||||||
ty::Dynamic(ref data, ..) => {
|
ty::Dynamic(ref data, ..) => {
|
||||||
data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
|
data.principal().with_self_ty(self.tcx(), self_ty)
|
||||||
}
|
}
|
||||||
_ => span_bug!(obligation.cause.span, "object candidate with non-object"),
|
_ => span_bug!(obligation.cause.span, "object candidate with non-object"),
|
||||||
};
|
};
|
||||||
|
@ -3244,10 +3236,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||||
// See assemble_candidates_for_unsizing for more info.
|
// See assemble_candidates_for_unsizing for more info.
|
||||||
let existential_predicates = data_a.map_bound(|data_a| {
|
let existential_predicates = data_a.map_bound(|data_a| {
|
||||||
let principal = data_a.principal();
|
let iter = iter::once(ty::ExistentialPredicate::Trait(data_a.principal()))
|
||||||
let iter = principal
|
|
||||||
.into_iter()
|
|
||||||
.map(ty::ExistentialPredicate::Trait)
|
|
||||||
.chain(
|
.chain(
|
||||||
data_a
|
data_a
|
||||||
.projection_bounds()
|
.projection_bounds()
|
||||||
|
@ -3285,7 +3274,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
// T -> Trait.
|
// T -> Trait.
|
||||||
(_, &ty::Dynamic(ref data, r)) => {
|
(_, &ty::Dynamic(ref data, r)) => {
|
||||||
let mut object_dids = data.auto_traits()
|
let mut object_dids = data.auto_traits()
|
||||||
.chain(data.principal().map(|p| p.def_id()));
|
.chain(iter::once(data.principal().def_id()));
|
||||||
if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
|
if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
|
||||||
return Err(TraitNotObjectSafe(did));
|
return Err(TraitNotObjectSafe(did));
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,8 +208,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
||||||
ty::FnDef(..) => "fn item".into(),
|
ty::FnDef(..) => "fn item".into(),
|
||||||
ty::FnPtr(_) => "fn pointer".into(),
|
ty::FnPtr(_) => "fn pointer".into(),
|
||||||
ty::Dynamic(ref inner, ..) => {
|
ty::Dynamic(ref inner, ..) => {
|
||||||
inner.principal().map_or_else(|| "trait".into(),
|
format!("trait {}", tcx.item_path_str(inner.principal().def_id())).into()
|
||||||
|p| format!("trait {}", tcx.item_path_str(p.def_id())).into())
|
|
||||||
}
|
}
|
||||||
ty::Closure(..) => "closure".into(),
|
ty::Closure(..) => "closure".into(),
|
||||||
ty::Generator(..) => "generator".into(),
|
ty::Generator(..) => "generator".into(),
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
|
ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
|
||||||
ty::RawPtr(_) => Some(PtrSimplifiedType),
|
ty::RawPtr(_) => Some(PtrSimplifiedType),
|
||||||
ty::Dynamic(ref trait_info, ..) => {
|
ty::Dynamic(ref trait_info, ..) => {
|
||||||
trait_info.principal().map(|p| TraitSimplifiedType(p.def_id()))
|
Some(TraitSimplifiedType(trait_info.principal().def_id()))
|
||||||
}
|
}
|
||||||
ty::Ref(_, ty, _) => {
|
ty::Ref(_, ty, _) => {
|
||||||
// since we introduce auto-refs during method lookup, we
|
// since we introduce auto-refs during method lookup, we
|
||||||
|
|
|
@ -436,7 +436,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Adt(adt_def, _) => Some(adt_def.did),
|
ty::Adt(adt_def, _) => Some(adt_def.did),
|
||||||
|
|
||||||
ty::Dynamic(data, ..) => data.principal().map(|p| p.def_id()),
|
ty::Dynamic(data, ..) => Some(data.principal().def_id()),
|
||||||
|
|
||||||
ty::Array(subty, _) |
|
ty::Array(subty, _) |
|
||||||
ty::Slice(subty) => characteristic_def_id_of_type(subty),
|
ty::Slice(subty) => characteristic_def_id_of_type(subty),
|
||||||
|
|
|
@ -559,10 +559,10 @@ impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> {
|
||||||
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {}
|
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {}
|
||||||
|
|
||||||
impl<'tcx> List<ExistentialPredicate<'tcx>> {
|
impl<'tcx> List<ExistentialPredicate<'tcx>> {
|
||||||
pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
|
pub fn principal(&self) -> ExistentialTraitRef<'tcx> {
|
||||||
match self.get(0) {
|
match self[0] {
|
||||||
Some(&ExistentialPredicate::Trait(tr)) => Some(tr),
|
ExistentialPredicate::Trait(tr) => tr,
|
||||||
_ => None,
|
other => bug!("first predicate is {:?}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,8 +589,8 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
|
impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
|
||||||
pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> {
|
pub fn principal(&self) -> PolyExistentialTraitRef<'tcx> {
|
||||||
self.skip_binder().principal().map(Binder::bind)
|
Binder::bind(self.skip_binder().principal())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1825,9 +1825,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
Dynamic(ref obj, region) => {
|
Dynamic(ref obj, region) => {
|
||||||
let mut v = vec![region];
|
let mut v = vec![region];
|
||||||
if let Some(p) = obj.principal() {
|
v.extend(obj.principal().skip_binder().substs.regions());
|
||||||
v.extend(p.skip_binder().substs.regions());
|
|
||||||
}
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
Adt(_, substs) | Opaque(_, substs) => {
|
Adt(_, substs) | Opaque(_, substs) => {
|
||||||
|
|
|
@ -387,7 +387,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let cause = self.cause(traits::MiscObligation);
|
let cause = self.cause(traits::MiscObligation);
|
||||||
let component_traits =
|
let component_traits =
|
||||||
data.auto_traits().chain(data.principal().map(|p| p.def_id()));
|
data.auto_traits().chain(once(data.principal().def_id()));
|
||||||
self.out.extend(
|
self.out.extend(
|
||||||
component_traits.map(|did| traits::Obligation::new(
|
component_traits.map(|did| traits::Obligation::new(
|
||||||
cause.clone(),
|
cause.clone(),
|
||||||
|
|
|
@ -621,8 +621,9 @@ define_print! {
|
||||||
// Use a type that can't appear in defaults of type parameters.
|
// Use a type that can't appear in defaults of type parameters.
|
||||||
let dummy_self = tcx.mk_infer(ty::FreshTy(0));
|
let dummy_self = tcx.mk_infer(ty::FreshTy(0));
|
||||||
|
|
||||||
if let Some(p) = self.principal() {
|
let principal = tcx
|
||||||
let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
|
.lift(&self.principal())
|
||||||
|
.expect("could not lift TraitRef for printing")
|
||||||
.with_self_ty(tcx, dummy_self);
|
.with_self_ty(tcx, dummy_self);
|
||||||
let projections = self.projection_bounds().map(|p| {
|
let projections = self.projection_bounds().map(|p| {
|
||||||
tcx.lift(&p)
|
tcx.lift(&p)
|
||||||
|
@ -630,7 +631,6 @@ define_print! {
|
||||||
.with_self_ty(tcx, dummy_self)
|
.with_self_ty(tcx, dummy_self)
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
|
cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
|
||||||
}
|
|
||||||
|
|
||||||
// Builtin bounds.
|
// Builtin bounds.
|
||||||
for did in self.auto_traits() {
|
for did in self.auto_traits() {
|
||||||
|
|
|
@ -536,7 +536,10 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
|
||||||
// Note that the platform intrinsic ABI is exempt here as
|
// Note that the platform intrinsic ABI is exempt here as
|
||||||
// that's how we connect up to LLVM and it's unstable
|
// that's how we connect up to LLVM and it's unstable
|
||||||
// anyway, we control all calls to it in libstd.
|
// anyway, we control all calls to it in libstd.
|
||||||
layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => {
|
layout::Abi::Vector { .. }
|
||||||
|
if abi != Abi::PlatformIntrinsic &&
|
||||||
|
cx.sess().target.target.options.simd_types_indirect =>
|
||||||
|
{
|
||||||
arg.make_indirect();
|
arg.make_indirect();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub struct CodegenCx<'a, 'tcx: 'a> {
|
||||||
/// Cache instances of monomorphic and polymorphic items
|
/// Cache instances of monomorphic and polymorphic items
|
||||||
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'a Value>>,
|
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'a Value>>,
|
||||||
/// Cache generated vtables
|
/// Cache generated vtables
|
||||||
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
|
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>),
|
||||||
&'a Value>>,
|
&'a Value>>,
|
||||||
/// Cache of constant strings,
|
/// Cache of constant strings,
|
||||||
pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'a Value>>,
|
pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'a Value>>,
|
||||||
|
|
|
@ -435,12 +435,7 @@ fn trait_pointer_metadata(
|
||||||
// But it does not describe the trait's methods.
|
// But it does not describe the trait's methods.
|
||||||
|
|
||||||
let containing_scope = match trait_type.sty {
|
let containing_scope = match trait_type.sty {
|
||||||
ty::Dynamic(ref data, ..) => if let Some(principal) = data.principal() {
|
ty::Dynamic(ref data, ..) => Some(get_namespace_for_item(cx, data.principal().def_id())),
|
||||||
let def_id = principal.def_id();
|
|
||||||
Some(get_namespace_for_item(cx, def_id))
|
|
||||||
} else {
|
|
||||||
NO_SCOPE_METADATA
|
|
||||||
},
|
|
||||||
_ => {
|
_ => {
|
||||||
bug!("debuginfo: Unexpected trait-object type in \
|
bug!("debuginfo: Unexpected trait-object type in \
|
||||||
trait_pointer_metadata(): {:?}",
|
trait_pointer_metadata(): {:?}",
|
||||||
|
|
|
@ -116,14 +116,12 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ty::Dynamic(ref trait_data, ..) => {
|
ty::Dynamic(ref trait_data, ..) => {
|
||||||
if let Some(principal) = trait_data.principal() {
|
|
||||||
let principal = cx.tcx.normalize_erasing_late_bound_regions(
|
let principal = cx.tcx.normalize_erasing_late_bound_regions(
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
&principal,
|
&trait_data.principal(),
|
||||||
);
|
);
|
||||||
push_item_name(cx, principal.def_id, false, output);
|
push_item_name(cx, principal.def_id, false, output);
|
||||||
push_type_params(cx, principal.substs, output);
|
push_type_params(cx, principal.substs, output);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||||
let sig = t.fn_sig(cx.tcx);
|
let sig = t.fn_sig(cx.tcx);
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl<'a, 'tcx> VirtualIndex {
|
||||||
pub fn get_vtable(
|
pub fn get_vtable(
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
trait_ref: ty::PolyExistentialTraitRef<'tcx>,
|
||||||
) -> &'ll Value {
|
) -> &'ll Value {
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
|
|
||||||
|
@ -86,23 +86,19 @@ pub fn get_vtable(
|
||||||
// Not in the cache. Build it.
|
// Not in the cache. Build it.
|
||||||
let nullptr = C_null(Type::i8p(cx));
|
let nullptr = C_null(Type::i8p(cx));
|
||||||
|
|
||||||
let (size, align) = cx.size_and_align_of(ty);
|
let methods = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
|
||||||
let mut components: Vec<_> = [
|
|
||||||
callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)),
|
|
||||||
C_usize(cx, size.bytes()),
|
|
||||||
C_usize(cx, align.abi())
|
|
||||||
].iter().cloned().collect();
|
|
||||||
|
|
||||||
if let Some(trait_ref) = trait_ref {
|
|
||||||
let trait_ref = trait_ref.with_self_ty(tcx, ty);
|
|
||||||
let methods = tcx.vtable_methods(trait_ref);
|
|
||||||
let methods = methods.iter().cloned().map(|opt_mth| {
|
let methods = methods.iter().cloned().map(|opt_mth| {
|
||||||
opt_mth.map_or(nullptr, |(def_id, substs)| {
|
opt_mth.map_or(nullptr, |(def_id, substs)| {
|
||||||
callee::resolve_and_get_fn(cx, def_id, substs)
|
callee::resolve_and_get_fn(cx, def_id, substs)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
components.extend(methods);
|
|
||||||
}
|
let (size, align) = cx.size_and_align_of(ty);
|
||||||
|
let components: Vec<_> = [
|
||||||
|
callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)),
|
||||||
|
C_usize(cx, size.bytes()),
|
||||||
|
C_usize(cx, align.abi())
|
||||||
|
].iter().cloned().chain(methods).collect();
|
||||||
|
|
||||||
let vtable_const = C_struct(cx, &components, false);
|
let vtable_const = C_struct(cx, &components, false);
|
||||||
let align = cx.data_layout().pointer_align;
|
let align = cx.data_layout().pointer_align;
|
||||||
|
|
|
@ -44,7 +44,7 @@ use serialize::json;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::OsString;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -1021,6 +1021,7 @@ where
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
missing_fragment_specifiers.sort();
|
missing_fragment_specifiers.sort();
|
||||||
|
|
||||||
for span in missing_fragment_specifiers {
|
for span in missing_fragment_specifiers {
|
||||||
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
|
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
|
||||||
let msg = "missing fragment specifier";
|
let msg = "missing fragment specifier";
|
||||||
|
@ -1472,7 +1473,7 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[Pa
|
||||||
.collect();
|
.collect();
|
||||||
let mut file = fs::File::create(&deps_filename)?;
|
let mut file = fs::File::create(&deps_filename)?;
|
||||||
for path in out_filenames {
|
for path in out_filenames {
|
||||||
write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
|
writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit a fake target for each input file to the compilation. This
|
// Emit a fake target for each input file to the compilation. This
|
||||||
|
@ -1484,16 +1485,13 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[Pa
|
||||||
Ok(())
|
Ok(())
|
||||||
})();
|
})();
|
||||||
|
|
||||||
match result {
|
if let Err(e) = result {
|
||||||
Ok(()) => {}
|
|
||||||
Err(e) => {
|
|
||||||
sess.fatal(&format!(
|
sess.fatal(&format!(
|
||||||
"error writing dependencies to `{}`: {}",
|
"error writing dependencies to `{}`: {}",
|
||||||
deps_filename.display(),
|
deps_filename.display(),
|
||||||
e
|
e
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
|
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
|
||||||
|
@ -1520,6 +1518,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
|
||||||
Symbol::intern("proc-macro"),
|
Symbol::intern("proc-macro"),
|
||||||
Symbol::intern("bin")
|
Symbol::intern("bin")
|
||||||
];
|
];
|
||||||
|
|
||||||
if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().node {
|
if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().node {
|
||||||
let span = spanned.span;
|
let span = spanned.span;
|
||||||
let lev_candidate = find_best_match_for_name(
|
let lev_candidate = find_best_match_for_name(
|
||||||
|
@ -1551,7 +1550,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => {
|
None => {
|
||||||
session
|
session
|
||||||
.struct_span_err(a.span, "`crate_type` requires a value")
|
.struct_span_err(a.span, "`crate_type` requires a value")
|
||||||
.note("for example: `#![crate_type=\"lib\"]`")
|
.note("for example: `#![crate_type=\"lib\"]`")
|
||||||
|
@ -1581,13 +1580,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
|
||||||
base.push(::rustc_codegen_utils::link::default_output_for_target(
|
base.push(::rustc_codegen_utils::link::default_output_for_target(
|
||||||
session,
|
session,
|
||||||
));
|
));
|
||||||
}
|
} else {
|
||||||
base.sort();
|
base.sort();
|
||||||
base.dedup();
|
base.dedup();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
base.into_iter()
|
base.retain(|crate_type| {
|
||||||
.filter(|crate_type| {
|
|
||||||
let res = !::rustc_codegen_utils::link::invalid_output_for_target(session, *crate_type);
|
let res = !::rustc_codegen_utils::link::invalid_output_for_target(session, *crate_type);
|
||||||
|
|
||||||
if !res {
|
if !res {
|
||||||
|
@ -1598,8 +1597,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
})
|
});
|
||||||
.collect()
|
|
||||||
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
|
pub fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
|
||||||
|
@ -1650,17 +1650,14 @@ pub fn build_output_filenames(
|
||||||
// "-" as input file will cause the parser to read from stdin so we
|
// "-" as input file will cause the parser to read from stdin so we
|
||||||
// have to make up a name
|
// have to make up a name
|
||||||
// We want to toss everything after the final '.'
|
// We want to toss everything after the final '.'
|
||||||
let dirpath = match *odir {
|
let dirpath = (*odir).as_ref().cloned().unwrap_or_default();
|
||||||
Some(ref d) => d.clone(),
|
|
||||||
None => PathBuf::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// If a crate name is present, we use it as the link name
|
// If a crate name is present, we use it as the link name
|
||||||
let stem = sess.opts
|
let stem = sess.opts
|
||||||
.crate_name
|
.crate_name
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
|
.or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
|
||||||
.unwrap_or(input.filestem());
|
.unwrap_or_else(|| input.filestem());
|
||||||
|
|
||||||
OutputFilenames {
|
OutputFilenames {
|
||||||
out_directory: dirpath,
|
out_directory: dirpath,
|
||||||
|
@ -1693,13 +1690,11 @@ pub fn build_output_filenames(
|
||||||
sess.warn("ignoring -C extra-filename flag due to -o flag");
|
sess.warn("ignoring -C extra-filename flag due to -o flag");
|
||||||
}
|
}
|
||||||
|
|
||||||
let cur_dir = Path::new("");
|
|
||||||
|
|
||||||
OutputFilenames {
|
OutputFilenames {
|
||||||
out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
|
out_directory: out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
|
||||||
out_filestem: out_file
|
out_filestem: out_file
|
||||||
.file_stem()
|
.file_stem()
|
||||||
.unwrap_or(OsStr::new(""))
|
.unwrap_or_default()
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|
|
@ -89,6 +89,7 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
use serialize::json::ToJson;
|
use serialize::json::ToJson;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||||
|
@ -136,9 +137,7 @@ pub mod target_features {
|
||||||
codegen_backend: &dyn CodegenBackend) {
|
codegen_backend: &dyn CodegenBackend) {
|
||||||
let tf = Symbol::intern("target_feature");
|
let tf = Symbol::intern("target_feature");
|
||||||
|
|
||||||
for feat in codegen_backend.target_features(sess) {
|
cfg.extend(codegen_backend.target_features(sess).into_iter().map(|feat| (tf, Some(feat))));
|
||||||
cfg.insert((tf, Some(feat)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if sess.crt_static_feature() {
|
if sess.crt_static_feature() {
|
||||||
cfg.insert((tf, Some(Symbol::intern("crt-static"))));
|
cfg.insert((tf, Some(Symbol::intern("crt-static"))));
|
||||||
|
@ -152,21 +151,14 @@ pub const EXIT_SUCCESS: isize = 0;
|
||||||
/// Exit status code used for compilation failures and invalid flags.
|
/// Exit status code used for compilation failures and invalid flags.
|
||||||
pub const EXIT_FAILURE: isize = 1;
|
pub const EXIT_FAILURE: isize = 1;
|
||||||
|
|
||||||
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
|
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
|
||||||
md#bug-reports";
|
md#bug-reports";
|
||||||
|
|
||||||
const ICE_REPORT_COMPILER_FLAGS: &'static [&'static str] = &[
|
const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"];
|
||||||
"Z",
|
|
||||||
"C",
|
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
|
||||||
"crate-type",
|
|
||||||
];
|
const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
|
||||||
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &'static [&'static str] = &[
|
|
||||||
"metadata",
|
|
||||||
"extra-filename",
|
|
||||||
];
|
|
||||||
const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &'static [&'static str] = &[
|
|
||||||
"incremental",
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
|
pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
|
||||||
match result {
|
match result {
|
||||||
|
@ -195,10 +187,12 @@ pub fn run<F>(run_compiler: F) -> isize
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let emitter =
|
let emitter =
|
||||||
errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
|
errors::emitter::EmitterWriter::stderr(
|
||||||
|
errors::ColorConfig::Auto,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
false);
|
false
|
||||||
|
);
|
||||||
let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
|
let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
|
||||||
handler.emit(&MultiSpan::new(),
|
handler.emit(&MultiSpan::new(),
|
||||||
"aborting due to previous error(s)",
|
"aborting due to previous error(s)",
|
||||||
|
@ -224,15 +218,10 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
|
||||||
// available for future dynamic libraries opened. This is currently used by
|
// available for future dynamic libraries opened. This is currently used by
|
||||||
// loading LLVM and then making its symbols available for other dynamic
|
// loading LLVM and then making its symbols available for other dynamic
|
||||||
// libraries.
|
// libraries.
|
||||||
let lib = match DynamicLibrary::open_global_now(path) {
|
let lib = DynamicLibrary::open_global_now(path).unwrap_or_else(|err| {
|
||||||
Ok(lib) => lib,
|
let err = format!("couldn't load codegen backend {:?}: {:?}", path, err);
|
||||||
Err(err) => {
|
|
||||||
let err = format!("couldn't load codegen backend {:?}: {:?}",
|
|
||||||
path,
|
|
||||||
err);
|
|
||||||
early_error(ErrorOutputType::default(), &err);
|
early_error(ErrorOutputType::default(), &err);
|
||||||
}
|
});
|
||||||
};
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match lib.symbol("__rustc_codegen_backend") {
|
match lib.symbol("__rustc_codegen_backend") {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
|
@ -328,18 +317,15 @@ fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
|
||||||
let sysroot = sysroot_candidates.iter()
|
let sysroot = sysroot_candidates.iter()
|
||||||
.map(|sysroot| {
|
.map(|sysroot| {
|
||||||
let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
|
let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
|
||||||
sysroot.join(libdir)
|
sysroot.join(libdir).with_file_name(
|
||||||
.with_file_name(option_env!("CFG_CODEGEN_BACKENDS_DIR")
|
option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
|
||||||
.unwrap_or("codegen-backends"))
|
|
||||||
})
|
})
|
||||||
.filter(|f| {
|
.filter(|f| {
|
||||||
info!("codegen backend candidate: {}", f.display());
|
info!("codegen backend candidate: {}", f.display());
|
||||||
f.exists()
|
f.exists()
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
let sysroot = match sysroot {
|
let sysroot = sysroot.unwrap_or_else(|| {
|
||||||
Some(path) => path,
|
|
||||||
None => {
|
|
||||||
let candidates = sysroot_candidates.iter()
|
let candidates = sysroot_candidates.iter()
|
||||||
.map(|p| p.display().to_string())
|
.map(|p| p.display().to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -347,18 +333,14 @@ fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
|
||||||
let err = format!("failed to find a `codegen-backends` folder \
|
let err = format!("failed to find a `codegen-backends` folder \
|
||||||
in the sysroot candidates:\n* {}", candidates);
|
in the sysroot candidates:\n* {}", candidates);
|
||||||
early_error(ErrorOutputType::default(), &err);
|
early_error(ErrorOutputType::default(), &err);
|
||||||
}
|
});
|
||||||
};
|
|
||||||
info!("probing {} for a codegen backend", sysroot.display());
|
info!("probing {} for a codegen backend", sysroot.display());
|
||||||
|
|
||||||
let d = match sysroot.read_dir() {
|
let d = sysroot.read_dir().unwrap_or_else(|e| {
|
||||||
Ok(d) => d,
|
|
||||||
Err(e) => {
|
|
||||||
let err = format!("failed to load default codegen backend, couldn't \
|
let err = format!("failed to load default codegen backend, couldn't \
|
||||||
read `{}`: {}", sysroot.display(), e);
|
read `{}`: {}", sysroot.display(), e);
|
||||||
early_error(ErrorOutputType::default(), &err);
|
early_error(ErrorOutputType::default(), &err);
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
let mut file: Option<PathBuf> = None;
|
let mut file: Option<PathBuf> = None;
|
||||||
|
|
||||||
|
@ -578,7 +560,7 @@ pub fn set_sigpipe_handler() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Set the SIGPIPE signal handler, so that an EPIPE
|
// Set the SIGPIPE signal handler, so that an EPIPE
|
||||||
// will cause rustc to terminate, as expected.
|
// will cause rustc to terminate, as expected.
|
||||||
assert!(libc::signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR);
|
assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,7 +978,7 @@ impl RustcDefaultCalls {
|
||||||
input: &Input)
|
input: &Input)
|
||||||
-> Compilation {
|
-> Compilation {
|
||||||
let r = matches.opt_strs("Z");
|
let r = matches.opt_strs("Z");
|
||||||
if r.contains(&("ls".to_string())) {
|
if r.iter().any(|s| *s == "ls") {
|
||||||
match input {
|
match input {
|
||||||
&Input::File(ref ifile) => {
|
&Input::File(ref ifile) => {
|
||||||
let path = &(*ifile);
|
let path = &(*ifile);
|
||||||
|
@ -1015,7 +997,7 @@ impl RustcDefaultCalls {
|
||||||
return Compilation::Stop;
|
return Compilation::Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compilation::Continue;
|
Compilation::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1028,7 +1010,7 @@ impl RustcDefaultCalls {
|
||||||
use rustc::session::config::PrintRequest::*;
|
use rustc::session::config::PrintRequest::*;
|
||||||
// PrintRequest::NativeStaticLibs is special - printed during linking
|
// PrintRequest::NativeStaticLibs is special - printed during linking
|
||||||
// (empty iterator returns true)
|
// (empty iterator returns true)
|
||||||
if sess.opts.prints.iter().all(|&p| p==PrintRequest::NativeStaticLibs) {
|
if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
|
||||||
return Compilation::Continue;
|
return Compilation::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,10 +1037,8 @@ impl RustcDefaultCalls {
|
||||||
Sysroot => println!("{}", sess.sysroot().display()),
|
Sysroot => println!("{}", sess.sysroot().display()),
|
||||||
TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
|
TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
|
||||||
FileNames | CrateName => {
|
FileNames | CrateName => {
|
||||||
let input = match input {
|
let input = input.unwrap_or_else(||
|
||||||
Some(input) => input,
|
early_error(ErrorOutputType::default(), "no input file provided"));
|
||||||
None => early_error(ErrorOutputType::default(), "no input file provided"),
|
|
||||||
};
|
|
||||||
let attrs = attrs.as_ref().unwrap();
|
let attrs = attrs.as_ref().unwrap();
|
||||||
let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
|
let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
|
||||||
let id = rustc_codegen_utils::link::find_crate_name(Some(sess), attrs, input);
|
let id = rustc_codegen_utils::link::find_crate_name(Some(sess), attrs, input);
|
||||||
|
@ -1074,18 +1054,14 @@ impl RustcDefaultCalls {
|
||||||
&id,
|
&id,
|
||||||
&t_outputs
|
&t_outputs
|
||||||
);
|
);
|
||||||
println!("{}",
|
println!("{}", fname.file_name().unwrap().to_string_lossy());
|
||||||
fname.file_name()
|
|
||||||
.unwrap()
|
|
||||||
.to_string_lossy());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cfg => {
|
Cfg => {
|
||||||
let allow_unstable_cfg = UnstableFeatures::from_environment()
|
let allow_unstable_cfg = UnstableFeatures::from_environment()
|
||||||
.is_nightly_build();
|
.is_nightly_build();
|
||||||
|
|
||||||
let mut cfgs = Vec::new();
|
let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| {
|
||||||
for &(name, ref value) in sess.parse_sess.config.iter() {
|
|
||||||
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
|
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
|
||||||
ident: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)),
|
ident: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)),
|
||||||
node: ast::MetaItemKind::Word,
|
node: ast::MetaItemKind::Word,
|
||||||
|
@ -1104,16 +1080,16 @@ impl RustcDefaultCalls {
|
||||||
let value = value.as_ref().map(|s| s.as_ref());
|
let value = value.as_ref().map(|s| s.as_ref());
|
||||||
if name != "target_feature" || value != Some("crt-static") {
|
if name != "target_feature" || value != Some("crt-static") {
|
||||||
if !allow_unstable_cfg && gated_cfg.is_some() {
|
if !allow_unstable_cfg && gated_cfg.is_some() {
|
||||||
continue;
|
return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgs.push(if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
format!("{}=\"{}\"", name, value)
|
Some(format!("{}=\"{}\"", name, value))
|
||||||
} else {
|
} else {
|
||||||
name.to_string()
|
Some(name.to_string())
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}).collect::<Vec<String>>();
|
||||||
|
|
||||||
cfgs.sort();
|
cfgs.sort();
|
||||||
for cfg in cfgs {
|
for cfg in cfgs {
|
||||||
|
@ -1150,9 +1126,8 @@ fn commit_date_str() -> Option<&'static str> {
|
||||||
pub fn version(binary: &str, matches: &getopts::Matches) {
|
pub fn version(binary: &str, matches: &getopts::Matches) {
|
||||||
let verbose = matches.opt_present("verbose");
|
let verbose = matches.opt_present("verbose");
|
||||||
|
|
||||||
println!("{} {}",
|
println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version"));
|
||||||
binary,
|
|
||||||
option_env!("CFG_VERSION").unwrap_or("unknown version"));
|
|
||||||
if verbose {
|
if verbose {
|
||||||
fn unw(x: Option<&str>) -> &str {
|
fn unw(x: Option<&str>) -> &str {
|
||||||
x.unwrap_or("unknown")
|
x.unwrap_or("unknown")
|
||||||
|
@ -1176,7 +1151,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
|
||||||
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
|
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
|
||||||
(option.apply)(&mut options);
|
(option.apply)(&mut options);
|
||||||
}
|
}
|
||||||
let message = "Usage: rustc [OPTIONS] INPUT".to_string();
|
let message = "Usage: rustc [OPTIONS] INPUT";
|
||||||
let nightly_help = if nightly_options::is_nightly_build() {
|
let nightly_help = if nightly_options::is_nightly_build() {
|
||||||
"\n -Z help Print internal options for debugging rustc"
|
"\n -Z help Print internal options for debugging rustc"
|
||||||
} else {
|
} else {
|
||||||
|
@ -1191,7 +1166,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
|
||||||
-C help Print codegen options
|
-C help Print codegen options
|
||||||
-W help \
|
-W help \
|
||||||
Print 'lint' options and default settings{}{}\n",
|
Print 'lint' options and default settings{}{}\n",
|
||||||
options.usage(&message),
|
options.usage(message),
|
||||||
nightly_help,
|
nightly_help,
|
||||||
verbose_help);
|
verbose_help);
|
||||||
}
|
}
|
||||||
|
@ -1273,8 +1248,6 @@ Available lint options:
|
||||||
|
|
||||||
print_lints(builtin);
|
print_lints(builtin);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let max_name_len = max("warnings".len(),
|
let max_name_len = max("warnings".len(),
|
||||||
plugin_groups.iter()
|
plugin_groups.iter()
|
||||||
.chain(&builtin_groups)
|
.chain(&builtin_groups)
|
||||||
|
@ -1407,10 +1380,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
||||||
for option in config::rustc_optgroups() {
|
for option in config::rustc_optgroups() {
|
||||||
(option.apply)(&mut options);
|
(option.apply)(&mut options);
|
||||||
}
|
}
|
||||||
let matches = match options.parse(args) {
|
let matches = options.parse(args).unwrap_or_else(|f|
|
||||||
Ok(m) => m,
|
early_error(ErrorOutputType::default(), &f.to_string()));
|
||||||
Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// For all options we just parsed, we check a few aspects:
|
// For all options we just parsed, we check a few aspects:
|
||||||
//
|
//
|
||||||
|
@ -1452,6 +1423,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let cg_flags = matches.opt_strs("C");
|
let cg_flags = matches.opt_strs("C");
|
||||||
|
|
||||||
if cg_flags.iter().any(|x| *x == "help") {
|
if cg_flags.iter().any(|x| *x == "help") {
|
||||||
describe_codegen_flags();
|
describe_codegen_flags();
|
||||||
return None;
|
return None;
|
||||||
|
@ -1462,7 +1434,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
||||||
"the --no-stack-check flag is deprecated and does nothing");
|
"the --no-stack-check flag is deprecated and does nothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
if cg_flags.contains(&"passes=list".to_string()) {
|
if cg_flags.iter().any(|x| *x == "passes=list") {
|
||||||
get_codegen_sysroot("llvm")().print_passes();
|
get_codegen_sysroot("llvm")().print_passes();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -1500,7 +1472,7 @@ pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any
|
||||||
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
|
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
|
||||||
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
|
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
|
||||||
|
|
||||||
#[cfg(all(unix,not(target_os = "haiku")))]
|
#[cfg(all(unix, not(target_os = "haiku")))]
|
||||||
let spawn_thread = unsafe {
|
let spawn_thread = unsafe {
|
||||||
// Fetch the current resource limits
|
// Fetch the current resource limits
|
||||||
let mut rlim = libc::rlimit {
|
let mut rlim = libc::rlimit {
|
||||||
|
@ -1554,7 +1526,7 @@ pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(any(windows,unix)))]
|
#[cfg(not(any(windows, unix)))]
|
||||||
let spawn_thread = true;
|
let spawn_thread = true;
|
||||||
|
|
||||||
// The or condition is added from backward compatibility.
|
// The or condition is added from backward compatibility.
|
||||||
|
@ -1632,7 +1604,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.len() > 0 {
|
if !result.is_empty() {
|
||||||
Some((result, excluded_cargo_defaults))
|
Some((result, excluded_cargo_defaults))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1680,25 +1652,25 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFail
|
||||||
errors::Level::Bug);
|
errors::Level::Bug);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut xs = vec![
|
let mut xs: Vec<Cow<'static, str>> = vec![
|
||||||
"the compiler unexpectedly panicked. this is a bug.".to_string(),
|
"the compiler unexpectedly panicked. this is a bug.".into(),
|
||||||
format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
|
format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(),
|
||||||
format!("rustc {} running on {}",
|
format!("rustc {} running on {}",
|
||||||
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
||||||
config::host_triple()),
|
config::host_triple()).into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
|
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
|
||||||
xs.push(format!("compiler flags: {}", flags.join(" ")));
|
xs.push(format!("compiler flags: {}", flags.join(" ")).into());
|
||||||
|
|
||||||
if excluded_cargo_defaults {
|
if excluded_cargo_defaults {
|
||||||
xs.push("some of the compiler flags provided by cargo are hidden".to_string());
|
xs.push("some of the compiler flags provided by cargo are hidden".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for note in &xs {
|
for note in &xs {
|
||||||
handler.emit(&MultiSpan::new(),
|
handler.emit(&MultiSpan::new(),
|
||||||
¬e,
|
note,
|
||||||
errors::Level::Note);
|
errors::Level::Note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,8 @@ impl PpSourceMode {
|
||||||
_ => panic!("Should use call_with_pp_support_hir"),
|
_ => panic!("Should use call_with_pp_support_hir"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn call_with_pp_support_hir<'tcx, A, F>(&self,
|
fn call_with_pp_support_hir<'tcx, A, F>(
|
||||||
|
&self,
|
||||||
sess: &'tcx Session,
|
sess: &'tcx Session,
|
||||||
cstore: &'tcx CStore,
|
cstore: &'tcx CStore,
|
||||||
hir_map: &hir_map::Map<'tcx>,
|
hir_map: &hir_map::Map<'tcx>,
|
||||||
|
@ -207,8 +208,8 @@ impl PpSourceMode {
|
||||||
arenas: &'tcx AllArenas<'tcx>,
|
arenas: &'tcx AllArenas<'tcx>,
|
||||||
output_filenames: &OutputFilenames,
|
output_filenames: &OutputFilenames,
|
||||||
id: &str,
|
id: &str,
|
||||||
f: F)
|
f: F
|
||||||
-> A
|
) -> A
|
||||||
where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A
|
where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -855,7 +856,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
|
||||||
break n.body();
|
break n.body();
|
||||||
}
|
}
|
||||||
let parent = tcx.hir.get_parent_node(node_id);
|
let parent = tcx.hir.get_parent_node(node_id);
|
||||||
assert!(node_id != parent);
|
assert_ne!(node_id, parent);
|
||||||
node_id = parent;
|
node_id = parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -962,8 +963,7 @@ pub fn print_after_parsing(sess: &Session,
|
||||||
box out,
|
box out,
|
||||||
annotation.pp_ann(),
|
annotation.pp_ann(),
|
||||||
false)
|
false)
|
||||||
})
|
}).unwrap()
|
||||||
.unwrap()
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn begin(sess: &Session) {
|
||||||
use std::sync::mpsc::{channel};
|
use std::sync::mpsc::{channel};
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
if profq_set_chan(sess, tx) {
|
if profq_set_chan(sess, tx) {
|
||||||
thread::spawn(move||profile_queries_thread(rx));
|
thread::spawn(move || profile_queries_thread(rx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +34,12 @@ pub fn begin(sess: &Session) {
|
||||||
pub fn dump(sess: &Session, path: String) {
|
pub fn dump(sess: &Session, path: String) {
|
||||||
use std::sync::mpsc::{channel};
|
use std::sync::mpsc::{channel};
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let params = ProfQDumpParams{
|
let params = ProfQDumpParams {
|
||||||
path, ack:tx,
|
path,
|
||||||
|
ack: tx,
|
||||||
// FIXME: Add another compiler flag to toggle whether this log
|
// FIXME: Add another compiler flag to toggle whether this log
|
||||||
// is written; false for now
|
// is written; false for now
|
||||||
dump_profq_msg_log:true,
|
dump_profq_msg_log: true,
|
||||||
};
|
};
|
||||||
profq_msg(sess, ProfileQueriesMsg::Dump(params));
|
profq_msg(sess, ProfileQueriesMsg::Dump(params));
|
||||||
let _ = rx.recv().unwrap();
|
let _ = rx.recv().unwrap();
|
||||||
|
@ -63,20 +64,20 @@ struct StackFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_duration(traces: &[trace::Rec]) -> Duration {
|
fn total_duration(traces: &[trace::Rec]) -> Duration {
|
||||||
let mut sum : Duration = Duration::new(0,0);
|
let mut sum : Duration = Duration::new(0, 0);
|
||||||
for t in traces.iter() { sum += t.dur_total; }
|
for t in traces.iter() { sum += t.dur_total; }
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
// profiling thread; retains state (in local variables) and dump traces, upon request.
|
// profiling thread; retains state (in local variables) and dump traces, upon request.
|
||||||
fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
fn profile_queries_thread(r: Receiver<ProfileQueriesMsg>) {
|
||||||
use self::trace::*;
|
use self::trace::*;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::time::{Instant};
|
use std::time::{Instant};
|
||||||
|
|
||||||
let mut profq_msgs : Vec<ProfileQueriesMsg> = vec![];
|
let mut profq_msgs: Vec<ProfileQueriesMsg> = vec![];
|
||||||
let mut frame : StackFrame = StackFrame{ parse_st:ParseState::Clear, traces:vec![] };
|
let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] };
|
||||||
let mut stack : Vec<StackFrame> = vec![];
|
let mut stack: Vec<StackFrame> = vec![];
|
||||||
loop {
|
loop {
|
||||||
let msg = r.recv();
|
let msg = r.recv();
|
||||||
if let Err(_recv_err) = msg {
|
if let Err(_recv_err) = msg {
|
||||||
|
@ -90,7 +91,7 @@ fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
||||||
match msg {
|
match msg {
|
||||||
ProfileQueriesMsg::Halt => return,
|
ProfileQueriesMsg::Halt => return,
|
||||||
ProfileQueriesMsg::Dump(params) => {
|
ProfileQueriesMsg::Dump(params) => {
|
||||||
assert!(stack.len() == 0);
|
assert!(stack.is_empty());
|
||||||
assert!(frame.parse_st == ParseState::Clear);
|
assert!(frame.parse_st == ParseState::Clear);
|
||||||
{
|
{
|
||||||
// write log of all messages
|
// write log of all messages
|
||||||
|
@ -109,17 +110,14 @@ fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
||||||
let counts_path = format!("{}.counts.txt", params.path);
|
let counts_path = format!("{}.counts.txt", params.path);
|
||||||
let mut counts_file = File::create(&counts_path).unwrap();
|
let mut counts_file = File::create(&counts_path).unwrap();
|
||||||
|
|
||||||
write!(html_file, "<html>\n").unwrap();
|
writeln!(html_file,
|
||||||
write!(html_file,
|
"<html>\n<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">",
|
||||||
"<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n",
|
|
||||||
"profile_queries.css").unwrap();
|
"profile_queries.css").unwrap();
|
||||||
write!(html_file, "<style>\n").unwrap();
|
writeln!(html_file, "<style>").unwrap();
|
||||||
trace::write_style(&mut html_file);
|
trace::write_style(&mut html_file);
|
||||||
write!(html_file, "</style>\n").unwrap();
|
writeln!(html_file, "</style>\n</head>\n<body>").unwrap();
|
||||||
write!(html_file, "</head>\n").unwrap();
|
|
||||||
write!(html_file, "<body>\n").unwrap();
|
|
||||||
trace::write_traces(&mut html_file, &mut counts_file, &frame.traces);
|
trace::write_traces(&mut html_file, &mut counts_file, &frame.traces);
|
||||||
write!(html_file, "</body>\n</html>\n").unwrap();
|
writeln!(html_file, "</body>\n</html>").unwrap();
|
||||||
|
|
||||||
let ack_path = format!("{}.ack", params.path);
|
let ack_path = format!("{}.ack", params.path);
|
||||||
let ack_file = File::create(&ack_path).unwrap();
|
let ack_file = File::create(&ack_path).unwrap();
|
||||||
|
@ -141,10 +139,10 @@ fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
||||||
|
|
||||||
// Parse State: Clear
|
// Parse State: Clear
|
||||||
(ParseState::Clear,
|
(ParseState::Clear,
|
||||||
ProfileQueriesMsg::QueryBegin(span,querymsg)) => {
|
ProfileQueriesMsg::QueryBegin(span, querymsg)) => {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
frame.parse_st = ParseState::HaveQuery
|
frame.parse_st = ParseState::HaveQuery
|
||||||
(Query{span:span, msg:querymsg}, start)
|
(Query { span, msg: querymsg }, start)
|
||||||
},
|
},
|
||||||
(ParseState::Clear,
|
(ParseState::Clear,
|
||||||
ProfileQueriesMsg::CacheHit) => {
|
ProfileQueriesMsg::CacheHit) => {
|
||||||
|
@ -287,8 +285,6 @@ fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
||||||
frame = StackFrame{parse_st:ParseState::Clear, traces:vec![]};
|
frame = StackFrame{parse_st:ParseState::Clear, traces:vec![]};
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Parse errors:
|
// Parse errors:
|
||||||
|
|
||||||
(ParseState::HaveQuery(q,_),
|
(ParseState::HaveQuery(q,_),
|
||||||
|
@ -310,7 +306,6 @@ fn profile_queries_thread(r:Receiver<ProfileQueriesMsg>) {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,18 +43,18 @@ pub struct QueryMetric {
|
||||||
pub dur_total: Duration,
|
pub dur_total: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cons(s: &str) -> String {
|
||||||
|
let first = s.split(|d| d == '(' || d == '{').next();
|
||||||
|
assert!(first.is_some() && first != Some(""));
|
||||||
|
first.unwrap().to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cons_of_query_msg(q: &trace::Query) -> String {
|
pub fn cons_of_query_msg(q: &trace::Query) -> String {
|
||||||
let s = format!("{:?}", q.msg);
|
cons(&format!("{:?}", q.msg))
|
||||||
let cons: Vec<&str> = s.split(|d| d == '(' || d == '{').collect();
|
|
||||||
assert!(cons.len() > 0 && cons[0] != "");
|
|
||||||
cons[0].to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cons_of_key(k: &DepNode) -> String {
|
pub fn cons_of_key(k: &DepNode) -> String {
|
||||||
let s = format!("{:?}", k);
|
cons(&format!("{:?}", k))
|
||||||
let cons: Vec<&str> = s.split(|d| d == '(' || d == '{').collect();
|
|
||||||
assert!(cons.len() > 0 && cons[0] != "");
|
|
||||||
cons[0].to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// First return value is text; second return value is a CSS class
|
// First return value is text; second return value is a CSS class
|
||||||
|
@ -84,35 +84,33 @@ pub fn html_of_effect(eff: &Effect) -> (String, String) {
|
||||||
// First return value is text; second return value is a CSS class
|
// First return value is text; second return value is a CSS class
|
||||||
fn html_of_duration(_start: &Instant, dur: &Duration) -> (String, String) {
|
fn html_of_duration(_start: &Instant, dur: &Duration) -> (String, String) {
|
||||||
use rustc::util::common::duration_to_secs_str;
|
use rustc::util::common::duration_to_secs_str;
|
||||||
(duration_to_secs_str(dur.clone()),
|
(duration_to_secs_str(dur.clone()), String::new())
|
||||||
String::new()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn html_of_fraction(frac: f64) -> (String, String) {
|
fn html_of_fraction(frac: f64) -> (String, &'static str) {
|
||||||
let css = {
|
let css = {
|
||||||
if frac > 0.50 { "frac-50".to_string() }
|
if frac > 0.50 { "frac-50" }
|
||||||
else if frac > 0.40 { "frac-40".to_string() }
|
else if frac > 0.40 { "frac-40" }
|
||||||
else if frac > 0.30 { "frac-30".to_string() }
|
else if frac > 0.30 { "frac-30" }
|
||||||
else if frac > 0.20 { "frac-20".to_string() }
|
else if frac > 0.20 { "frac-20" }
|
||||||
else if frac > 0.10 { "frac-10".to_string() }
|
else if frac > 0.10 { "frac-10" }
|
||||||
else if frac > 0.05 { "frac-05".to_string() }
|
else if frac > 0.05 { "frac-05" }
|
||||||
else if frac > 0.02 { "frac-02".to_string() }
|
else if frac > 0.02 { "frac-02" }
|
||||||
else if frac > 0.01 { "frac-01".to_string() }
|
else if frac > 0.01 { "frac-01" }
|
||||||
else if frac > 0.001 { "frac-001".to_string() }
|
else if frac > 0.001 { "frac-001" }
|
||||||
else { "frac-0".to_string() }
|
else { "frac-0" }
|
||||||
};
|
};
|
||||||
let percent = frac * 100.0;
|
let percent = frac * 100.0;
|
||||||
if percent > 0.1 { (format!("{:.1}%", percent), css) }
|
|
||||||
else { ("< 0.1%".to_string(), css) }
|
if percent > 0.1 {
|
||||||
|
(format!("{:.1}%", percent), css)
|
||||||
|
} else {
|
||||||
|
("< 0.1%".to_string(), css)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_duration(traces: &[Rec]) -> Duration {
|
fn total_duration(traces: &[Rec]) -> Duration {
|
||||||
let mut sum : Duration = Duration::new(0,0);
|
Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum()
|
||||||
for t in traces.iter() {
|
|
||||||
sum += t.dur_total;
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn duration_div(nom: Duration, den: Duration) -> f64 {
|
fn duration_div(nom: Duration, den: Duration) -> f64 {
|
||||||
|
@ -130,64 +128,65 @@ fn write_traces_rec(file: &mut File, traces: &[Rec], total: Duration, depth: usi
|
||||||
let fraction = duration_div(t.dur_total, total);
|
let fraction = duration_div(t.dur_total, total);
|
||||||
let percent = fraction * 100.0;
|
let percent = fraction * 100.0;
|
||||||
let (frc_text, frc_css_classes) = html_of_fraction(fraction);
|
let (frc_text, frc_css_classes) = html_of_fraction(fraction);
|
||||||
write!(file, "<div class=\"trace depth-{} extent-{}{} {} {} {}\">\n",
|
writeln!(file, "<div class=\"trace depth-{} extent-{}{} {} {} {}\">",
|
||||||
depth,
|
depth,
|
||||||
t.extent.len(),
|
t.extent.len(),
|
||||||
/* Heuristic for 'important' CSS class: */
|
/* Heuristic for 'important' CSS class: */
|
||||||
if t.extent.len() > 5 || percent >= 1.0 {
|
if t.extent.len() > 5 || percent >= 1.0 { " important" } else { "" },
|
||||||
" important" }
|
|
||||||
else { "" },
|
|
||||||
eff_css_classes,
|
eff_css_classes,
|
||||||
dur_css_classes,
|
dur_css_classes,
|
||||||
frc_css_classes,
|
frc_css_classes,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
write!(file, "<div class=\"eff\">{}</div>\n", eff_text).unwrap();
|
writeln!(file, "<div class=\"eff\">{}</div>", eff_text).unwrap();
|
||||||
write!(file, "<div class=\"dur\">{}</div>\n", dur_text).unwrap();
|
writeln!(file, "<div class=\"dur\">{}</div>", dur_text).unwrap();
|
||||||
write!(file, "<div class=\"frc\">{}</div>\n", frc_text).unwrap();
|
writeln!(file, "<div class=\"frc\">{}</div>", frc_text).unwrap();
|
||||||
write_traces_rec(file, &t.extent, total, depth + 1);
|
write_traces_rec(file, &t.extent, total, depth + 1);
|
||||||
write!(file, "</div>\n").unwrap();
|
writeln!(file, "</div>").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]) {
|
fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]) {
|
||||||
|
counts.reserve(traces.len());
|
||||||
for t in traces.iter() {
|
for t in traces.iter() {
|
||||||
match t.effect {
|
match t.effect {
|
||||||
Effect::TimeBegin(ref msg) => {
|
Effect::TimeBegin(ref msg) => {
|
||||||
let qm = match counts.get(msg) {
|
let qm = match counts.get(msg) {
|
||||||
Some(_qm) => { panic!("TimeBegin with non-unique, repeat message") }
|
Some(_qm) => panic!("TimeBegin with non-unique, repeat message"),
|
||||||
None => QueryMetric{
|
None => QueryMetric {
|
||||||
count: 1,
|
count: 1,
|
||||||
dur_self: t.dur_self,
|
dur_self: t.dur_self,
|
||||||
dur_total: t.dur_total,
|
dur_total: t.dur_total,
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
counts.insert(msg.clone(), qm);
|
counts.insert(msg.clone(), qm);
|
||||||
},
|
},
|
||||||
Effect::TaskBegin(ref key) => {
|
Effect::TaskBegin(ref key) => {
|
||||||
let cons = cons_of_key(key);
|
let cons = cons_of_key(key);
|
||||||
let qm = match counts.get(&cons) {
|
let qm = match counts.get(&cons) {
|
||||||
Some(qm) =>
|
Some(qm) =>
|
||||||
QueryMetric{
|
QueryMetric {
|
||||||
count: qm.count + 1,
|
count: qm.count + 1,
|
||||||
dur_self: qm.dur_self + t.dur_self,
|
dur_self: qm.dur_self + t.dur_self,
|
||||||
dur_total: qm.dur_total + t.dur_total,
|
dur_total: qm.dur_total + t.dur_total,
|
||||||
},
|
},
|
||||||
None => QueryMetric{
|
None => QueryMetric {
|
||||||
count: 1,
|
count: 1,
|
||||||
dur_self: t.dur_self,
|
dur_self: t.dur_self,
|
||||||
dur_total: t.dur_total,
|
dur_total: t.dur_total,
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
counts.insert(cons, qm);
|
counts.insert(cons, qm);
|
||||||
},
|
},
|
||||||
Effect::QueryBegin(ref qmsg, ref _cc) => {
|
Effect::QueryBegin(ref qmsg, ref _cc) => {
|
||||||
let qcons = cons_of_query_msg(qmsg);
|
let qcons = cons_of_query_msg(qmsg);
|
||||||
let qm = match counts.get(&qcons) {
|
let qm = match counts.get(&qcons) {
|
||||||
Some(qm) =>
|
Some(qm) =>
|
||||||
QueryMetric{
|
QueryMetric {
|
||||||
count: qm.count + 1,
|
count: qm.count + 1,
|
||||||
dur_total: qm.dur_total + t.dur_total,
|
dur_total: qm.dur_total + t.dur_total,
|
||||||
dur_self: qm.dur_self + t.dur_self
|
dur_self: qm.dur_self + t.dur_self
|
||||||
},
|
},
|
||||||
None => QueryMetric{
|
None => QueryMetric {
|
||||||
count: 1,
|
count: 1,
|
||||||
dur_total: t.dur_total,
|
dur_total: t.dur_total,
|
||||||
dur_self: t.dur_self,
|
dur_self: t.dur_self,
|
||||||
|
@ -200,16 +199,17 @@ fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap<String,QueryMetric>) {
|
pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap<String, QueryMetric>) {
|
||||||
use rustc::util::common::duration_to_secs_str;
|
use rustc::util::common::duration_to_secs_str;
|
||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
|
|
||||||
let mut data = counts.iter().map(|(ref cons, ref qm)|
|
let mut data = counts.iter().map(|(ref cons, ref qm)|
|
||||||
(cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone())
|
(cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone())
|
||||||
).collect::<Vec<_>>();
|
).collect::<Vec<_>>();
|
||||||
|
|
||||||
data.sort_by_key(|k| Reverse(k.3));
|
data.sort_by_key(|k| Reverse(k.3));
|
||||||
for (cons, count, dur_total, dur_self) in data {
|
for (cons, count, dur_total, dur_self) in data {
|
||||||
write!(count_file, "{}, {}, {}, {}\n",
|
writeln!(count_file, "{}, {}, {}, {}",
|
||||||
cons, count,
|
cons, count,
|
||||||
duration_to_secs_str(dur_total),
|
duration_to_secs_str(dur_total),
|
||||||
duration_to_secs_str(dur_self)
|
duration_to_secs_str(dur_self)
|
||||||
|
@ -223,12 +223,12 @@ pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]
|
||||||
compute_counts_rec(&mut counts, traces);
|
compute_counts_rec(&mut counts, traces);
|
||||||
write_counts(counts_file, &mut counts);
|
write_counts(counts_file, &mut counts);
|
||||||
|
|
||||||
let total : Duration = total_duration(traces);
|
let total: Duration = total_duration(traces);
|
||||||
write_traces_rec(html_file, traces, total, 0)
|
write_traces_rec(html_file, traces, total, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_style(html_file: &mut File) {
|
pub fn write_style(html_file: &mut File) {
|
||||||
write!(html_file,"{}", "
|
write!(html_file, "{}", "
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
background: black;
|
background: black;
|
||||||
|
|
|
@ -80,10 +80,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
||||||
match callee.node {
|
match callee.node {
|
||||||
hir::ExprKind::Path(ref qpath) => {
|
hir::ExprKind::Path(ref qpath) => {
|
||||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||||
if let Def::Fn(_) = def {
|
match def {
|
||||||
Some(def)
|
Def::Fn(_) | Def::Method(_) => Some(def),
|
||||||
} else { // `Def::Local` if it was a closure, for which we
|
// `Def::Local` if it was a closure, for which we
|
||||||
None // do not currently support must-use linting
|
// do not currently support must-use linting
|
||||||
|
_ => None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => None
|
_ => None
|
||||||
|
|
|
@ -327,7 +327,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
(_, &ty::Dynamic(ref data, _)) => {
|
(_, &ty::Dynamic(ref data, _)) => {
|
||||||
// Initial cast from sized to dyn trait
|
// Initial cast from sized to dyn trait
|
||||||
let trait_ref = data.principal().unwrap().with_self_ty(
|
let trait_ref = data.principal().with_self_ty(
|
||||||
*self.tcx,
|
*self.tcx,
|
||||||
src_pointee_ty,
|
src_pointee_ty,
|
||||||
);
|
);
|
||||||
|
|
|
@ -907,8 +907,7 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
!impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
|
!impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
|
||||||
|
|
||||||
if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
|
if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
|
||||||
if let Some(principal) = trait_ty.principal() {
|
let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty);
|
||||||
let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
|
|
||||||
assert!(!poly_trait_ref.has_escaping_regions());
|
assert!(!poly_trait_ref.has_escaping_regions());
|
||||||
|
|
||||||
// Walk all methods of the trait, including those of its supertraits
|
// Walk all methods of the trait, including those of its supertraits
|
||||||
|
@ -922,7 +921,6 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
.filter(|&instance| should_monomorphize_locally(tcx, &instance))
|
.filter(|&instance| should_monomorphize_locally(tcx, &instance))
|
||||||
.map(|instance| create_fn_mono_item(instance));
|
.map(|instance| create_fn_mono_item(instance));
|
||||||
output.extend(methods);
|
output.extend(methods);
|
||||||
}
|
|
||||||
// Also add the destructor
|
// Also add the destructor
|
||||||
visit_drop_use(tcx, impl_ty, false, output);
|
visit_drop_use(tcx, impl_ty, false, output);
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,12 +320,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||||
output.push(']');
|
output.push(']');
|
||||||
},
|
},
|
||||||
ty::Dynamic(ref trait_data, ..) => {
|
ty::Dynamic(ref trait_data, ..) => {
|
||||||
if let Some(principal) = trait_data.principal() {
|
let principal = trait_data.principal();
|
||||||
self.push_def_path(principal.def_id(), output);
|
self.push_def_path(principal.def_id(), output);
|
||||||
self.push_type_params(principal.skip_binder().substs,
|
self.push_type_params(
|
||||||
|
principal.skip_binder().substs,
|
||||||
trait_data.projection_bounds(),
|
trait_data.projection_bounds(),
|
||||||
output);
|
output,
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
ty::Foreign(did) => self.push_def_path(did, output),
|
ty::Foreign(did) => self.push_def_path(did, output),
|
||||||
ty::FnDef(..) |
|
ty::FnDef(..) |
|
||||||
|
|
|
@ -19,7 +19,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::visit::*;
|
use rustc::mir::visit::*;
|
||||||
use rustc::ty::{self, Instance, Ty, TyCtxt};
|
use rustc::ty::{self, Instance, InstanceDef, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::{Subst,Substs};
|
use rustc::ty::subst::{Subst,Substs};
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -100,6 +100,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||||
param_env,
|
param_env,
|
||||||
callee_def_id,
|
callee_def_id,
|
||||||
substs) {
|
substs) {
|
||||||
|
let is_virtual =
|
||||||
|
if let InstanceDef::Virtual(..) = instance.def {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_virtual {
|
||||||
callsites.push_back(CallSite {
|
callsites.push_back(CallSite {
|
||||||
callee: instance.def_id(),
|
callee: instance.def_id(),
|
||||||
substs: instance.substs,
|
substs: instance.substs,
|
||||||
|
@ -110,6 +118,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
||||||
let ty_def_id = match self.tcx.type_of(item_def_id).sty {
|
let ty_def_id = match self.tcx.type_of(item_def_id).sty {
|
||||||
ty::Adt(adt, _) => adt.did,
|
ty::Adt(adt, _) => adt.did,
|
||||||
ty::Foreign(did) => did,
|
ty::Foreign(did) => did,
|
||||||
ty::Dynamic(ref obj, ..) if obj.principal().is_some() =>
|
ty::Dynamic(ref obj, ..) => obj.principal().def_id(),
|
||||||
obj.principal().unwrap().def_id(),
|
|
||||||
ty::Projection(ref proj) => proj.trait_ref(self.tcx).def_id,
|
ty::Projection(ref proj) => proj.trait_ref(self.tcx).def_id,
|
||||||
_ => return Some(AccessLevel::Public)
|
_ => return Some(AccessLevel::Public)
|
||||||
};
|
};
|
||||||
|
@ -484,7 +483,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
|
||||||
let ty_def_id = match ty.sty {
|
let ty_def_id = match ty.sty {
|
||||||
ty::Adt(adt, _) => Some(adt.did),
|
ty::Adt(adt, _) => Some(adt.did),
|
||||||
ty::Foreign(did) => Some(did),
|
ty::Foreign(did) => Some(did),
|
||||||
ty::Dynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
|
ty::Dynamic(ref obj, ..) => Some(obj.principal().def_id()),
|
||||||
ty::Projection(ref proj) => Some(proj.item_def_id),
|
ty::Projection(ref proj) => Some(proj.item_def_id),
|
||||||
ty::FnDef(def_id, ..) |
|
ty::FnDef(def_id, ..) |
|
||||||
ty::Closure(def_id, ..) |
|
ty::Closure(def_id, ..) |
|
||||||
|
@ -1456,7 +1455,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
|
||||||
let ty_def_id = match ty.sty {
|
let ty_def_id = match ty.sty {
|
||||||
ty::Adt(adt, _) => Some(adt.did),
|
ty::Adt(adt, _) => Some(adt.did),
|
||||||
ty::Foreign(did) => Some(did),
|
ty::Foreign(did) => Some(did),
|
||||||
ty::Dynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
|
ty::Dynamic(ref obj, ..) => Some(obj.principal().def_id()),
|
||||||
ty::Projection(ref proj) => {
|
ty::Projection(ref proj) => {
|
||||||
if self.required_visibility == ty::Visibility::Invisible {
|
if self.required_visibility == ty::Visibility::Invisible {
|
||||||
// Conservatively approximate the whole type alias as public without
|
// Conservatively approximate the whole type alias as public without
|
||||||
|
|
|
@ -680,6 +680,12 @@ pub struct TargetOptions {
|
||||||
/// typically because the platform needs to unwind for things like stack
|
/// typically because the platform needs to unwind for things like stack
|
||||||
/// unwinders.
|
/// unwinders.
|
||||||
pub requires_uwtable: bool,
|
pub requires_uwtable: bool,
|
||||||
|
|
||||||
|
/// Whether or not SIMD types are passed by reference in the Rust ABI,
|
||||||
|
/// typically required if a target can be compiled with a mixed set of
|
||||||
|
/// target features. This is `true` by default, and `false` for targets like
|
||||||
|
/// wasm32 where the whole program either has simd or not.
|
||||||
|
pub simd_types_indirect: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TargetOptions {
|
impl Default for TargetOptions {
|
||||||
|
@ -760,6 +766,7 @@ impl Default for TargetOptions {
|
||||||
embed_bitcode: false,
|
embed_bitcode: false,
|
||||||
emit_debug_gdb_scripts: true,
|
emit_debug_gdb_scripts: true,
|
||||||
requires_uwtable: false,
|
requires_uwtable: false,
|
||||||
|
simd_types_indirect: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1041,6 +1048,7 @@ impl Target {
|
||||||
key!(embed_bitcode, bool);
|
key!(embed_bitcode, bool);
|
||||||
key!(emit_debug_gdb_scripts, bool);
|
key!(emit_debug_gdb_scripts, bool);
|
||||||
key!(requires_uwtable, bool);
|
key!(requires_uwtable, bool);
|
||||||
|
key!(simd_types_indirect, bool);
|
||||||
|
|
||||||
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
|
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
|
||||||
for name in array.iter().filter_map(|abi| abi.as_string()) {
|
for name in array.iter().filter_map(|abi| abi.as_string()) {
|
||||||
|
@ -1250,6 +1258,7 @@ impl ToJson for Target {
|
||||||
target_option_val!(embed_bitcode);
|
target_option_val!(embed_bitcode);
|
||||||
target_option_val!(emit_debug_gdb_scripts);
|
target_option_val!(emit_debug_gdb_scripts);
|
||||||
target_option_val!(requires_uwtable);
|
target_option_val!(requires_uwtable);
|
||||||
|
target_option_val!(simd_types_indirect);
|
||||||
|
|
||||||
if default.abi_blacklist != self.options.abi_blacklist {
|
if default.abi_blacklist != self.options.abi_blacklist {
|
||||||
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
|
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
|
||||||
|
|
|
@ -54,6 +54,12 @@ pub fn target() -> Result<Target, String> {
|
||||||
linker: Some("rust-lld".to_owned()),
|
linker: Some("rust-lld".to_owned()),
|
||||||
lld_flavor: LldFlavor::Wasm,
|
lld_flavor: LldFlavor::Wasm,
|
||||||
|
|
||||||
|
// No need for indirection here, simd types can always be passed by
|
||||||
|
// value as the whole module either has simd or not, which is different
|
||||||
|
// from x86 (for example) where programs can have functions that don't
|
||||||
|
// enable simd features.
|
||||||
|
simd_types_indirect: false,
|
||||||
|
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
};
|
};
|
||||||
Ok(Target {
|
Ok(Target {
|
||||||
|
|
|
@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
|
||||||
/// No metadata attached, ie pointer to sized type or foreign type
|
/// No metadata attached, ie pointer to sized type or foreign type
|
||||||
Thin,
|
Thin,
|
||||||
/// A trait object
|
/// A trait object
|
||||||
Vtable(Option<DefId>),
|
Vtable(DefId),
|
||||||
/// Slice
|
/// Slice
|
||||||
Length,
|
Length,
|
||||||
/// The unsize info of this projection
|
/// The unsize info of this projection
|
||||||
|
@ -105,7 +105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
Ok(match t.sty {
|
Ok(match t.sty {
|
||||||
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
|
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
|
||||||
ty::Dynamic(ref tty, ..) =>
|
ty::Dynamic(ref tty, ..) =>
|
||||||
Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))),
|
Some(PointerKind::Vtable(tty.principal().def_id())),
|
||||||
ty::Adt(def, substs) if def.is_struct() => {
|
ty::Adt(def, substs) if def.is_struct() => {
|
||||||
match def.non_enum_variant().fields.last() {
|
match def.non_enum_variant().fields.last() {
|
||||||
None => Some(PointerKind::Thin),
|
None => Some(PointerKind::Thin),
|
||||||
|
|
|
@ -198,9 +198,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.deduce_sig_from_projection(None, &pb)
|
self.deduce_sig_from_projection(None, &pb)
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
let kind = object_type
|
let kind = self.tcx.lang_items().fn_trait_kind(object_type.principal().def_id());
|
||||||
.principal()
|
|
||||||
.and_then(|p| self.tcx.lang_items().fn_trait_kind(p.def_id()));
|
|
||||||
(sig, kind)
|
(sig, kind)
|
||||||
}
|
}
|
||||||
ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
|
ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
|
||||||
|
|
|
@ -290,7 +290,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||||
.include_raw_pointers()
|
.include_raw_pointers()
|
||||||
.filter_map(|(ty, _)|
|
.filter_map(|(ty, _)|
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Dynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)),
|
ty::Dynamic(ref data, ..) => Some(closure(self, ty, data.principal())),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -452,11 +452,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
match self_ty.sty {
|
match self_ty.sty {
|
||||||
ty::Dynamic(ref data, ..) => {
|
ty::Dynamic(ref data, ..) => {
|
||||||
if let Some(p) = data.principal() {
|
let p = data.principal();
|
||||||
self.assemble_inherent_candidates_from_object(self_ty, p);
|
self.assemble_inherent_candidates_from_object(self_ty, p);
|
||||||
self.assemble_inherent_impl_candidates_for_type(p.def_id());
|
self.assemble_inherent_impl_candidates_for_type(p.def_id());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ty::Adt(def, _) => {
|
ty::Adt(def, _) => {
|
||||||
self.assemble_inherent_impl_candidates_for_type(def.did);
|
self.assemble_inherent_impl_candidates_for_type(def.did);
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,8 +663,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
ty::Adt(def, _) => def.did.is_local(),
|
ty::Adt(def, _) => def.did.is_local(),
|
||||||
ty::Foreign(did) => did.is_local(),
|
ty::Foreign(did) => did.is_local(),
|
||||||
|
|
||||||
ty::Dynamic(ref tr, ..) => tr.principal()
|
ty::Dynamic(ref tr, ..) => tr.principal().def_id().is_local(),
|
||||||
.map_or(false, |p| p.def_id().is_local()),
|
|
||||||
|
|
||||||
ty::Param(_) => true,
|
ty::Param(_) => true,
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
|
||||||
ty::Foreign(did) => {
|
ty::Foreign(did) => {
|
||||||
self.check_def_id(item, did);
|
self.check_def_id(item, did);
|
||||||
}
|
}
|
||||||
ty::Dynamic(ref data, ..) if data.principal().is_some() => {
|
ty::Dynamic(ref data, ..) => {
|
||||||
self.check_def_id(item, data.principal().unwrap().def_id());
|
self.check_def_id(item, data.principal().def_id());
|
||||||
}
|
}
|
||||||
ty::Char => {
|
ty::Char => {
|
||||||
self.check_primitive_impl(def_id,
|
self.check_primitive_impl(def_id,
|
||||||
|
|
|
@ -181,13 +181,12 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI
|
||||||
// This is something like impl Trait1 for Trait2. Illegal
|
// This is something like impl Trait1 for Trait2. Illegal
|
||||||
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
|
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
|
||||||
|
|
||||||
if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
|
if !tcx.is_object_safe(data.principal().def_id()) {
|
||||||
// This is an error, but it will be reported by wfcheck. Ignore it here.
|
// This is an error, but it will be reported by wfcheck. Ignore it here.
|
||||||
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
|
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
|
||||||
} else {
|
} else {
|
||||||
let mut supertrait_def_ids =
|
let mut supertrait_def_ids =
|
||||||
traits::supertrait_def_ids(tcx,
|
traits::supertrait_def_ids(tcx, data.principal().def_id());
|
||||||
data.principal().unwrap().def_id());
|
|
||||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||||
let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
|
let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
|
||||||
struct_span_err!(tcx.sess,
|
struct_span_err!(tcx.sess,
|
||||||
|
|
|
@ -203,7 +203,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
||||||
debug!("Dynamic");
|
debug!("Dynamic");
|
||||||
debug!("field_ty = {}", &field_ty);
|
debug!("field_ty = {}", &field_ty);
|
||||||
debug!("ty in field = {}", &ty);
|
debug!("ty in field = {}", &ty);
|
||||||
if let Some(ex_trait_ref) = obj.principal() {
|
let ex_trait_ref = obj.principal();
|
||||||
// Here, we are passing the type `usize` as a
|
// Here, we are passing the type `usize` as a
|
||||||
// placeholder value with the function
|
// placeholder value with the function
|
||||||
// `with_self_ty`, since there is no concrete type
|
// `with_self_ty`, since there is no concrete type
|
||||||
|
@ -225,7 +225,6 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
||||||
IgnoreSelfTy(true),
|
IgnoreSelfTy(true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ty::Projection(obj) => {
|
ty::Projection(obj) => {
|
||||||
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
|
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
|
||||||
|
|
|
@ -311,11 +311,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
let contra = self.contravariant(variance);
|
let contra = self.contravariant(variance);
|
||||||
self.add_constraints_from_region(current, r, contra);
|
self.add_constraints_from_region(current, r, contra);
|
||||||
|
|
||||||
if let Some(p) = data.principal() {
|
let poly_trait_ref = data
|
||||||
let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
|
.principal()
|
||||||
|
.with_self_ty(self.tcx(), self.tcx().types.err);
|
||||||
self.add_constraints_from_trait_ref(
|
self.add_constraints_from_trait_ref(
|
||||||
current, *poly_trait_ref.skip_binder(), variance);
|
current, *poly_trait_ref.skip_binder(), variance);
|
||||||
}
|
|
||||||
|
|
||||||
for projection in data.projection_bounds() {
|
for projection in data.projection_bounds() {
|
||||||
self.add_constraints_from_ty(
|
self.add_constraints_from_ty(
|
||||||
|
|
|
@ -2632,7 +2632,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Dynamic(ref obj, ref reg) => {
|
ty::Dynamic(ref obj, ref reg) => {
|
||||||
if let Some(principal) = obj.principal() {
|
let principal = obj.principal();
|
||||||
let did = principal.def_id();
|
let did = principal.def_id();
|
||||||
inline::record_extern_fqn(cx, did, TypeKind::Trait);
|
inline::record_extern_fqn(cx, did, TypeKind::Trait);
|
||||||
|
|
||||||
|
@ -2671,9 +2671,6 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||||
did,
|
did,
|
||||||
is_generic: false,
|
is_generic: false,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Never
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::Tuple(ref t) => Tuple(t.clean(cx)),
|
ty::Tuple(ref t) => Tuple(t.clean(cx)),
|
||||||
|
|
||||||
|
|
|
@ -48,4 +48,13 @@ jemalloc = ["alloc_jemalloc"]
|
||||||
force_alloc_system = []
|
force_alloc_system = []
|
||||||
panic-unwind = ["panic_unwind"]
|
panic-unwind = ["panic_unwind"]
|
||||||
profiler = ["profiler_builtins"]
|
profiler = ["profiler_builtins"]
|
||||||
|
|
||||||
|
# An off-by-default feature which enables a linux-syscall-like ABI for libstd to
|
||||||
|
# interoperate with the host environment. Currently not well documented and
|
||||||
|
# requires rebuilding the standard library to use it.
|
||||||
wasm_syscall = []
|
wasm_syscall = []
|
||||||
|
|
||||||
|
# An off-by-default features to enable libstd to assume that wasm-bindgen is in
|
||||||
|
# the environment for hooking up some thread-related information like the
|
||||||
|
# current thread id and accessing/getting the current thread's TCB
|
||||||
|
wasm-bindgen-threads = []
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
use arch::wasm32::atomic;
|
use arch::wasm32::atomic;
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use mem;
|
use mem;
|
||||||
use sync::atomic::{AtomicUsize, AtomicU64, Ordering::SeqCst};
|
use sync::atomic::{AtomicUsize, AtomicU32, Ordering::SeqCst};
|
||||||
|
use sys::thread;
|
||||||
|
|
||||||
pub struct Mutex {
|
pub struct Mutex {
|
||||||
locked: AtomicUsize,
|
locked: AtomicUsize,
|
||||||
|
@ -70,7 +71,7 @@ impl Mutex {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReentrantMutex {
|
pub struct ReentrantMutex {
|
||||||
owner: AtomicU64,
|
owner: AtomicU32,
|
||||||
recursions: UnsafeCell<u32>,
|
recursions: UnsafeCell<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ unsafe impl Sync for ReentrantMutex {}
|
||||||
impl ReentrantMutex {
|
impl ReentrantMutex {
|
||||||
pub unsafe fn uninitialized() -> ReentrantMutex {
|
pub unsafe fn uninitialized() -> ReentrantMutex {
|
||||||
ReentrantMutex {
|
ReentrantMutex {
|
||||||
owner: AtomicU64::new(0),
|
owner: AtomicU32::new(0),
|
||||||
recursions: UnsafeCell::new(0),
|
recursions: UnsafeCell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,20 +102,20 @@ impl ReentrantMutex {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn lock(&self) {
|
pub unsafe fn lock(&self) {
|
||||||
let me = thread_id();
|
let me = thread::my_id();
|
||||||
while let Err(owner) = self._try_lock(me) {
|
while let Err(owner) = self._try_lock(me) {
|
||||||
let val = atomic::wait_i64(self.ptr(), owner as i64, -1);
|
let val = atomic::wait_i32(self.ptr(), owner as i32, -1);
|
||||||
debug_assert!(val == 0 || val == 1);
|
debug_assert!(val == 0 || val == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn try_lock(&self) -> bool {
|
pub unsafe fn try_lock(&self) -> bool {
|
||||||
self._try_lock(thread_id()).is_ok()
|
self._try_lock(thread::my_id()).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn _try_lock(&self, id: u64) -> Result<(), u64> {
|
unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
|
||||||
let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
|
let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
|
||||||
match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
|
match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
|
||||||
// we transitioned from unlocked to locked
|
// we transitioned from unlocked to locked
|
||||||
|
@ -153,11 +154,7 @@ impl ReentrantMutex {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ptr(&self) -> *mut i64 {
|
fn ptr(&self) -> *mut i32 {
|
||||||
&self.owner as *const AtomicU64 as *mut i64
|
&self.owner as *const AtomicU32 as *mut i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thread_id() -> u64 {
|
|
||||||
panic!("thread ids not implemented on wasm with atomics yet")
|
|
||||||
}
|
|
||||||
|
|
|
@ -69,3 +69,49 @@ pub mod guard {
|
||||||
pub unsafe fn init() -> Option<Guard> { None }
|
pub unsafe fn init() -> Option<Guard> { None }
|
||||||
pub unsafe fn deinit() {}
|
pub unsafe fn deinit() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] {
|
||||||
|
#[link(wasm_import_module = "__wbindgen_thread_xform__")]
|
||||||
|
extern {
|
||||||
|
fn __wbindgen_current_id() -> u32;
|
||||||
|
fn __wbindgen_tcb_get() -> u32;
|
||||||
|
fn __wbindgen_tcb_set(ptr: u32);
|
||||||
|
}
|
||||||
|
pub fn my_id() -> u32 {
|
||||||
|
unsafe { __wbindgen_current_id() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are currently only ever used in `thread_local_atomics.rs`, if
|
||||||
|
// you'd like to use them be sure to update that and make sure everyone
|
||||||
|
// agrees what's what.
|
||||||
|
pub fn tcb_get() -> *mut u8 {
|
||||||
|
use mem;
|
||||||
|
assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::<u32>());
|
||||||
|
unsafe { __wbindgen_tcb_get() as *mut u8 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tcb_set(ptr: *mut u8) {
|
||||||
|
unsafe { __wbindgen_tcb_set(ptr as u32); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: still need something for hooking exiting a thread to free
|
||||||
|
// data...
|
||||||
|
|
||||||
|
} else if #[cfg(target_feature = "atomics")] {
|
||||||
|
pub fn my_id() -> u32 {
|
||||||
|
panic!("thread ids not implemented on wasm with atomics yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tcb_get() -> *mut u8 {
|
||||||
|
panic!("thread local data not implemented on wasm with atomics yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tcb_set(ptr: *mut u8) {
|
||||||
|
panic!("thread local data not implemented on wasm with atomics yet")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// stubbed out because no functions actually access these intrinsics
|
||||||
|
// unless atomics are enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,22 +8,61 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use sys::thread;
|
||||||
|
use sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||||
|
|
||||||
|
const MAX_KEYS: usize = 128;
|
||||||
|
static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
struct ThreadControlBlock {
|
||||||
|
keys: [*mut u8; MAX_KEYS],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThreadControlBlock {
|
||||||
|
fn new() -> ThreadControlBlock {
|
||||||
|
ThreadControlBlock {
|
||||||
|
keys: [0 as *mut u8; MAX_KEYS],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get() -> *mut ThreadControlBlock {
|
||||||
|
let ptr = thread::tcb_get();
|
||||||
|
if !ptr.is_null() {
|
||||||
|
return ptr as *mut ThreadControlBlock
|
||||||
|
}
|
||||||
|
let tcb = Box::into_raw(Box::new(ThreadControlBlock::new()));
|
||||||
|
thread::tcb_set(tcb as *mut u8);
|
||||||
|
tcb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Key = usize;
|
pub type Key = usize;
|
||||||
|
|
||||||
pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
|
pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
|
||||||
panic!("TLS on wasm with atomics not implemented yet");
|
drop(dtor); // FIXME: need to figure out how to hook thread exit to run this
|
||||||
|
let key = NEXT_KEY.fetch_add(1, SeqCst);
|
||||||
|
if key >= MAX_KEYS {
|
||||||
|
NEXT_KEY.store(MAX_KEYS, SeqCst);
|
||||||
|
panic!("cannot allocate space for more TLS keys");
|
||||||
|
}
|
||||||
|
// offset by 1 so we never hand out 0. This is currently required by
|
||||||
|
// `sys_common/thread_local.rs` where it can't cope with keys of value 0
|
||||||
|
// because it messes up the atomic management.
|
||||||
|
return key + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set(_key: Key, _value: *mut u8) {
|
pub unsafe fn set(key: Key, value: *mut u8) {
|
||||||
panic!("TLS on wasm with atomics not implemented yet");
|
(*ThreadControlBlock::get()).keys[key - 1] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get(_key: Key) -> *mut u8 {
|
pub unsafe fn get(key: Key) -> *mut u8 {
|
||||||
panic!("TLS on wasm with atomics not implemented yet");
|
(*ThreadControlBlock::get()).keys[key - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn destroy(_key: Key) {
|
pub unsafe fn destroy(_key: Key) {
|
||||||
panic!("TLS on wasm with atomics not implemented yet");
|
// FIXME: should implement this somehow, this isn't typically called but it
|
||||||
|
// can be called if two threads race to initialize a TLS slot and one ends
|
||||||
|
// up not being needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -172,16 +172,22 @@ macro_rules! __thread_local_inner {
|
||||||
&'static $crate::cell::UnsafeCell<
|
&'static $crate::cell::UnsafeCell<
|
||||||
$crate::option::Option<$t>>>
|
$crate::option::Option<$t>>>
|
||||||
{
|
{
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
|
||||||
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
|
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
|
||||||
$crate::thread::__StaticLocalKeyInner::new();
|
$crate::thread::__StaticLocalKeyInner::new();
|
||||||
|
|
||||||
#[thread_local]
|
#[thread_local]
|
||||||
#[cfg(all(target_thread_local, not(target_arch = "wasm32")))]
|
#[cfg(all(
|
||||||
|
target_thread_local,
|
||||||
|
not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
|
||||||
|
))]
|
||||||
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
|
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
|
||||||
$crate::thread::__FastLocalKeyInner::new();
|
$crate::thread::__FastLocalKeyInner::new();
|
||||||
|
|
||||||
#[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))]
|
#[cfg(all(
|
||||||
|
not(target_thread_local),
|
||||||
|
not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
|
||||||
|
))]
|
||||||
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
|
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
|
||||||
$crate::thread::__OsLocalKeyInner::new();
|
$crate::thread::__OsLocalKeyInner::new();
|
||||||
|
|
||||||
|
@ -302,7 +308,7 @@ impl<T: 'static> LocalKey<T> {
|
||||||
/// On some platforms like wasm32 there's no threads, so no need to generate
|
/// On some platforms like wasm32 there's no threads, so no need to generate
|
||||||
/// thread locals and we can instead just use plain statics!
|
/// thread locals and we can instead just use plain statics!
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
|
||||||
pub mod statik {
|
pub mod statik {
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use fmt;
|
use fmt;
|
||||||
|
|
|
@ -203,7 +203,7 @@ pub use self::local::{LocalKey, AccessError};
|
||||||
// where available, but both are needed.
|
// where available, but both are needed.
|
||||||
|
|
||||||
#[unstable(feature = "libstd_thread_internals", issue = "0")]
|
#[unstable(feature = "libstd_thread_internals", issue = "0")]
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
|
||||||
#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner;
|
#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner;
|
||||||
#[unstable(feature = "libstd_thread_internals", issue = "0")]
|
#[unstable(feature = "libstd_thread_internals", issue = "0")]
|
||||||
#[cfg(target_thread_local)]
|
#[cfg(target_thread_local)]
|
||||||
|
|
|
@ -499,6 +499,9 @@ declare_features! (
|
||||||
|
|
||||||
// #[cfg_attr(predicate, multiple, attributes, here)]
|
// #[cfg_attr(predicate, multiple, attributes, here)]
|
||||||
(active, cfg_attr_multi, "1.31.0", Some(54881), None),
|
(active, cfg_attr_multi, "1.31.0", Some(54881), None),
|
||||||
|
|
||||||
|
// Allows `const _: TYPE = VALUE`
|
||||||
|
(active, underscore_const_names, "1.31.0", Some(54912), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -1583,6 +1586,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::ItemKind::Const(_,_) => {
|
||||||
|
if i.ident.name == "_" {
|
||||||
|
gate_feature_post!(&self, underscore_const_names, i.span,
|
||||||
|
"naming constants with `_` is unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ast::ItemKind::ForeignMod(ref foreign_module) => {
|
ast::ItemKind::ForeignMod(ref foreign_module) => {
|
||||||
self.check_abi(foreign_module.abi, i.span);
|
self.check_abi(foreign_module.abi, i.span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6346,7 +6346,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
|
fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
|
||||||
let id = self.parse_ident()?;
|
let id = match self.token {
|
||||||
|
token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
|
||||||
|
self.bump(); // `_`
|
||||||
|
ident.gensym()
|
||||||
|
},
|
||||||
|
_ => self.parse_ident()?,
|
||||||
|
};
|
||||||
self.expect(&token::Colon)?;
|
self.expect(&token::Colon)?;
|
||||||
let ty = self.parse_ty()?;
|
let ty = self.parse_ty()?;
|
||||||
self.expect(&token::Eq)?;
|
self.expect(&token::Eq)?;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
|
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
|
||||||
# `0.x.0` for Cargo where they were released on `date`.
|
# `0.x.0` for Cargo where they were released on `date`.
|
||||||
|
|
||||||
date: 2018-09-23
|
date: 2018-10-13
|
||||||
rustc: beta
|
rustc: beta
|
||||||
cargo: beta
|
cargo: beta
|
||||||
|
|
||||||
|
|
31
src/test/mir-opt/inline-trait-method.rs
Normal file
31
src/test/mir-opt/inline-trait-method.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// compile-flags: -Z span_free_formats
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{}", test(&()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test(x: &dyn X) -> u32 {
|
||||||
|
x.y()
|
||||||
|
}
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
fn y(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X for () {
|
||||||
|
fn y(&self) -> u32 {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END RUST SOURCE
|
||||||
|
// START rustc.test.Inline.after.mir
|
||||||
|
// ...
|
||||||
|
// bb0: {
|
||||||
|
// ...
|
||||||
|
// _0 = const X::y(move _2) -> bb1;
|
||||||
|
// }
|
||||||
|
// ...
|
||||||
|
// END rustc.test.Inline.after.mir
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
fn check<Clone>(_c: Clone) {
|
fn check<Clone>(_c: Clone) {
|
||||||
fn check2() {
|
fn check2() {
|
||||||
<() as std::clone::Clone>::clone(&());
|
let _ = <() as std::clone::Clone>::clone(&());
|
||||||
}
|
}
|
||||||
check2();
|
check2();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
See `src/test/run-pass/closure-expected-type`.
|
|
20
src/test/ui/closure-expected-type/issue-24421.rs
Normal file
20
src/test/ui/closure-expected-type/issue-24421.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-pass
|
||||||
|
|
||||||
|
fn test<F: Fn(&u64, &u64)>(f: F) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test(|x, y | {});
|
||||||
|
test(|x:&u64, y:&u64| {});
|
||||||
|
test(|x:&u64, y | {});
|
||||||
|
test(|x, y:&u64| {});
|
||||||
|
}
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
|
|
||||||
#[lang = "panic_impl"]
|
#[lang = "arc"]
|
||||||
struct Foo; //~ ERROR E0152
|
struct Foo; //~ ERROR E0152
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
error[E0152]: duplicate lang item found: `panic_impl`.
|
error[E0152]: duplicate lang item found: `arc`.
|
||||||
--> $DIR/E0152.rs:14:1
|
--> $DIR/E0152.rs:14:1
|
||||||
|
|
|
|
||||||
LL | struct Foo; //~ ERROR E0152
|
LL | struct Foo; //~ ERROR E0152
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: first defined in crate `std`.
|
= note: first defined in crate `alloc`.
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
17
src/test/ui/error-codes/E0718.rs
Normal file
17
src/test/ui/error-codes/E0718.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(lang_items)]
|
||||||
|
|
||||||
|
// Arc is expected to be a struct, so this will error.
|
||||||
|
#[lang = "arc"]
|
||||||
|
static X: u32 = 42;
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/error-codes/E0718.stderr
Normal file
9
src/test/ui/error-codes/E0718.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0718]: `arc` language item must be applied to a struct
|
||||||
|
--> $DIR/E0718.rs:14:1
|
||||||
|
|
|
||||||
|
LL | #[lang = "arc"]
|
||||||
|
| ^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0718`.
|
24
src/test/ui/feature-gate-underscore_const_names.rs
Normal file
24
src/test/ui/feature-gate-underscore_const_names.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![feature(const_let)]
|
||||||
|
|
||||||
|
trait Trt {}
|
||||||
|
struct Str {}
|
||||||
|
|
||||||
|
impl Trt for Str {}
|
||||||
|
|
||||||
|
const _ : () = {
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
struct ImplementsTrait<T: Trt>(PhantomData<T>);
|
||||||
|
let _ = ImplementsTrait::<Str>(PhantomData);
|
||||||
|
()
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {}
|
16
src/test/ui/feature-gate-underscore_const_names.stderr
Normal file
16
src/test/ui/feature-gate-underscore_const_names.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error[E0658]: naming constants with `_` is unstable (see issue #54912)
|
||||||
|
--> $DIR/feature-gate-underscore_const_names.rs:17:1
|
||||||
|
|
|
||||||
|
LL | / const _ : () = {
|
||||||
|
LL | | use std::marker::PhantomData;
|
||||||
|
LL | | struct ImplementsTrait<T: Trt>(PhantomData<T>);
|
||||||
|
LL | | let _ = ImplementsTrait::<Str>(PhantomData);
|
||||||
|
LL | | ()
|
||||||
|
LL | | };
|
||||||
|
| |__^
|
||||||
|
|
|
||||||
|
= help: add #![feature(underscore_const_names)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -22,6 +22,11 @@ impl MyStruct {
|
||||||
fn need_to_use_this_method_value(&self) -> usize {
|
fn need_to_use_this_method_value(&self) -> usize {
|
||||||
self.n
|
self.n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn need_to_use_this_associated_function_value() -> isize {
|
||||||
|
-1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait EvenNature {
|
trait EvenNature {
|
||||||
|
@ -66,6 +71,9 @@ fn main() {
|
||||||
m.is_even(); // trait method!
|
m.is_even(); // trait method!
|
||||||
//~^ WARN unused return value
|
//~^ WARN unused return value
|
||||||
|
|
||||||
|
MyStruct::need_to_use_this_associated_function_value();
|
||||||
|
//~^ WARN unused return value
|
||||||
|
|
||||||
m.replace(3); // won't warn (annotation needs to be in trait definition)
|
m.replace(3); // won't warn (annotation needs to be in trait definition)
|
||||||
|
|
||||||
// comparison methods are `must_use`
|
// comparison methods are `must_use`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
warning: unused return value of `need_to_use_this_value` which must be used
|
warning: unused return value of `need_to_use_this_value` which must be used
|
||||||
--> $DIR/fn_must_use.rs:60:5
|
--> $DIR/fn_must_use.rs:65:5
|
||||||
|
|
|
|
||||||
LL | need_to_use_this_value(); //~ WARN unused return value
|
LL | need_to_use_this_value(); //~ WARN unused return value
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -12,39 +12,45 @@ LL | #![warn(unused_must_use)]
|
||||||
= note: it's important
|
= note: it's important
|
||||||
|
|
||||||
warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used
|
warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used
|
||||||
--> $DIR/fn_must_use.rs:65:5
|
--> $DIR/fn_must_use.rs:70:5
|
||||||
|
|
|
|
||||||
LL | m.need_to_use_this_method_value(); //~ WARN unused return value
|
LL | m.need_to_use_this_method_value(); //~ WARN unused return value
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unused return value of `EvenNature::is_even` which must be used
|
warning: unused return value of `EvenNature::is_even` which must be used
|
||||||
--> $DIR/fn_must_use.rs:66:5
|
--> $DIR/fn_must_use.rs:71:5
|
||||||
|
|
|
|
||||||
LL | m.is_even(); // trait method!
|
LL | m.is_even(); // trait method!
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: no side effects
|
= note: no side effects
|
||||||
|
|
||||||
|
warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` which must be used
|
||||||
|
--> $DIR/fn_must_use.rs:74:5
|
||||||
|
|
|
||||||
|
LL | MyStruct::need_to_use_this_associated_function_value();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unused return value of `std::cmp::PartialEq::eq` which must be used
|
warning: unused return value of `std::cmp::PartialEq::eq` which must be used
|
||||||
--> $DIR/fn_must_use.rs:72:5
|
--> $DIR/fn_must_use.rs:80:5
|
||||||
|
|
|
|
||||||
LL | 2.eq(&3); //~ WARN unused return value
|
LL | 2.eq(&3); //~ WARN unused return value
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
warning: unused return value of `std::cmp::PartialEq::eq` which must be used
|
warning: unused return value of `std::cmp::PartialEq::eq` which must be used
|
||||||
--> $DIR/fn_must_use.rs:73:5
|
--> $DIR/fn_must_use.rs:81:5
|
||||||
|
|
|
|
||||||
LL | m.eq(&n); //~ WARN unused return value
|
LL | m.eq(&n); //~ WARN unused return value
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
warning: unused comparison which must be used
|
warning: unused comparison which must be used
|
||||||
--> $DIR/fn_must_use.rs:76:5
|
--> $DIR/fn_must_use.rs:84:5
|
||||||
|
|
|
|
||||||
LL | 2 == 3; //~ WARN unused comparison
|
LL | 2 == 3; //~ WARN unused comparison
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
warning: unused comparison which must be used
|
warning: unused comparison which must be used
|
||||||
--> $DIR/fn_must_use.rs:77:5
|
--> $DIR/fn_must_use.rs:85:5
|
||||||
|
|
|
|
||||||
LL | m == n; //~ WARN unused comparison
|
LL | m == n; //~ WARN unused comparison
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
9
src/test/ui/issues/issue-52240.nll.stderr
Normal file
9
src/test/ui/issues/issue-52240.nll.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0596]: cannot borrow data in a `&` reference as mutable
|
||||||
|
--> $DIR/issue-52240.rs:9:27
|
||||||
|
|
|
||||||
|
LL | if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
|
||||||
|
| ^^^^^^^^^^^ cannot borrow as mutable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0596`.
|
16
src/test/ui/issues/issue-52240.rs
Normal file
16
src/test/ui/issues/issue-52240.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// issue-52240: Can turn immutable into mut with `ref mut`
|
||||||
|
|
||||||
|
enum Foo {
|
||||||
|
Bar(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let arr = vec!(Foo::Bar(0));
|
||||||
|
if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
|
||||||
|
//~^ ERROR cannot borrow field of immutable binding as mutable
|
||||||
|
*val = 9001;
|
||||||
|
}
|
||||||
|
match arr[0] {
|
||||||
|
Foo::Bar(ref s) => println!("{}", s)
|
||||||
|
}
|
||||||
|
}
|
9
src/test/ui/issues/issue-52240.stderr
Normal file
9
src/test/ui/issues/issue-52240.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0596]: cannot borrow field of immutable binding as mutable
|
||||||
|
--> $DIR/issue-52240.rs:9:27
|
||||||
|
|
|
||||||
|
LL | if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
|
||||||
|
| ^^^^^^^^^^^ cannot mutably borrow field of immutable binding
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0596`.
|
6
src/test/ui/issues/issue-54966.rs
Normal file
6
src/test/ui/issues/issue-54966.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// issue-54966: ICE returning an unknown type with impl FnMut
|
||||||
|
|
||||||
|
fn generate_duration() -> Oper<impl FnMut()> {}
|
||||||
|
//~^ ERROR cannot find type `Oper` in this scope
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/issues/issue-54966.stderr
Normal file
9
src/test/ui/issues/issue-54966.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0412]: cannot find type `Oper` in this scope
|
||||||
|
--> $DIR/issue-54966.rs:3:27
|
||||||
|
|
|
||||||
|
LL | fn generate_duration() -> Oper<impl FnMut()> {}
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0412`.
|
18
src/test/ui/panic-handler/panic-handler-wrong-location.rs
Normal file
18
src/test/ui/panic-handler/panic-handler-wrong-location.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags:-C panic=abort
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
#[no_mangle]
|
||||||
|
static X: u32 = 42;
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0718]: `panic_impl` language item must be applied to a function
|
||||||
|
--> $DIR/panic-handler-wrong-location.rs:16:1
|
||||||
|
|
|
||||||
|
LL | #[panic_handler]
|
||||||
|
| ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static item
|
||||||
|
|
||||||
|
error: `#[panic_handler]` function required, but not found
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0718`.
|
43
src/test/ui/underscore_const_names.rs
Normal file
43
src/test/ui/underscore_const_names.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-pass
|
||||||
|
|
||||||
|
#![feature(const_let)]
|
||||||
|
#![feature(underscore_const_names)]
|
||||||
|
|
||||||
|
trait Trt {}
|
||||||
|
struct Str {}
|
||||||
|
impl Trt for Str {}
|
||||||
|
|
||||||
|
macro_rules! check_impl {
|
||||||
|
($struct:ident,$trait:ident) => {
|
||||||
|
const _ : () = {
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
struct ImplementsTrait<T: $trait>(PhantomData<T>);
|
||||||
|
let _ = ImplementsTrait::<$struct>(PhantomData);
|
||||||
|
()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deny(unused)]
|
||||||
|
const _ : () = ();
|
||||||
|
|
||||||
|
const _ : i32 = 42;
|
||||||
|
const _ : Str = Str{};
|
||||||
|
|
||||||
|
check_impl!(Str, Trt);
|
||||||
|
check_impl!(Str, Trt);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
check_impl!(Str, Trt);
|
||||||
|
check_impl!(Str, Trt);
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit ad6e5c0037d88602a1c95051e42b392ed5ffcbe8
|
Subproject commit 5dbac98885199bbd7c0f189d7405b5523434d1e3
|
|
@ -1 +1 @@
|
||||||
Subproject commit 32b1d1fc157f71ed2f10b60fe28abe087a743618
|
Subproject commit 9d3373137b74a403281b293b19ab9346773af073
|
|
@ -1 +1 @@
|
||||||
Subproject commit 26f9d617c347185433b77c481a5c50c55d9b72ce
|
Subproject commit 8b14b03368429e6ee2a8ac0e0c876505606ab1f1
|
|
@ -1 +1 @@
|
||||||
Subproject commit 15d4d4a5b0cf3c0155195f3322cc7a61148e5567
|
Subproject commit 440a9855b73b6bf9b5345cf3a79565566f6ef345
|
Loading…
Add table
Add a link
Reference in a new issue