From 8740d5d171fbb2fc9a12e46ecda32a0124badb46 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 20:08:32 +0100 Subject: [PATCH 01/46] Add benchmarks for [u8]::make_ascii_uppercase --- src/libcore/benches/ascii_case.rs | 172 ++++++++++++++++++++++++++++++ src/libcore/benches/lib.rs | 1 + 2 files changed, 173 insertions(+) create mode 100644 src/libcore/benches/ascii_case.rs diff --git a/src/libcore/benches/ascii_case.rs b/src/libcore/benches/ascii_case.rs new file mode 100644 index 0000000000000..43242ca3f364e --- /dev/null +++ b/src/libcore/benches/ascii_case.rs @@ -0,0 +1,172 @@ +// Lower-case ASCII 'a' is the first byte that has its highest bit set after wrap-adding 0x1F: +// +// b'a' + 0x1F == 0x80 == 0b1000_0000 +// b'z' + 0x1F == 0x98 == 0b10011000 +// +// Lower-case ASCII 'z' is the last byte that has its highest bit unset after wrap-adding 0x05: +// +// b'a' + 0x05 == 0x66 == 0b0110_0110 +// b'z' + 0x05 == 0x7F == 0b0111_1111 +// +// … except for 0xFB to 0xFF, but those are in the range of bytes that have the highest bit +// unset again after adding 0x1F. +// +// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set +// iff `byte` is a lower-case ASCII letter. +// +// Lower-case ASCII letters all have the 0x20 bit set. +// (Two positions right of 0x80, the highest bit.) +// Unsetting that bit produces the same letter, in upper-case. +// +// Therefore: +fn branchless_to_ascii_upper_case(byte: u8) -> u8 { + byte & + !( + ( + byte.wrapping_add(0x1f) & + !byte.wrapping_add(0x05) & + 0x80 + ) >> 2 + ) +} + + +macro_rules! benches { + ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { + benches!(mod short SHORT $($name $arg $body)+); + benches!(mod medium MEDIUM $($name $arg $body)+); + benches!(mod long LONG $($name $arg $body)+); + }; + + (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => { + mod $mod_name { + use super::*; + + $( + #[bench] + fn $name(bencher: &mut Bencher) { + bencher.bytes = $input.len() as u64; + bencher.iter(|| { + let mut vec = $input.as_bytes().to_vec(); + { + let $arg = &mut vec[..]; + $body + } + vec + }) + } + )+ + } + } +} + +use test::black_box; +use test::Bencher; + +benches! { + fn bench00_alloc_only(_bytes: &mut [u8]) {} + + fn bench01_black_box_read_each_byte(bytes: &mut [u8]) { + for byte in bytes { + black_box(*byte); + } + } + + fn bench02_lookup(bytes: &mut [u8]) { + for byte in bytes { + *byte = ASCII_UPPERCASE_MAP[*byte as usize] + } + } + + fn bench03_branch_and_subtract(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte - b'a' + b'A' + } else { + *byte + } + } + } + + fn bench04_branch_and_mask(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte & !0x20 + } else { + *byte + } + } + } + + fn bench05_branchless(bytes: &mut [u8]) { + for byte in bytes { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn bench06_libcore(bytes: &mut [u8]) { + bytes.make_ascii_uppercase() + } +} + +macro_rules! repeat { + ($s: expr) => { concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) } +} + +const SHORT: &'static str = "Alice's"; +const MEDIUM: &'static str = "Alice's Adventures in Wonderland"; +const LONG: &'static str = repeat!(r#" + La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) + Alice's Adventures in Wonderland (1865) + Phantasmagoria and Other Poems (1869) + Through the Looking-Glass, and What Alice Found There (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) + The Hunting of the Snark (1876) + Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, including the long poem "Phantasmagoria" + A Tangled Tale (1885) + Sylvie and Bruno (1889) + Sylvie and Bruno Concluded (1893) + Pillow Problems (1893) + What the Tortoise Said to Achilles (1895) + Three Sunsets and Other Poems (1898) + The Manlet (1903)[106] +"#); + +const ASCII_UPPERCASE_MAP: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', + b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', + b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', + b'`', + + b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', + + b'{', b'|', b'}', b'~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 48572af611a5b..b72d035b0ce94 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -5,6 +5,7 @@ extern crate core; extern crate test; mod any; +mod ascii_case; mod char; mod hash; mod iter; From ce933f77c865a15670855ac5941fe200752b739f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 20:16:37 +0100 Subject: [PATCH 02/46] Make u8::to_ascii_lowercase and to_ascii_uppercase branchless --- src/libcore/benches/ascii_case.rs | 22 +----- src/libcore/num/mod.rs | 122 ++++++++++-------------------- 2 files changed, 43 insertions(+), 101 deletions(-) diff --git a/src/libcore/benches/ascii_case.rs b/src/libcore/benches/ascii_case.rs index 43242ca3f364e..1c9691d1ee173 100644 --- a/src/libcore/benches/ascii_case.rs +++ b/src/libcore/benches/ascii_case.rs @@ -1,24 +1,4 @@ -// Lower-case ASCII 'a' is the first byte that has its highest bit set after wrap-adding 0x1F: -// -// b'a' + 0x1F == 0x80 == 0b1000_0000 -// b'z' + 0x1F == 0x98 == 0b10011000 -// -// Lower-case ASCII 'z' is the last byte that has its highest bit unset after wrap-adding 0x05: -// -// b'a' + 0x05 == 0x66 == 0b0110_0110 -// b'z' + 0x05 == 0x7F == 0b0111_1111 -// -// … except for 0xFB to 0xFF, but those are in the range of bytes that have the highest bit -// unset again after adding 0x1F. -// -// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set -// iff `byte` is a lower-case ASCII letter. -// -// Lower-case ASCII letters all have the 0x20 bit set. -// (Two positions right of 0x80, the highest bit.) -// Unsetting that bit produces the same letter, in upper-case. -// -// Therefore: +// See comments in `u8::to_ascii_uppercase` in `src/libcore/num/mod.rs`. fn branchless_to_ascii_upper_case(byte: u8) -> u8 { byte & !( diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d93cfbc2a28ac..977e21e0dc89a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3794,7 +3794,39 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> u8 { - ASCII_UPPERCASE_MAP[*self as usize] + // See benchmarks in src/libcore/benches/ascii_case.rs + + // Lower-case ASCII 'a' is the first byte that has its highest bit set + // after wrap-adding 0x1F: + // + // b'a' + 0x1F == 0x80 == 0b1000_0000 + // b'z' + 0x1F == 0x98 == 0b10011000 + // + // Lower-case ASCII 'z' is the last byte that has its highest bit unset + // after wrap-adding 0x05: + // + // b'a' + 0x05 == 0x66 == 0b0110_0110 + // b'z' + 0x05 == 0x7F == 0b0111_1111 + // + // … except for 0xFB to 0xFF, but those are in the range of bytes + // that have the highest bit unset again after adding 0x1F. + // + // So `(byte + 0x1f) & !(byte + 5)` has its highest bit set + // iff `byte` is a lower-case ASCII letter. + // + // Lower-case ASCII letters all have the 0x20 bit set. + // (Two positions right of 0x80, the highest bit.) + // Unsetting that bit produces the same letter, in upper-case. + // + // Therefore: + *self & + !( + ( + self.wrapping_add(0x1f) & + !self.wrapping_add(0x05) & + 0x80 + ) >> 2 + ) } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -3816,7 +3848,15 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> u8 { - ASCII_LOWERCASE_MAP[*self as usize] + // See comments in to_ascii_uppercase above. + *self | + ( + ( + self.wrapping_add(0x3f) & + !self.wrapping_add(0x25) & + 0x80 + ) >> 2 + ) } /// Checks that two values are an ASCII case-insensitive match. @@ -4940,84 +4980,6 @@ impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" // Float -> Float impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -static ASCII_LOWERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', - - b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', - - b'[', b'\\', b']', b'^', b'_', - b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -static ASCII_UPPERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', - b'`', - - b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', - - b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - enum AsciiCharacterClass { C, // control Cw, // control whitespace From fbe34cc521a5d0f04dd6afadb5b200f0338f41d9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 20:40:32 +0100 Subject: [PATCH 03/46] =?UTF-8?q?Add=20benchmark=20for=20not-quite-correct?= =?UTF-8?q?=20=E2=80=9Cfake=20SIMD=E2=80=9D=20make=5Fascii=5Fuppercase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libcore/benches/ascii_case.rs | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/libcore/benches/ascii_case.rs b/src/libcore/benches/ascii_case.rs index 1c9691d1ee173..df82a8cb1d537 100644 --- a/src/libcore/benches/ascii_case.rs +++ b/src/libcore/benches/ascii_case.rs @@ -87,6 +87,52 @@ benches! { fn bench06_libcore(bytes: &mut [u8]) { bytes.make_ascii_uppercase() } + + fn bench07_fake_simd_u32(bytes: &mut [u8]) { + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: this is incorrect for some byte values: + // addition within a byte can carry/overflow into the next byte. + // Test case: b"\xFFz " + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f) & + !word.wrapping_add(0x05050505) & + 0x80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn bench08_fake_simd_u64(bytes: &mut [u8]) { + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: like above, this is incorrect for some byte values. + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f_1f1f1f1f) & + !word.wrapping_add(0x05050505_05050505) & + 0x80808080_80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } } macro_rules! repeat { From e3fb6f89fef4fea94deeac572b0373843560c2d6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 21:28:33 +0100 Subject: [PATCH 04/46] Tidy --- src/libcore/benches/ascii_case.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcore/benches/ascii_case.rs b/src/libcore/benches/ascii_case.rs index df82a8cb1d537..dcc87cc45b1e3 100644 --- a/src/libcore/benches/ascii_case.rs +++ b/src/libcore/benches/ascii_case.rs @@ -145,9 +145,11 @@ const LONG: &'static str = repeat!(r#" La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) Alice's Adventures in Wonderland (1865) Phantasmagoria and Other Poems (1869) - Through the Looking-Glass, and What Alice Found There (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) + Through the Looking-Glass, and What Alice Found There + (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) The Hunting of the Snark (1876) - Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, including the long poem "Phantasmagoria" + Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, + including the long poem "Phantasmagoria" A Tangled Tale (1885) Sylvie and Bruno (1889) Sylvie and Bruno Concluded (1893) From 525a043c6bc8a220b7dbdde3eb10bb79f8e99506 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 23:32:36 +0100 Subject: [PATCH 05/46] Rename src/libcore/benches/ascii_case.rs to ascii.rs --- src/libcore/benches/{ascii_case.rs => ascii.rs} | 6 ++++++ src/libcore/benches/lib.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) rename src/libcore/benches/{ascii_case.rs => ascii.rs} (97%) diff --git a/src/libcore/benches/ascii_case.rs b/src/libcore/benches/ascii.rs similarity index 97% rename from src/libcore/benches/ascii_case.rs rename to src/libcore/benches/ascii.rs index dcc87cc45b1e3..2714a8a5c278e 100644 --- a/src/libcore/benches/ascii_case.rs +++ b/src/libcore/benches/ascii.rs @@ -84,6 +84,12 @@ benches! { } } + fn bench05_multiply_by_bool(bytes: &mut [u8]) { + for byte in bytes { + *byte &= !(0x20 * (b'a' <= *byte && *byte <= b'z') as u8) + } + } + fn bench06_libcore(bytes: &mut [u8]) { bytes.make_ascii_uppercase() } diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index b72d035b0ce94..707cdd5f450ea 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -5,7 +5,7 @@ extern crate core; extern crate test; mod any; -mod ascii_case; +mod ascii; mod char; mod hash; mod iter; From 6d3840b23a185d057cc9792a2516e6a71887f277 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 23:56:50 +0100 Subject: [PATCH 06/46] Add benchmarks for `u8::is_ascii*` --- src/libcore/benches/ascii.rs | 49 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index 2714a8a5c278e..e20b1b9bf3136 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -12,7 +12,14 @@ fn branchless_to_ascii_upper_case(byte: u8) -> u8 { macro_rules! benches { - ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { + ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => { + benches! {@ + $( fn $name($arg: &mut [u8]) $body )+ + $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+ + } + }; + + (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { benches!(mod short SHORT $($name $arg $body)+); benches!(mod medium MEDIUM $($name $arg $body)+); benches!(mod long LONG $($name $arg $body)+); @@ -30,7 +37,7 @@ macro_rules! benches { let mut vec = $input.as_bytes().to_vec(); { let $arg = &mut vec[..]; - $body + black_box($body); } vec }) @@ -44,21 +51,21 @@ use test::black_box; use test::Bencher; benches! { - fn bench00_alloc_only(_bytes: &mut [u8]) {} + fn case00_alloc_only(_bytes: &mut [u8]) {} - fn bench01_black_box_read_each_byte(bytes: &mut [u8]) { + fn case01_black_box_read_each_byte(bytes: &mut [u8]) { for byte in bytes { black_box(*byte); } } - fn bench02_lookup(bytes: &mut [u8]) { + fn case02_lookup(bytes: &mut [u8]) { for byte in bytes { *byte = ASCII_UPPERCASE_MAP[*byte as usize] } } - fn bench03_branch_and_subtract(bytes: &mut [u8]) { + fn case03_branch_and_subtract(bytes: &mut [u8]) { for byte in bytes { *byte = if b'a' <= *byte && *byte <= b'z' { *byte - b'a' + b'A' @@ -68,7 +75,7 @@ benches! { } } - fn bench04_branch_and_mask(bytes: &mut [u8]) { + fn case04_branch_and_mask(bytes: &mut [u8]) { for byte in bytes { *byte = if b'a' <= *byte && *byte <= b'z' { *byte & !0x20 @@ -78,23 +85,17 @@ benches! { } } - fn bench05_branchless(bytes: &mut [u8]) { + fn case05_branchless(bytes: &mut [u8]) { for byte in bytes { *byte = branchless_to_ascii_upper_case(*byte) } } - fn bench05_multiply_by_bool(bytes: &mut [u8]) { - for byte in bytes { - *byte &= !(0x20 * (b'a' <= *byte && *byte <= b'z') as u8) - } - } - - fn bench06_libcore(bytes: &mut [u8]) { + fn case06_libcore(bytes: &mut [u8]) { bytes.make_ascii_uppercase() } - fn bench07_fake_simd_u32(bytes: &mut [u8]) { + fn case07_fake_simd_u32(bytes: &mut [u8]) { let (before, aligned, after) = unsafe { bytes.align_to_mut::() }; @@ -118,7 +119,7 @@ benches! { } } - fn bench08_fake_simd_u64(bytes: &mut [u8]) { + fn case08_fake_simd_u64(bytes: &mut [u8]) { let (before, aligned, after) = unsafe { bytes.align_to_mut::() }; @@ -139,6 +140,20 @@ benches! { *byte = branchless_to_ascii_upper_case(*byte) } } + + @iter + + is_ascii, + is_ascii_alphabetic, + is_ascii_uppercase, + is_ascii_lowercase, + is_ascii_alphanumeric, + is_ascii_digit, + is_ascii_hexdigit, + is_ascii_punctuation, + is_ascii_graphic, + is_ascii_whitespace, + is_ascii_control, } macro_rules! repeat { From b4faa9b45635ae5185d562701d7429e5fbb08c8b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 18 Mar 2019 23:57:09 +0100 Subject: [PATCH 07/46] Remove ASCII_CHARACTER_CLASS table, use `match` with range patterns instead. --- src/libcore/num/mod.rs | 75 +++++++++++------------------------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 977e21e0dc89a..64469a4b7e43c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3958,9 +3958,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_alphabetic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - L | Lx | U | Ux => true, + match *self { + b'A'...b'Z' | b'a'...b'z' => true, _ => false } } @@ -3994,9 +3993,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_uppercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - U | Ux => true, + match *self { + b'A'...b'Z' => true, _ => false } } @@ -4030,9 +4028,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_lowercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - L | Lx => true, + match *self { + b'a'...b'z' => true, _ => false } } @@ -4069,9 +4066,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_alphanumeric(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D | L | Lx | U | Ux => true, + match *self { + b'0'...b'9' | b'A'...b'Z' | b'a'...b'z' => true, _ => false } } @@ -4105,9 +4101,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_digit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D => true, + match *self { + b'0'...b'9' => true, _ => false } } @@ -4144,9 +4139,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_hexdigit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D | Lx | Ux => true, + match *self { + b'0'...b'9' | b'A'...b'F' | b'a'...b'f' => true, _ => false } } @@ -4184,9 +4178,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_punctuation(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - P => true, + match *self { + b'!'...b'/' | b':'...b'@' | b'['...b'`' | b'{'...b'~' => true, _ => false } } @@ -4220,9 +4213,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_graphic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Ux | U | Lx | L | D | P => true, + match *self { + b'!'...b'~' => true, _ => false } } @@ -4273,9 +4265,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_whitespace(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Cw | W => true, + match *self { + b'\t' | b'\n' | b'\x0C' | b'\r' | b' ' => true, _ => false } } @@ -4311,9 +4302,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_control(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - C | Cw => true, + match *self { + b'\0'...b'\x1F' | b'\x7F' => true, _ => false } } @@ -4979,28 +4969,3 @@ impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" // Float -> Float impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -enum AsciiCharacterClass { - C, // control - Cw, // control whitespace - W, // whitespace - D, // digit - L, // lowercase - Lx, // lowercase hex digit - U, // uppercase - Ux, // uppercase hex digit - P, // punctuation -} -use self::AsciiCharacterClass::*; - -static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [ -// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f - C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ - C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ - W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ - D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ - P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ - U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ - P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ - L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ -]; From 4a3241a815e951dfa87e9be7133e8265bc945e57 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 19 Mar 2019 00:34:27 +0100 Subject: [PATCH 08/46] Benchmark more possibles impls of [u8]::make_ascii_uppercase --- src/libcore/benches/ascii.rs | 84 +++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index e20b1b9bf3136..ce36027394a48 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -59,7 +59,7 @@ benches! { } } - fn case02_lookup(bytes: &mut [u8]) { + fn case02_lookup_table(bytes: &mut [u8]) { for byte in bytes { *byte = ASCII_UPPERCASE_MAP[*byte as usize] } @@ -141,6 +141,55 @@ benches! { } } + fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + if b >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false, + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'...b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'...b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !((is_ascii_lowercase(*byte) as u8) << 5) + } + } + @iter is_ascii, @@ -219,3 +268,36 @@ const ASCII_UPPERCASE_MAP: [u8; 256] = [ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; +enum AsciiCharacterClass { + C, // control + Cw, // control whitespace + W, // whitespace + D, // digit + L, // lowercase + Lx, // lowercase hex digit + U, // uppercase + Ux, // uppercase hex digit + P, // punctuation + N, // Non-ASCII +} +use self::AsciiCharacterClass::*; + +static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ +// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f + C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ + W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ + D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ + P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ + U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ + P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ + L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, +]; From 0ad91f73d92c3b8d3978f8f54c04b8efe3d2e673 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 19 Mar 2019 00:50:26 +0100 Subject: [PATCH 09/46] Simplify u8::to_ascii_{upp,low}ercase while keeping it fast --- src/libcore/benches/ascii.rs | 24 ++++++++++++++++++- src/libcore/num/mod.rs | 46 ++++-------------------------------- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index ce36027394a48..89e67cca4b754 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -1,4 +1,26 @@ -// See comments in `u8::to_ascii_uppercase` in `src/libcore/num/mod.rs`. +// Lower-case ASCII 'a' is the first byte that has its highest bit set +// after wrap-adding 0x1F: +// +// b'a' + 0x1F == 0x80 == 0b1000_0000 +// b'z' + 0x1F == 0x98 == 0b10011000 +// +// Lower-case ASCII 'z' is the last byte that has its highest bit unset +// after wrap-adding 0x05: +// +// b'a' + 0x05 == 0x66 == 0b0110_0110 +// b'z' + 0x05 == 0x7F == 0b0111_1111 +// +// … except for 0xFB to 0xFF, but those are in the range of bytes +// that have the highest bit unset again after adding 0x1F. +// +// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set +// iff `byte` is a lower-case ASCII letter. +// +// Lower-case ASCII letters all have the 0x20 bit set. +// (Two positions right of 0x80, the highest bit.) +// Unsetting that bit produces the same letter, in upper-case. +// +// Therefore: fn branchless_to_ascii_upper_case(byte: u8) -> u8 { byte & !( diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 64469a4b7e43c..3fcae6b94b06d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3794,39 +3794,8 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> u8 { - // See benchmarks in src/libcore/benches/ascii_case.rs - - // Lower-case ASCII 'a' is the first byte that has its highest bit set - // after wrap-adding 0x1F: - // - // b'a' + 0x1F == 0x80 == 0b1000_0000 - // b'z' + 0x1F == 0x98 == 0b10011000 - // - // Lower-case ASCII 'z' is the last byte that has its highest bit unset - // after wrap-adding 0x05: - // - // b'a' + 0x05 == 0x66 == 0b0110_0110 - // b'z' + 0x05 == 0x7F == 0b0111_1111 - // - // … except for 0xFB to 0xFF, but those are in the range of bytes - // that have the highest bit unset again after adding 0x1F. - // - // So `(byte + 0x1f) & !(byte + 5)` has its highest bit set - // iff `byte` is a lower-case ASCII letter. - // - // Lower-case ASCII letters all have the 0x20 bit set. - // (Two positions right of 0x80, the highest bit.) - // Unsetting that bit produces the same letter, in upper-case. - // - // Therefore: - *self & - !( - ( - self.wrapping_add(0x1f) & - !self.wrapping_add(0x05) & - 0x80 - ) >> 2 - ) + // Unset the fith bit if this is a lowercase letter + *self & !((self.is_ascii_lowercase() as u8) << 5) } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -3848,15 +3817,8 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> u8 { - // See comments in to_ascii_uppercase above. - *self | - ( - ( - self.wrapping_add(0x3f) & - !self.wrapping_add(0x25) & - 0x80 - ) >> 2 - ) + // Set the fith bit if this is an uppercase letter + *self | ((self.is_ascii_uppercase() as u8) << 5) } /// Checks that two values are an ASCII case-insensitive match. From c1ec29ace000ce4c733cde6948c87f9bc2370691 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 19 Mar 2019 08:32:15 +0100 Subject: [PATCH 10/46] ASCII uppercase: add "subtract shifted bool" benchmark --- src/libcore/benches/ascii.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index 89e67cca4b754..968d28a995897 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -212,6 +212,18 @@ benches! { } } + fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'...b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (is_ascii_lowercase(*byte) as u8) << 5 + } + } + @iter is_ascii, From 7fad370fe9dc000f6f6f497a1939de6196e2c4fc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 19 Mar 2019 13:41:59 +0100 Subject: [PATCH 11/46] ASCII uppercase: add "subtract multiplied bool" benchmark --- src/libcore/benches/ascii.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index 968d28a995897..635537e312158 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -224,6 +224,18 @@ benches! { } } + fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'...b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8 + } + } + @iter is_ascii, From b34a71b7daf0f770cd5e7f9c36be960e32d2b167 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Fri, 22 Mar 2019 14:56:08 -0400 Subject: [PATCH 12/46] add suggestions to trim_{left,right} deprecations --- src/libcore/str/mod.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 528281d317be3..f54d7badc3ae0 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -3601,7 +3601,11 @@ impl str { /// assert!(Some('ע') == s.trim_left().chars().next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_start`", + suggestion = "trim_start", + )] pub fn trim_left(&self) -> &str { self.trim_start() } @@ -3638,7 +3642,11 @@ impl str { /// assert!(Some('ת') == s.trim_right().chars().rev().next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_end`", + suggestion = "trim_end", + )] pub fn trim_right(&self) -> &str { self.trim_end() } @@ -3802,7 +3810,11 @@ impl str { /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_start_matches`", + suggestion = "trim_start_matches", + )] pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { self.trim_start_matches(pat) } @@ -3840,7 +3852,11 @@ impl str { /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_end_matches`", + suggestion = "trim_end_matches", + )] pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> { From ac3290e8d949448193014c85096f8772db331d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2019 22:42:51 -0700 Subject: [PATCH 13/46] Add suggestion to use `&*var` when `&str: From` is expected --- .../src/language-features/on-unimplemented.md | 12 ++++++++++++ src/libcore/convert.rs | 6 ++++++ src/test/ui/suggestions/into-str.rs | 6 ++++++ src/test/ui/suggestions/into-str.stderr | 17 +++++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 src/test/ui/suggestions/into-str.rs create mode 100644 src/test/ui/suggestions/into-str.stderr diff --git a/src/doc/unstable-book/src/language-features/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md index f787f629756f3..b156038fba06d 100644 --- a/src/doc/unstable-book/src/language-features/on-unimplemented.md +++ b/src/doc/unstable-book/src/language-features/on-unimplemented.md @@ -138,3 +138,15 @@ error[E0277]: `&str` is not an iterator = help: the trait `std::iter::Iterator` is not implemented for `&str` = note: required by `std::iter::IntoIterator::into_iter` ``` + +If you need to filter on multiple attributes, you can use `all` in the following way: + +```rust,compile_fail +#[rustc_on_unimplemented( + on( + all(_Self="&str", T="std::string::String"), + note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" + ) +)] +pub trait From: Sized { /* ... */ } +``` \ No newline at end of file diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 774d648558b48..cb574a53dbccb 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -352,6 +352,12 @@ pub trait Into: Sized { /// [`from`]: trait.From.html#tymethod.from /// [book]: ../../book/ch09-00-error-handling.html #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented( + on( + all(_Self="&str", T="std::string::String"), + note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" + ) +)] pub trait From: Sized { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/suggestions/into-str.rs b/src/test/ui/suggestions/into-str.rs new file mode 100644 index 0000000000000..9793ee801d185 --- /dev/null +++ b/src/test/ui/suggestions/into-str.rs @@ -0,0 +1,6 @@ +fn foo<'a, T>(_t: T) where T: Into<&'a str> {} + +fn main() { + foo(String::new()); + //~^ ERROR the trait bound `&str: std::convert::From` is not satisfied +} diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr new file mode 100644 index 0000000000000..f341d36370213 --- /dev/null +++ b/src/test/ui/suggestions/into-str.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `&str: std::convert::From` is not satisfied + --> $DIR/into-str.rs:4:5 + | +LL | foo(String::new()); + | ^^^ the trait `std::convert::From` is not implemented for `&str` + | + = note: you can coerce a `std::string::String` into a `&str` by writing `&*variable` + = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` +note: required by `foo` + --> $DIR/into-str.rs:1:1 + | +LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2f7b32091ecdc86520d75aa8fe6bcffb5849732d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 18 Mar 2019 11:06:48 -0700 Subject: [PATCH 14/46] extend on-unimplemented docs --- .../unstable-book/src/language-features/on-unimplemented.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md index b156038fba06d..a770ab65c26f8 100644 --- a/src/doc/unstable-book/src/language-features/on-unimplemented.md +++ b/src/doc/unstable-book/src/language-features/on-unimplemented.md @@ -139,7 +139,8 @@ error[E0277]: `&str` is not an iterator = note: required by `std::iter::IntoIterator::into_iter` ``` -If you need to filter on multiple attributes, you can use `all` in the following way: +If you need to filter on multiple attributes, you can use `all`, `any` or +`not` in the following way: ```rust,compile_fail #[rustc_on_unimplemented( @@ -149,4 +150,4 @@ If you need to filter on multiple attributes, you can use `all` in the following ) )] pub trait From: Sized { /* ... */ } -``` \ No newline at end of file +``` From e929d19edc99e5eb7af319709247470cff99719b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 22 Mar 2019 20:38:09 -0700 Subject: [PATCH 15/46] review comments --- src/libcore/convert.rs | 2 +- src/test/ui/suggestions/into-str.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index cb574a53dbccb..d36de3bbe8691 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -355,7 +355,7 @@ pub trait Into: Sized { #[rustc_on_unimplemented( on( all(_Self="&str", T="std::string::String"), - note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" + note="to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ) )] pub trait From: Sized { diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index f341d36370213..3e28700ce9552 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `&str: std::convert::From` is LL | foo(String::new()); | ^^^ the trait `std::convert::From` is not implemented for `&str` | - = note: you can coerce a `std::string::String` into a `&str` by writing `&*variable` + = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` note: required by `foo` --> $DIR/into-str.rs:1:1 From 4b382946e4fffb0f82e821ae4f8239a439b35207 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 13 Jan 2019 04:52:59 +0300 Subject: [PATCH 16/46] syntax: Remove warning for unnecessary path disambiguators --- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 31 ++++++---------- .../packed/packed-struct-generic-size.rs | 12 +++---- .../packed/packed-struct-generic-size.stderr | 36 ------------------- src/test/ui/issues/issue-36116.rs | 6 ++-- src/test/ui/issues/issue-36116.stderr | 12 ------- 6 files changed, 20 insertions(+), 79 deletions(-) delete mode 100644 src/test/run-pass/packed/packed-struct-generic-size.stderr delete mode 100644 src/test/ui/issues/issue-36116.stderr diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 1a419e7fadaa0..ab5823eaca52a 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -929,7 +929,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { p.fatal(&format!("expected ident, found {}", &token_str)).emit(); FatalError.raise() } - "path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))), + "path" => token::NtPath(panictry!(p.parse_path(PathStyle::Type))), "meta" => token::NtMeta(panictry!(p.parse_meta_item())), "vis" => token::NtVis(panictry!(p.parse_visibility(true))), "lifetime" => if p.check_lifetime() { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6ff06aa4b31d3..c3e1aa7ae117f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1903,7 +1903,7 @@ impl<'a> Parser<'a> { self.expect(&token::ModSep)?; let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; - self.parse_path_segments(&mut path.segments, T::PATH_STYLE, true)?; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; path.span = ty_span.to(self.prev_span); let ty_str = self.sess.source_map().span_to_snippet(ty_span) @@ -2294,7 +2294,7 @@ impl<'a> Parser<'a> { self.expect(&token::ModSep)?; let qself = QSelf { ty, path_span, position: path.segments.len() }; - self.parse_path_segments(&mut path.segments, style, true)?; + self.parse_path_segments(&mut path.segments, style)?; Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) } @@ -2310,11 +2310,6 @@ impl<'a> Parser<'a> { /// `Fn(Args)` (without disambiguator) /// `Fn::(Args)` (with disambiguator) pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - self.parse_path_common(style, true) - } - - crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |path| { if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some()) { @@ -2329,7 +2324,7 @@ impl<'a> Parser<'a> { if self.eat(&token::ModSep) { segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } - self.parse_path_segments(&mut segments, style, enable_warning)?; + self.parse_path_segments(&mut segments, style)?; Ok(ast::Path { segments, span: lo.to(self.prev_span) }) } @@ -2357,11 +2352,10 @@ impl<'a> Parser<'a> { fn parse_path_segments(&mut self, segments: &mut Vec, - style: PathStyle, - enable_warning: bool) + style: PathStyle) -> PResult<'a, ()> { loop { - let segment = self.parse_path_segment(style, enable_warning)?; + let segment = self.parse_path_segment(style)?; if style == PathStyle::Expr { // In order to check for trailing angle brackets, we must have finished // recursing (`parse_path_segment` can indirectly call this function), @@ -2389,8 +2383,7 @@ impl<'a> Parser<'a> { } } - fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, PathSegment> { + fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; let is_args_start = |token: &token::Token| match *token { @@ -2407,13 +2400,6 @@ impl<'a> Parser<'a> { Ok(if style == PathStyle::Type && check_args_start(self) || style != PathStyle::Mod && self.check(&token::ModSep) && self.look_ahead(1, |t| is_args_start(t)) { - // Generic arguments are found - `<`, `(`, `::<` or `::(`. - if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning { - self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator") - .span_label(self.prev_span, "try removing `::`").emit(); - } - let lo = self.span; - // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If // it isn't, then we reset the unmatched angle bracket count as we're about to start // parsing a new path. @@ -2422,6 +2408,9 @@ impl<'a> Parser<'a> { self.max_angle_bracket_count = 0; } + // Generic arguments are found - `<`, `(`, `::<` or `::(`. + self.eat(&token::ModSep); + let lo = self.span; let args = if self.eat_lt() { // `<'a, T, A = U>` let (args, bindings) = @@ -3043,7 +3032,7 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { - let segment = self.parse_path_segment(PathStyle::Expr, true)?; + let segment = self.parse_path_segment(PathStyle::Expr)?; self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); Ok(match self.token { diff --git a/src/test/run-pass/packed/packed-struct-generic-size.rs b/src/test/run-pass/packed/packed-struct-generic-size.rs index 08d4674d2a88a..7c93e46c30c23 100644 --- a/src/test/run-pass/packed/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed/packed-struct-generic-size.rs @@ -33,12 +33,12 @@ macro_rules! check { } pub fn main() { - check!(P1::, 1, 3); - check!(P1::, 1, 11); + check!(P1, 1, 3); + check!(P1, 1, 11); - check!(P2::, 1, 3); - check!(P2::, 2, 12); + check!(P2, 1, 3); + check!(P2, 2, 12); - check!(P4C::, 1, 3); - check!(P4C::, 4, 12); + check!(P4C, 1, 3); + check!(P4C, 4, 12); } diff --git a/src/test/run-pass/packed/packed-struct-generic-size.stderr b/src/test/run-pass/packed/packed-struct-generic-size.stderr deleted file mode 100644 index 1af476c156866..0000000000000 --- a/src/test/run-pass/packed/packed-struct-generic-size.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:36:14 - | -LL | check!(P1::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:37:14 - | -LL | check!(P1::, 1, 11); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:39:14 - | -LL | check!(P2::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:40:14 - | -LL | check!(P2::, 2, 12); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:42:15 - | -LL | check!(P4C::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:43:15 - | -LL | check!(P4C::, 4, 12); - | ^^ try removing `::` - diff --git a/src/test/ui/issues/issue-36116.rs b/src/test/ui/issues/issue-36116.rs index f4fe96cf75b55..b4bfba4d6e5d7 100644 --- a/src/test/ui/issues/issue-36116.rs +++ b/src/test/ui/issues/issue-36116.rs @@ -17,10 +17,10 @@ struct Foo { struct S(T); fn f() { - let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); //~ WARN unnecessary path disambiguator - let g: Foo:: = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator + let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); + let g: Foo:: = Foo { _a: 42 }; - m!(S::); // OK, no warning + m!(S::); } diff --git a/src/test/ui/issues/issue-36116.stderr b/src/test/ui/issues/issue-36116.stderr deleted file mode 100644 index 5236db29ae4af..0000000000000 --- a/src/test/ui/issues/issue-36116.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: unnecessary path disambiguator - --> $DIR/issue-36116.rs:20:50 - | -LL | let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/issue-36116.rs:21:15 - | -LL | let g: Foo:: = Foo { _a: 42 }; - | ^^ try removing `::` - From 00716b480fa8fbbfc0a3d64b908cafe7141b1f09 Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Sat, 23 Mar 2019 19:43:32 -0400 Subject: [PATCH 17/46] Make `ptr::eq` documentation mention smart-pointer behavior Resolves #59214 --- src/libcore/ptr.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a9a029d606d6f..c9f1a87ba9ff2 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2483,6 +2483,10 @@ impl Eq for *mut T {} /// by their address rather than comparing the values they point to /// (which is what the `PartialEq for &T` implementation does). /// +/// Smart pointer types, such as `Box`, `Rc`, and `Arc` do not compare +/// using this function, instead they compare the values rather than +/// their addresses. +/// /// # Examples /// /// ``` From c709a10434ecfdaa9ec8b726a405fb0d027edd07 Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Sat, 23 Mar 2019 23:02:16 -0400 Subject: [PATCH 18/46] Refactor tuple comparison tests --- src/libcore/tests/tuple.rs | 44 +++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/libcore/tests/tuple.rs b/src/libcore/tests/tuple.rs index a4c171eb4243b..c7ed1612dd5ea 100644 --- a/src/libcore/tests/tuple.rs +++ b/src/libcore/tests/tuple.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering::{Equal, Less, Greater}; +use std::f64::NAN; #[test] fn test_clone() { @@ -8,18 +9,18 @@ fn test_clone() { } #[test] -fn test_tuple_cmp() { +fn test_partial_eq() { let (small, big) = ((1, 2, 3), (3, 2, 1)); - - let nan = 0.0f64/0.0; - - // PartialEq assert_eq!(small, small); assert_eq!(big, big); - assert!(small != big); - assert!(big != small); + assert_ne!(small, big); + assert_ne!(big, small); +} + +#[test] +fn test_partial_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); - // PartialOrd assert!(small < big); assert!(!(small < small)); assert!(!(big < small)); @@ -33,18 +34,21 @@ fn test_tuple_cmp() { assert!(big >= small); assert!(big >= big); - assert!(!((1.0f64, 2.0f64) < (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) <= (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) > (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) >= (nan, 3.0))); - assert!(((1.0f64, 2.0f64) < (2.0, nan))); - assert!(!((2.0f64, 2.0f64) < (2.0, nan))); - - // Ord - assert!(small.cmp(&small) == Equal); - assert!(big.cmp(&big) == Equal); - assert!(small.cmp(&big) == Less); - assert!(big.cmp(&small) == Greater); + assert!(!((1.0f64, 2.0f64) < (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) <= (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) > (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) >= (NAN, 3.0))); + assert!(((1.0f64, 2.0f64) < (2.0, NAN))); + assert!(!((2.0f64, 2.0f64) < (2.0, NAN))); +} + +#[test] +fn test_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); + assert_eq!(small.cmp(&small), Equal); + assert_eq!(big.cmp(&big), Equal); + assert_eq!(small.cmp(&big), Less); + assert_eq!(big.cmp(&small), Greater); } #[test] From e91689cd97657ae2db5e716a5178ea4f5779570a Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Mon, 25 Mar 2019 16:38:12 -0400 Subject: [PATCH 19/46] Rework documentation to be about fat pointers --- src/libcore/ptr.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c9f1a87ba9ff2..d795bf0ad8303 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2483,9 +2483,13 @@ impl Eq for *mut T {} /// by their address rather than comparing the values they point to /// (which is what the `PartialEq for &T` implementation does). /// -/// Smart pointer types, such as `Box`, `Rc`, and `Arc` do not compare -/// using this function, instead they compare the values rather than -/// their addresses. +/// A reference in Rust is sometimes stored different than a raw +/// memory address. These cases are called fat pointers. A reference +/// to a slice must store both the address of the slice and the length +/// of the slice. A reference to an object satisfying a trait must +/// also point to the vtable for the trait's methods. Since this +/// function compares pointers in totality, careful consideration to +/// the type of the variable must be made. /// /// # Examples /// @@ -2499,9 +2503,9 @@ impl Eq for *mut T {} /// let other_five_ref = &other_five; /// /// assert!(five_ref == same_five_ref); -/// assert!(five_ref == other_five_ref); -/// /// assert!(ptr::eq(five_ref, same_five_ref)); +/// +/// assert!(five_ref == other_five_ref); /// assert!(!ptr::eq(five_ref, other_five_ref)); /// ``` #[stable(feature = "ptr_eq", since = "1.17.0")] From fbfc8082b425b8812a725a7d3097b124acde10ea Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Mon, 25 Mar 2019 17:19:47 -0400 Subject: [PATCH 20/46] Rework documentation into examples --- src/libcore/ptr.rs | 54 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d795bf0ad8303..55af518b886b0 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2483,14 +2483,6 @@ impl Eq for *mut T {} /// by their address rather than comparing the values they point to /// (which is what the `PartialEq for &T` implementation does). /// -/// A reference in Rust is sometimes stored different than a raw -/// memory address. These cases are called fat pointers. A reference -/// to a slice must store both the address of the slice and the length -/// of the slice. A reference to an object satisfying a trait must -/// also point to the vtable for the trait's methods. Since this -/// function compares pointers in totality, careful consideration to -/// the type of the variable must be made. -/// /// # Examples /// /// ``` @@ -2508,6 +2500,52 @@ impl Eq for *mut T {} /// assert!(five_ref == other_five_ref); /// assert!(!ptr::eq(five_ref, other_five_ref)); /// ``` +/// +/// Slices are also compared by their length (fat pointers): +/// +/// ``` +/// let a = [1, 2, 3]; +/// assert!(std::ptr::eq(&a[..3], &a[..3])); +/// assert!(!std::ptr::eq(&a[..2], &a[..3])); +/// assert!(!std::ptr::eq(&a[0..2], &a[1..3])); +/// ``` +/// +/// Traits are also compared by their implementation: +/// +/// ``` +/// #[repr(transparent)] +/// struct Wrapper { member: i32 } +/// +/// trait Trait {} +/// impl Trait for Wrapper {} +/// impl Trait for i32 {} +/// +/// fn main() { +/// let wrapper = Wrapper { member: 10 }; +/// +/// // Pointers are equal address +/// assert!(std::ptr::eq( +/// &wrapper as *const Wrapper as *const u8, +/// &wrapper.member as *const i32 as *const u8 +/// )); +/// +/// // Objects have equal addresses, but `Trait` has different implementations +/// assert!(!std::ptr::eq( +/// &wrapper as &Trait, +/// &wrapper.member as &Trait, +/// )); +/// assert!(!std::ptr::eq( +/// &wrapper as &Trait as *const Trait, +/// &wrapper.member as &Trait as *const Trait, +/// )); +/// +/// // Converting the reference to a `*const u8` compares by address +/// assert!(std::ptr::eq( +/// &wrapper as &Trait as *const Trait as *const u8, +/// &wrapper.member as &Trait as *const Trait as *const u8, +/// )); +/// } +/// ``` #[stable(feature = "ptr_eq", since = "1.17.0")] #[inline] pub fn eq(a: *const T, b: *const T) -> bool { From 7e156c2066bd9bf3a3d076ed32dd0d7b217c5857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 11 Jun 2018 08:48:15 +0200 Subject: [PATCH 21/46] Make some lints incremental --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/hir/map/mod.rs | 8 +-- src/librustc/lint/context.rs | 80 ++++++++++++++++++++++++++---- src/librustc/lint/mod.rs | 1 + src/librustc/ty/query/mod.rs | 2 + src/librustc/ty/query/plumbing.rs | 1 + src/librustc_interface/passes.rs | 2 +- src/librustc_lint/lib.rs | 53 +++++++++++++++++--- src/librustc_privacy/lib.rs | 3 +- 9 files changed, 127 insertions(+), 24 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 43e865ad08941..792b0ce714634 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -474,6 +474,7 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [] UnsafetyCheckResult(DefId), [] UnsafeDeriveOnReprPacked(DefId), + [] LintMod(DefId), [] CheckModAttrs(DefId), [] CheckModLoops(DefId), [] CheckModUnstableApiUsage(DefId), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d810a9310c55f..56c3c71339f14 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -580,17 +580,17 @@ impl<'hir> Map<'hir> { &self.forest.krate.attrs } - pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, NodeId) - { + pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, HirId) { let node_id = self.as_local_node_id(module).unwrap(); + let hir_id = self.node_to_hir_id(node_id); self.read(node_id); match self.find_entry(node_id).unwrap().node { Node::Item(&Item { span, node: ItemKind::Mod(ref m), .. - }) => (m, span, node_id), - Node::Crate => (&self.forest.krate.module, self.forest.krate.span, node_id), + }) => (m, span, hir_id), + Node::Crate => (&self.forest.krate.module, self.forest.krate.span, hir_id), _ => panic!("not a module") } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 94f1d9c271007..6df3409d080e7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -27,6 +27,7 @@ use crate::rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use crate::session::{config, early_error, Session}; use crate::ty::{self, TyCtxt, Ty}; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; +use crate::ty::query::Providers; use crate::util::nodemap::FxHashMap; use crate::util::common::time; @@ -36,7 +37,7 @@ use syntax::edition; use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}}; use errors::DiagnosticBuilder; use crate::hir; -use crate::hir::def_id::LOCAL_CRATE; +use crate::hir::def_id::{DefId, LOCAL_CRATE}; use crate::hir::intravisit as hir_visit; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; @@ -55,6 +56,7 @@ pub struct LintStore { pre_expansion_passes: Option>, early_passes: Option>, late_passes: Option>, + late_module_passes: Option>, /// Lints indexed by name. by_name: FxHashMap, @@ -150,6 +152,7 @@ impl LintStore { pre_expansion_passes: Some(vec![]), early_passes: Some(vec![]), late_passes: Some(vec![]), + late_module_passes: Some(vec![]), by_name: Default::default(), future_incompatible: Default::default(), lint_groups: Default::default(), @@ -199,9 +202,14 @@ impl LintStore { pub fn register_late_pass(&mut self, sess: Option<&Session>, from_plugin: bool, + per_module: bool, pass: LateLintPassObject) { self.push_pass(sess, from_plugin, &pass); - self.late_passes.as_mut().unwrap().push(pass); + if per_module { + self.late_module_passes.as_mut().unwrap().push(pass); + } else { + self.late_passes.as_mut().unwrap().push(pass); + } } // Helper method for register_early/late_pass @@ -508,6 +516,7 @@ pub struct LateContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Side-tables for the body we are in. + // FIXME: Make this lazy to avoid running the TypeckTables query? pub tables: &'a ty::TypeckTables<'tcx>, /// Parameter environment for the item we are in. @@ -523,6 +532,9 @@ pub struct LateContext<'a, 'tcx: 'a> { /// Generic type parameters in scope for the item we are in. pub generics: Option<&'tcx hir::Generics>, + + /// We are only looking at one module + only_module: bool, } /// Context for lint checking of the AST, after expansion, before lowering to @@ -803,6 +815,12 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { pub fn current_lint_root(&self) -> hir::HirId { self.last_node_with_lint_attrs } + + fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) { + run_lints!(self, check_mod, m, s, n); + hir_visit::walk_mod(self, m, n); + run_lints!(self, check_mod_post, m, s, n); + } } impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> { @@ -934,9 +952,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) { - run_lints!(self, check_mod, m, s, n); - hir_visit::walk_mod(self, m, n); - run_lints!(self, check_mod_post, m, s, n); + if !self.only_module { + self.process_mod(m, s, n); + } } fn visit_local(&mut self, l: &'tcx hir::Local) { @@ -1203,11 +1221,43 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } } +pub fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); -/// Performs lint checking on a crate. -/// -/// Consumes the `lint_store` field of the `Session`. -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let store = &tcx.sess.lint_store; + let passes = store.borrow_mut().late_module_passes.take(); + + let mut cx = LateContext { + tcx, + tables: &ty::TypeckTables::empty(None), + param_env: ty::ParamEnv::empty(), + access_levels, + lint_sess: LintSession { + lints: store.borrow(), + passes, + }, + last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(), + generics: None, + only_module: true, + }; + + let (module, span, hir_id) = tcx.hir().get_module(module_def_id); + cx.process_mod(module, span, hir_id); + + // Put the lint store levels and passes back in the session. + let passes = cx.lint_sess.passes; + drop(cx.lint_sess.lints); + store.borrow_mut().late_module_passes = passes; +} + +pub(crate) fn provide(providers: &mut Providers<'_>) { + *providers = Providers { + lint_mod, + ..*providers + }; +} + +fn lint_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir().krate(); @@ -1225,6 +1275,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { }, last_node_with_lint_attrs: hir::CRATE_HIR_ID, generics: None, + only_module: false, }; // Visit the whole crate. @@ -1244,6 +1295,17 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.sess.lint_store.borrow_mut().late_passes = passes; } +/// Performs lint checking on a crate. +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + // Run per-module lints + for &module in tcx.hir().krate().modules.keys() { + tcx.ensure().lint_mod(tcx.hir().local_def_id(module)); + } + + // Run whole crate non-incremental lints + lint_crate(tcx); +} + struct EarlyLintPassObjects<'a> { lints: &'a mut [EarlyLintPassObject], } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index ae44210bcfffc..cf1c5d50000fa 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -824,6 +824,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> { pub fn provide(providers: &mut Providers<'_>) { providers.lint_levels = lint_levels; + context::provide(providers); } /// Returns whether `span` originates in a foreign crate's external macro. diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a2d7815920e0b..86299b29f48c9 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -245,6 +245,8 @@ rustc_query_append! { [define_queries!][ <'tcx> }, Other { + [] fn lint_mod: LintMod(DefId) -> (), + /// Checks the attributes in the module [] fn check_mod_attrs: CheckModAttrs(DefId) -> (), diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index e82e09c299765..099fd352680c2 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1272,6 +1272,7 @@ pub fn force_from_dep_node<'tcx>( DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); } DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); } DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); } + DepKind::LintMod => { force!(lint_mod, def_id!()); } DepKind::CheckModAttrs => { force!(check_mod_attrs, def_id!()); } DepKind::CheckModLoops => { force!(check_mod_loops, def_id!()); } DepKind::CheckModUnstableApiUsage => { force!(check_mod_unstable_api_usage, def_id!()); } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index c199829b298c0..b6daadb1b456f 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -328,7 +328,7 @@ pub fn register_plugins<'a>( ls.register_early_pass(Some(sess), true, false, pass); } for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); + ls.register_late_pass(Some(sess), true, false, pass); } for (name, (to, deprecated_name)) in lint_groups { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 73a32f6d2003a..a5e5b570a4e63 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -125,37 +125,74 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new()); } - late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ + // FIXME: Make a separate lint type which do not require typeck tables + + late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedModuleLateLintPass, [ HardwiredLints: HardwiredLints, WhileTrue: WhileTrue, ImproperCTypes: ImproperCTypes, VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, - UnusedAttributes: UnusedAttributes, PathStatements: PathStatements, UnusedResults: UnusedResults, - NonSnakeCase: NonSnakeCase, NonUpperCaseGlobals: NonUpperCaseGlobals, NonShorthandFieldPatterns: NonShorthandFieldPatterns, UnusedAllocation: UnusedAllocation, + + // Depends on types used in type definitions MissingCopyImplementations: MissingCopyImplementations, - UnstableFeatures: UnstableFeatures, - InvalidNoMangleItems: InvalidNoMangleItems, + PluginAsLibrary: PluginAsLibrary, + + // Depends on referenced function signatures in expressions MutableTransmutes: MutableTransmutes, + + // Depends on types of fields, checks if they implement Drop UnionsWithDropFields: UnionsWithDropFields, - UnreachablePub: UnreachablePub, - UnnameableTestItems: UnnameableTestItems::new(), + TypeAliasBounds: TypeAliasBounds, + + // May Depend on constants elsewhere UnusedBrokenConst: UnusedBrokenConst, + TrivialConstraints: TrivialConstraints, TypeLimits: TypeLimits::new(), + ]], ['tcx]); + + store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new()); + + late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ + + // Uses attr::is_used which is untracked, can't be an incremental module pass. + // Doesn't require type tables. Make a separate combined pass for that? + UnusedAttributes: UnusedAttributes, + + + // Checks crate attributes. Find out how that would work. + NonSnakeCase: NonSnakeCase, + + + // Needs to look at crate attributes. Make sure that works + UnstableFeatures: UnstableFeatures, + + // Depends on access levels + InvalidNoMangleItems: InvalidNoMangleItems, + + // Depends on access levels + UnreachablePub: UnreachablePub, + + UnnameableTestItems: UnnameableTestItems::new(), + + // Tracks attributes of parents MissingDoc: MissingDoc::new(), + + // Depends on access levels MissingDebugImplementations: MissingDebugImplementations::new(), + ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, ]], ['tcx]); - store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new()); + store.register_late_pass(sess, false, false, box BuiltinCombinedLateLintPass::new()); add_lint_group!(sess, "nonstandard_style", diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index bbd03e82a3730..b532e5c94d531 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1790,8 +1790,7 @@ fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { current_item: hir::DUMMY_HIR_ID, empty_tables: &empty_tables, }; - let (module, span, node_id) = tcx.hir().get_module(module_def_id); - let hir_id = tcx.hir().node_to_hir_id(node_id); + let (module, span, hir_id) = tcx.hir().get_module(module_def_id); intravisit::walk_mod(&mut visitor, module, hir_id); // Check privacy of explicitly written types and traits as well as From 32bc4a50c08e1710b2328de654bc0b281a1a5a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 3 Mar 2019 18:47:54 +0100 Subject: [PATCH 22/46] Make more lints incremental --- src/librustc/hir/map/mod.rs | 3 ++- src/librustc/lint/context.rs | 6 +++++ src/librustc_lint/lib.rs | 33 ++++++++++++-------------- src/librustc_lint/nonstandard_style.rs | 8 +++++-- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 56c3c71339f14..2ffb4959951b8 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1013,7 +1013,7 @@ impl<'hir> Map<'hir> { /// corresponding to the Node ID pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] { self.read(id); // reveals attributes on the node - let attrs = match self.find(id) { + let attrs = match self.find_entry(id).map(|entry| entry.node) { Some(Node::Local(l)) => Some(&l.attrs[..]), Some(Node::Item(i)) => Some(&i.attrs[..]), Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), @@ -1027,6 +1027,7 @@ impl<'hir> Map<'hir> { // Unit/tuple structs/variants take the attributes straight from // the struct/variant definition. Some(Node::Ctor(..)) => return self.attrs(self.get_parent(id)), + Some(Node::Crate) => Some(&self.forest.krate.attrs[..]), _ => None }; attrs.unwrap_or(&[]) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6df3409d080e7..953d0116aa2ba 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -39,6 +39,7 @@ use errors::DiagnosticBuilder; use crate::hir; use crate::hir::def_id::{DefId, LOCAL_CRATE}; use crate::hir::intravisit as hir_visit; +use crate::hir::intravisit::Visitor; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; @@ -1244,6 +1245,11 @@ pub fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { let (module, span, hir_id) = tcx.hir().get_module(module_def_id); cx.process_mod(module, span, hir_id); + // Visit the crate attributes + if hir_id == hir::CRATE_HIR_ID { + walk_list!(cx, visit_attribute, cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID)); + } + // Put the lint store levels and passes back in the session. let passes = cx.lint_sess.passes; drop(cx.lint_sess.lints); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index a5e5b570a4e63..2caaa0159921b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -125,8 +125,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new()); } - // FIXME: Make a separate lint type which do not require typeck tables - late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedModuleLateLintPass, [ HardwiredLints: HardwiredLints, WhileTrue: WhileTrue, @@ -134,7 +132,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, + + // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, + NonUpperCaseGlobals: NonUpperCaseGlobals, NonShorthandFieldPatterns: NonShorthandFieldPatterns, UnusedAllocation: UnusedAllocation, @@ -157,39 +158,35 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { TrivialConstraints: TrivialConstraints, TypeLimits: TypeLimits::new(), + + NonSnakeCase: NonSnakeCase, + InvalidNoMangleItems: InvalidNoMangleItems, + + // Depends on access levels + UnreachablePub: UnreachablePub, + + ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, ]], ['tcx]); store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new()); late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ - // Uses attr::is_used which is untracked, can't be an incremental module pass. - // Doesn't require type tables. Make a separate combined pass for that? UnusedAttributes: UnusedAttributes, - - // Checks crate attributes. Find out how that would work. - NonSnakeCase: NonSnakeCase, - - - // Needs to look at crate attributes. Make sure that works + // Needs to run after UnusedAttributes as it marks all `feature` attributes as used. UnstableFeatures: UnstableFeatures, - // Depends on access levels - InvalidNoMangleItems: InvalidNoMangleItems, - - // Depends on access levels - UnreachablePub: UnreachablePub, - + // Tracks state across modules UnnameableTestItems: UnnameableTestItems::new(), // Tracks attributes of parents MissingDoc: MissingDoc::new(), // Depends on access levels + // FIXME: Turn the computation of types which implement Debug into a query + // and change this to a module lint pass MissingDebugImplementations: MissingDebugImplementations::new(), - - ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, ]], ['tcx]); store.register_late_pass(sess, false, false, box BuiltinCombinedLateLintPass::new()); diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index fa18dd1eb8ddb..7a164dbcdf12d 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -267,11 +267,15 @@ impl LintPass for NonSnakeCase { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { - fn check_crate(&mut self, cx: &LateContext<'_, '_>, cr: &hir::Crate) { + fn check_mod(&mut self, cx: &LateContext<'_, '_>, _: &'tcx hir::Mod, _: Span, id: hir::HirId) { + if id != hir::CRATE_HIR_ID { + return; + } + let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - attr::find_by_name(&cr.attrs, "crate_name") + attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), "crate_name") .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { From 00d8fa3fdb3392916b45fc8e86ed0346fce4ffee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 13 Mar 2019 02:55:37 +0100 Subject: [PATCH 23/46] Update tests --- src/test/ui/lint/lint-impl-fn.stderr | 16 ++++++------- src/test/ui/lint/suggestions.stderr | 36 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/test/ui/lint/lint-impl-fn.stderr b/src/test/ui/lint/lint-impl-fn.stderr index 2c9a264287c96..56f85111d428f 100644 --- a/src/test/ui/lint/lint-impl-fn.stderr +++ b/src/test/ui/lint/lint-impl-fn.stderr @@ -11,25 +11,25 @@ LL | #[deny(while_true)] | ^^^^^^^^^^ error: denote infinite loops with `loop { ... }` - --> $DIR/lint-impl-fn.rs:18:25 + --> $DIR/lint-impl-fn.rs:27:5 | -LL | fn foo(&self) { while true {} } - | ^^^^^^^^^^ help: use `loop` +LL | while true {} + | ^^^^^^^^^^ help: use `loop` | note: lint level defined here - --> $DIR/lint-impl-fn.rs:13:8 + --> $DIR/lint-impl-fn.rs:25:8 | LL | #[deny(while_true)] | ^^^^^^^^^^ error: denote infinite loops with `loop { ... }` - --> $DIR/lint-impl-fn.rs:27:5 + --> $DIR/lint-impl-fn.rs:18:25 | -LL | while true {} - | ^^^^^^^^^^ help: use `loop` +LL | fn foo(&self) { while true {} } + | ^^^^^^^^^^ help: use `loop` | note: lint level defined here - --> $DIR/lint-impl-fn.rs:25:8 + --> $DIR/lint-impl-fn.rs:13:8 | LL | #[deny(while_true)] | ^^^^^^^^^^ diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index c28814aeee8f9..5aaa9947f998a 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -65,6 +65,24 @@ LL | pub fn defiant(_t: T) {} | = note: #[warn(no_mangle_generic_items)] on by default +warning: denote infinite loops with `loop { ... }` + --> $DIR/suggestions.rs:46:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: #[warn(while_true)] on by default + +warning: the `warp_factor:` in this pattern is redundant + --> $DIR/suggestions.rs:61:23 + | +LL | Equinox { warp_factor: warp_factor } => {} + | ------------^^^^^^^^^^^^ + | | + | help: remove this + | + = note: #[warn(non_shorthand_field_patterns)] on by default + error: const items should never be #[no_mangle] --> $DIR/suggestions.rs:22:18 | @@ -97,23 +115,5 @@ LL | #[no_mangle] pub(crate) fn crossfield() {} | | | help: remove this attribute -warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:46:5 - | -LL | while true { - | ^^^^^^^^^^ help: use `loop` - | - = note: #[warn(while_true)] on by default - -warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:61:23 - | -LL | Equinox { warp_factor: warp_factor } => {} - | ------------^^^^^^^^^^^^ - | | - | help: remove this - | - = note: #[warn(non_shorthand_field_patterns)] on by default - error: aborting due to 3 previous errors From 9e663032a1d8697ddde7e0e51e632e8565772265 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 25 Mar 2019 15:27:49 -0700 Subject: [PATCH 24/46] [CI] record docker image info for reuse This writes an extra `dist/image-$image.txt` which contains the S3 URL of the cached image and the `sha256` digest of the docker entry point. This will be uploaded with the rest of the deployed artifacts in the Travis `after_success` script. --- src/ci/docker/run.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index ef151750af9bf..98a765e1cec95 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -12,6 +12,9 @@ ci_dir="`dirname $docker_dir`" src_dir="`dirname $ci_dir`" root_dir="`dirname $src_dir`" +objdir=$root_dir/obj +dist=$objdir/build/dist + source "$ci_dir/shared.sh" travis_fold start build_docker @@ -77,6 +80,11 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then else echo "Looks like docker image is the same as before, not uploading" fi + # Record the container image for reuse, e.g. by rustup.rs builds + info="$dist/image-$image.txt" + mkdir -p "$dist" + echo "$url" >"$info" + echo "$digest" >>"$info" fi elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then if [ -n "$TRAVIS_OS_NAME" ]; then @@ -99,8 +107,6 @@ fi travis_fold end build_docker travis_time_finish -objdir=$root_dir/obj - mkdir -p $HOME/.cargo mkdir -p $objdir/tmp mkdir -p $objdir/cores From 91b74237605a6715213ae32b5781431ff6e40019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 25 Mar 2019 16:11:21 -0700 Subject: [PATCH 25/46] Reject integer suffix when tuple indexing --- src/libsyntax/parse/parser.rs | 95 +++++++++++++++------------ src/test/ui/parser/issue-59418.rs | 9 +++ src/test/ui/parser/issue-59418.stderr | 8 +++ 3 files changed, 69 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/parser/issue-59418.rs create mode 100644 src/test/ui/parser/issue-59418.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d7a2170342d7f..efeace4f05ecc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3196,51 +3196,60 @@ impl<'a> Parser<'a> { // expr.f if self.eat(&token::Dot) { match self.token { - token::Ident(..) => { - e = self.parse_dot_suffix(e, lo)?; - } - token::Literal(token::Integer(name), _) => { - let span = self.span; - self.bump(); - let field = ExprKind::Field(e, Ident::new(name, span)); - e = self.mk_expr(lo.to(span), field, ThinVec::new()); - } - token::Literal(token::Float(n), _suf) => { - self.bump(); - let fstr = n.as_str(); - let mut err = self.diagnostic() - .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); - err.span_label(self.prev_span, "unexpected token"); - if fstr.chars().all(|x| "0123456789.".contains(x)) { - let float = match fstr.parse::().ok() { - Some(f) => f, - None => continue, - }; - let sugg = pprust::to_string(|s| { - use crate::print::pprust::PrintState; - s.popen()?; - s.print_expr(&e)?; - s.s.word( ".")?; - s.print_usize(float.trunc() as usize)?; - s.pclose()?; - s.s.word(".")?; - s.s.word(fstr.splitn(2, ".").last().unwrap().to_string()) - }); - err.span_suggestion( - lo.to(self.prev_span), - "try parenthesizing the first index", - sugg, - Applicability::MachineApplicable - ); + token::Ident(..) => { + e = self.parse_dot_suffix(e, lo)?; } - return Err(err); + token::Literal(token::Integer(name), suffix) => { + let span = self.span; + self.bump(); + let field = ExprKind::Field(e, Ident::new(name, span)); + e = self.mk_expr(lo.to(span), field, ThinVec::new()); - } - _ => { - // FIXME Could factor this out into non_fatal_unexpected or something. - let actual = self.this_token_to_string(); - self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - } + if let Some(suffix) = suffix { + let mut err = self.diagnostic().struct_span_err( + span, + "tuple index with a suffix is invalid", + ); + err.span_label(span, format!("invalid suffix `{}`", suffix)); + err.emit(); + } + } + token::Literal(token::Float(n), _suf) => { + self.bump(); + let fstr = n.as_str(); + let mut err = self.diagnostic() + .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, "unexpected token"); + if fstr.chars().all(|x| "0123456789.".contains(x)) { + let float = match fstr.parse::().ok() { + Some(f) => f, + None => continue, + }; + let sugg = pprust::to_string(|s| { + use crate::print::pprust::PrintState; + s.popen()?; + s.print_expr(&e)?; + s.s.word( ".")?; + s.print_usize(float.trunc() as usize)?; + s.pclose()?; + s.s.word(".")?; + s.s.word(fstr.splitn(2, ".").last().unwrap().to_string()) + }); + err.span_suggestion( + lo.to(self.prev_span), + "try parenthesizing the first index", + sugg, + Applicability::MachineApplicable + ); + } + return Err(err); + + } + _ => { + // FIXME Could factor this out into non_fatal_unexpected or something. + let actual = self.this_token_to_string(); + self.span_err(self.span, &format!("unexpected token: `{}`", actual)); + } } continue; } diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs new file mode 100644 index 0000000000000..33ad11bb0b011 --- /dev/null +++ b/src/test/ui/parser/issue-59418.rs @@ -0,0 +1,9 @@ +struct X(i32,i32,i32); + +fn main() { + let a = X(1, 2, 3); + let b = a.1suffix; + //~^ ERROR tuple index with a suffix is invalid + println!("{}", b); +} + diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr new file mode 100644 index 0000000000000..c06b950f60119 --- /dev/null +++ b/src/test/ui/parser/issue-59418.stderr @@ -0,0 +1,8 @@ +error: tuple index with a suffix is invalid + --> $DIR/issue-59418.rs:5:15 + | +LL | let b = a.1suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: aborting due to previous error + From 630d5a489552e671bf9dc7c0e72c77b0a1ad353c Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Tue, 26 Mar 2019 13:06:15 +0900 Subject: [PATCH 26/46] renames EvalContext to InterpretCx. --- src/librustc_mir/const_eval.rs | 28 +++++++++++----------- src/librustc_mir/interpret/cast.rs | 4 ++-- src/librustc_mir/interpret/eval_context.rs | 12 +++++----- src/librustc_mir/interpret/intrinsics.rs | 4 ++-- src/librustc_mir/interpret/machine.rs | 24 +++++++++---------- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/operand.rs | 4 ++-- src/librustc_mir/interpret/operator.rs | 6 ++--- src/librustc_mir/interpret/place.rs | 6 ++--- src/librustc_mir/interpret/step.rs | 6 ++--- src/librustc_mir/interpret/terminator.rs | 4 ++-- src/librustc_mir/interpret/traits.rs | 4 ++-- src/librustc_mir/interpret/validity.rs | 8 +++---- src/librustc_mir/interpret/visitor.rs | 24 +++++++++---------- src/librustc_mir/transform/const_prop.rs | 4 ++-- 15 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 8c774e0d54cce..211573ab49a1c 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -22,7 +22,7 @@ use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer, RawConst, ConstValue, - EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup, + EvalResult, EvalError, EvalErrorKind, GlobalId, InterpretCx, StackPopCleanup, Allocation, AllocId, MemoryKind, snapshot, RefTracking, }; @@ -47,7 +47,7 @@ pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> CompileTimeEvalContext<'a, 'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); - EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()) + InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new()) } pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( @@ -116,7 +116,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( // and try improving it down the road when more information is available let span = tcx.def_span(cid.instance.def_id()); let span = mir.map(|mir| mir.span).unwrap_or(span); - let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()); + let mut ecx = InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new()); let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env); (r, ecx) } @@ -292,7 +292,7 @@ impl interpret::AllocMap for FxHashMap { } type CompileTimeEvalContext<'a, 'mir, 'tcx> = - EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>; + InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>; impl interpret::MayLeak for ! { #[inline(always)] @@ -317,12 +317,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> const STATIC_KIND: Option = None; // no copying of statics allowed #[inline(always)] - fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { false // for now, we don't enforce validity } fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: Option>, @@ -362,7 +362,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } fn call_intrinsic( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, @@ -378,7 +378,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } fn ptr_op( - _ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, _bin_op: mir::BinOp, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, @@ -406,7 +406,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } fn box_alloc( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> EvalResult<'tcx> { Err( @@ -414,7 +414,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> ) } - fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { + fn before_terminator(ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { { let steps = &mut ecx.machine.steps_since_detector_enabled; @@ -440,7 +440,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> #[inline(always)] fn tag_new_allocation( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ptr: Pointer, _kind: MemoryKind, ) -> Pointer { @@ -449,7 +449,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> #[inline(always)] fn stack_push( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ) -> EvalResult<'tcx> { Ok(()) } @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> /// Called immediately before a stack frame gets popped. #[inline(always)] fn stack_pop( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, _extra: (), ) -> EvalResult<'tcx> { Ok(()) @@ -504,7 +504,7 @@ pub fn const_variant_index<'a, 'tcx>( } pub fn error_to_const_error<'a, 'mir, 'tcx>( - ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, + ecx: &InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, mut error: EvalError<'tcx> ) -> ConstEvalErr<'tcx> { error.print_backtrace(); diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 7543dd678d032..003c2182d0b45 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -9,9 +9,9 @@ use rustc::mir::interpret::{ use rustc::mir::CastKind; use rustc_apfloat::Float; -use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate}; +use super::{InterpretCx, Machine, PlaceTy, OpTy, ImmTy, Immediate}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::RawPtr(ty::TypeAndMut { ty, .. }) | diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e81d0a56b2b05..8b7e28c3de077 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -26,7 +26,7 @@ use super::{ Memory, Machine }; -pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { +pub struct InterpretCx<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { /// Stores the `Machine` instance. pub machine: M, @@ -141,7 +141,7 @@ impl<'tcx, Tag> LocalState<'tcx, Tag> { } impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout - for EvalContext<'a, 'mir, 'tcx, M> + for InterpretCx<'a, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { @@ -149,7 +149,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout } } -impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx, M> +impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpretCx<'a, 'mir, 'tcx, M> where M: Machine<'a, 'mir, 'tcx> { #[inline] @@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx, } impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf - for EvalContext<'a, 'mir, 'tcx, M> + for InterpretCx<'a, 'mir, 'tcx, M> { type Ty = Ty<'tcx>; type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; @@ -171,13 +171,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf } } -impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, machine: M, ) -> Self { - EvalContext { + InterpretCx { machine, tcx, param_env, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index e002c3fd511d6..99dd654df21e3 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -11,7 +11,7 @@ use rustc::mir::interpret::{ }; use super::{ - Machine, PlaceTy, OpTy, EvalContext, + Machine, PlaceTy, OpTy, InterpretCx, }; @@ -36,7 +36,7 @@ fn numeric_intrinsic<'tcx, Tag>( Ok(Scalar::from_uint(bits_out, size)) } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// Returns `true` if emulation happened. pub fn emulate_intrinsic( &mut self, diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 7fb4c47d92acb..09d403ab243d6 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -11,7 +11,7 @@ use rustc::ty::{self, query::TyCtxtAt}; use super::{ Allocation, AllocId, EvalResult, Scalar, AllocationExtra, - EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind, + InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind, }; /// Whether this kind of memory is allowed to leak @@ -95,11 +95,11 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { const STATIC_KIND: Option; /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool; + fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool; /// Called before a basic block terminator is executed. /// You can use this to detect endlessly running programs. - fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>; + fn before_terminator(ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>; /// Entry point to all function calls. /// @@ -112,7 +112,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them /// was used. fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], dest: Option>, @@ -122,7 +122,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Directly process an intrinsic without pushing a stack frame. /// If this returns successfully, the engine will take care of jumping to the next block. fn call_intrinsic( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], dest: PlaceTy<'tcx, Self::PointerTag>, @@ -156,7 +156,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// /// Returns a (value, overflowed) pair if the operation succeeded fn ptr_op( - ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Self::PointerTag>, right: ImmTy<'tcx, Self::PointerTag>, @@ -164,13 +164,13 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Heap allocations via the `box` keyword. fn box_alloc( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Self::PointerTag>, ) -> EvalResult<'tcx>; /// Adds the tag for a newly allocated pointer. fn tag_new_allocation( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, ) -> Pointer; @@ -180,7 +180,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// `mutability` can be `None` in case a raw ptr is being dereferenced. #[inline] fn tag_dereference( - _ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, place: MPlaceTy<'tcx, Self::PointerTag>, _mutability: Option, ) -> EvalResult<'tcx, Scalar> { @@ -190,7 +190,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Executes a retagging operation #[inline] fn retag( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, _kind: mir::RetagKind, _place: PlaceTy<'tcx, Self::PointerTag>, ) -> EvalResult<'tcx> { @@ -199,12 +199,12 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Called immediately before a new stack frame got pushed fn stack_push( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ) -> EvalResult<'tcx, Self::FrameExtra>; /// Called immediately after a stack frame gets popped fn stack_pop( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, extra: Self::FrameExtra, ) -> EvalResult<'tcx>; } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index d2ab3fcb7a30a..ea358389ddb76 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,7 +18,7 @@ mod visitor; pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::eval_context::{ - EvalContext, Frame, StackPopCleanup, LocalState, LocalValue, + InterpretCx, Frame, StackPopCleanup, LocalState, LocalValue, }; pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy}; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 70511075e87c9..15b6d5c914d20 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -13,7 +13,7 @@ use rustc::mir::interpret::{ sign_extend, truncate, }; use super::{ - EvalContext, Machine, + InterpretCx, Machine, MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind, }; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -267,7 +267,7 @@ pub(super) fn from_known_layout<'tcx>( } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for ScalarPair. /// Returns `None` if the layout does not permit loading this as a value. fn try_read_immediate_from_mplace( diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 944e393d296fc..ca93007788e03 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -5,10 +5,10 @@ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc::mir::interpret::{EvalResult, Scalar}; -use super::{EvalContext, PlaceTy, Immediate, Machine, ImmTy}; +use super::{InterpretCx, PlaceTy, Immediate, Machine, ImmTy}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. pub fn binop_with_overflow( @@ -37,7 +37,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { fn binary_char_op( &self, bin_op: mir::BinOp, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 755bbd96b02f9..70c3e9f5a58bc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -14,7 +14,7 @@ use rustc::ty::TypeFoldable; use super::{ GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic, - EvalContext, Machine, AllocMap, AllocationExtra, + InterpretCx, Machine, AllocMap, AllocationExtra, RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind }; @@ -305,7 +305,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { } // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 -impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M> +impl<'a, 'mir, 'tcx, Tag, M> InterpretCx<'a, 'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static, @@ -606,7 +606,7 @@ where // global table but not in its local memory: It calls back into tcx through // a query, triggering the CTFE machinery to actually turn this lazy reference // into a bunch of bytes. IOW, statics are evaluated with CTFE even when - // this EvalContext uses another Machine (e.g., in miri). This is what we + // this InterpretCx uses another Machine (e.g., in miri). This is what we // want! This way, computing statics works concistently between codegen // and miri: They use the same query to eventually obtain a `ty::Const` // and use that for further computation. diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 656c13c16d9ed..29a8547035e4a 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -1,4 +1,4 @@ -//! This module contains the `EvalContext` methods for executing a single step of the interpreter. +//! This module contains the `InterpretCx` methods for executing a single step of the interpreter. //! //! The main entry point is the `step` method. @@ -6,7 +6,7 @@ use rustc::mir; use rustc::ty::layout::LayoutOf; use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic}; -use super::{EvalContext, Machine}; +use super::{InterpretCx, Machine}; /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the /// same type as the result. @@ -35,7 +35,7 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool { } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { pub fn run(&mut self) -> EvalResult<'tcx> { while self.step()? {} Ok(()) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 83469d749870f..01965f53c157d 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,10 +7,10 @@ use rustc_target::spec::abi::Abi; use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar}; use super::{ - EvalContext, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup + InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup }; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { #[inline] pub fn goto_block(&mut self, target: Option) -> EvalResult<'tcx> { if let Some(target) = target { diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 1b0a9b17d3686..cce6c95a31240 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -3,9 +3,9 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic}; -use super::{EvalContext, Machine, MemoryKind}; +use super::{InterpretCx, Machine, MemoryKind}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 252e8bac2a3f8..3323ec387bfd5 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -11,7 +11,7 @@ use rustc::mir::interpret::{ }; use super::{ - OpTy, Machine, EvalContext, ValueVisitor, MPlaceTy, + OpTy, Machine, InterpretCx, ValueVisitor, MPlaceTy, }; macro_rules! validation_failure { @@ -153,7 +153,7 @@ struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a path: Vec, ref_tracking: Option<&'rt mut RefTracking>>, const_mode: bool, - ecx: &'rt EvalContext<'a, 'mir, 'tcx, M>, + ecx: &'rt InterpretCx<'a, 'mir, 'tcx, M>, } impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> { @@ -224,7 +224,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> type V = OpTy<'tcx, M::PointerTag>; #[inline(always)] - fn ecx(&self) -> &EvalContext<'a, 'mir, 'tcx, M> { + fn ecx(&self) -> &InterpretCx<'a, 'mir, 'tcx, M> { &self.ecx } @@ -587,7 +587,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// This function checks the data at `op`. `op` is assumed to cover valid memory if it /// is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index e2abf2ffc849c..90d4fff421837 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ use rustc::mir::interpret::{ }; use super::{ - Machine, EvalContext, MPlaceTy, OpTy, + Machine, InterpretCx, MPlaceTy, OpTy, }; // A thing that we can project into, and that has a layout. @@ -22,7 +22,7 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy /// Makes this into an `OpTy`. fn to_op( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Creates this from an `MPlaceTy`. @@ -31,14 +31,14 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy /// Projects to the given enum variant. fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, variant: VariantIdx, ) -> EvalResult<'tcx, Self>; /// Projects to the n-th field. fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, field: u64, ) -> EvalResult<'tcx, Self>; } @@ -56,7 +56,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn to_op( self, - _ecx: &EvalContext<'a, 'mir, 'tcx, M>, + _ecx: &InterpretCx<'a, 'mir, 'tcx, M>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self) } @@ -69,7 +69,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, variant: VariantIdx, ) -> EvalResult<'tcx, Self> { ecx.operand_downcast(self, variant) @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, field: u64, ) -> EvalResult<'tcx, Self> { ecx.operand_field(self, field) @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn to_op( self, - _ecx: &EvalContext<'a, 'mir, 'tcx, M>, + _ecx: &InterpretCx<'a, 'mir, 'tcx, M>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } @@ -108,7 +108,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, variant: VariantIdx, ) -> EvalResult<'tcx, Self> { ecx.mplace_downcast(self, variant) @@ -117,7 +117,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'a, 'mir, 'tcx, M>, field: u64, ) -> EvalResult<'tcx, Self> { ecx.mplace_field(self, field) @@ -130,9 +130,9 @@ macro_rules! make_value_visitor { pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized { type V: Value<'a, 'mir, 'tcx, M>; - /// The visitor must have an `EvalContext` in it. + /// The visitor must have an `InterpretCx` in it. fn ecx(&$($mutability)? self) - -> &$($mutability)? EvalContext<'a, 'mir, 'tcx, M>; + -> &$($mutability)? InterpretCx<'a, 'mir, 'tcx, M>; // Recursive actions, ready to be overloaded. /// Visits the given value, dispatching as appropriate to more specialized visitors. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 33672a2b7745c..dd84aa5d5530a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -18,7 +18,7 @@ use rustc::ty::layout::{ HasTyCtxt, TargetDataLayout, HasDataLayout, }; -use crate::interpret::{EvalContext, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind}; +use crate::interpret::{InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind}; use crate::const_eval::{ CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, }; @@ -70,7 +70,7 @@ type Const<'tcx> = (OpTy<'tcx>, Span); /// Finds optimization opportunities on the MIR. struct ConstPropagator<'a, 'mir, 'tcx:'a+'mir> { - ecx: EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, + ecx: InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, mir: &'mir Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, From 6ad77b09388224c38b65f5c54125b669b886c7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 25 Mar 2019 21:38:23 -0700 Subject: [PATCH 27/46] review comments --- src/libsyntax/parse/parser.rs | 2 +- src/test/ui/parser/issue-59418.rs | 6 +++++- src/test/ui/parser/issue-59418.stderr | 10 ++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index efeace4f05ecc..38647bec982cc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3208,7 +3208,7 @@ impl<'a> Parser<'a> { if let Some(suffix) = suffix { let mut err = self.diagnostic().struct_span_err( span, - "tuple index with a suffix is invalid", + "suffixes on tuple indexes are invalid", ); err.span_label(span, format!("invalid suffix `{}`", suffix)); err.emit(); diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs index 33ad11bb0b011..cab37e0d80920 100644 --- a/src/test/ui/parser/issue-59418.rs +++ b/src/test/ui/parser/issue-59418.rs @@ -3,7 +3,11 @@ struct X(i32,i32,i32); fn main() { let a = X(1, 2, 3); let b = a.1suffix; - //~^ ERROR tuple index with a suffix is invalid + //~^ ERROR suffixes on tuple indexes are invalid println!("{}", b); + let c = (1, 2, 3); + let d = c.1suffix; + //~^ ERROR suffixes on tuple indexes are invalid + println!("{}", d); } diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr index c06b950f60119..e50780de4f96b 100644 --- a/src/test/ui/parser/issue-59418.stderr +++ b/src/test/ui/parser/issue-59418.stderr @@ -1,8 +1,14 @@ -error: tuple index with a suffix is invalid +error: suffixes on tuple indexes are invalid --> $DIR/issue-59418.rs:5:15 | LL | let b = a.1suffix; | ^^^^^^^ invalid suffix `suffix` -error: aborting due to previous error +error: suffixes on tuple indexes are invalid + --> $DIR/issue-59418.rs:9:15 + | +LL | let d = c.1suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: aborting due to 2 previous errors From 0e0383abc6d1f7d1edc456f66a2e3f4082e9a0a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Mar 2019 22:45:02 +0100 Subject: [PATCH 28/46] adjust MaybeUninit API to discussions uninitialized -> uninit into_initialized -> assume_init read_initialized -> read set -> write --- src/liballoc/collections/btree/node.rs | 10 +-- src/libcore/fmt/float.rs | 16 ++-- src/libcore/fmt/num.rs | 4 +- src/libcore/macros.rs | 4 +- src/libcore/mem.rs | 110 ++++++++++++++++--------- src/libcore/ptr.rs | 14 ++-- src/libcore/slice/rotate.rs | 2 +- 7 files changed, 97 insertions(+), 63 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 66d619b1298b4..581c66c7086a5 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -109,7 +109,7 @@ impl LeafNode { keys: uninitialized_array![_; CAPACITY], vals: uninitialized_array![_; CAPACITY], parent: ptr::null(), - parent_idx: MaybeUninit::uninitialized(), + parent_idx: MaybeUninit::uninit(), len: 0 } } @@ -129,7 +129,7 @@ unsafe impl Sync for NodeHeader<(), ()> {} // ever take a pointer past the first key. static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader { parent: ptr::null(), - parent_idx: MaybeUninit::uninitialized(), + parent_idx: MaybeUninit::uninit(), len: 0, keys_start: [], }; @@ -261,7 +261,7 @@ impl Root { -> NodeRef, K, V, marker::Internal> { debug_assert!(!self.is_shared_root()); let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0].set(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); + new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); self.node = BoxedNode::from_internal(new_node); self.height += 1; @@ -737,7 +737,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { unsafe { ptr::write(self.keys_mut().get_unchecked_mut(idx), key); ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - self.as_internal_mut().edges.get_unchecked_mut(idx + 1).set(edge.node); + self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); (*self.as_leaf_mut()).len += 1; @@ -1080,7 +1080,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let mut child = self.descend(); unsafe { (*child.as_leaf_mut()).parent = ptr; - (*child.as_leaf_mut()).parent_idx.set(idx); + (*child.as_leaf_mut()).parent_idx.write(idx); } } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index edeb65afd67b2..5f4c6f7b0a3f0 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -10,8 +10,8 @@ fn float_to_decimal_common_exact(fmt: &mut Formatter, num: &T, where T: flt2dec::DecodableFloat { unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 + let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninit(); // FIXME(#53491): Technically, this is calling `get_mut` on an uninitialized // `MaybeUninit` (here and elsewhere in this file). Revisit this once // we decided whether that is valid or not. @@ -32,8 +32,8 @@ fn float_to_decimal_common_shortest(fmt: &mut Formatter, num: &T, { unsafe { // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); - let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); + let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninit(); // FIXME(#53491) let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, precision, false, buf.get_mut(), @@ -71,8 +71,8 @@ fn float_to_exponential_common_exact(fmt: &mut Formatter, num: &T, where T: flt2dec::DecodableFloat { unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 + let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninit(); // FIXME(#53491) let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, precision, @@ -91,8 +91,8 @@ fn float_to_exponential_common_shortest(fmt: &mut Formatter, { unsafe { // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); - let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); + let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninit(); // FIXME(#53491) let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, (0, 0), upper, diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index b9fa364037108..e96dbcaa14416 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -60,7 +60,7 @@ trait GenericRadix { for byte in buf.iter_mut().rev() { let n = x % base; // Get the current place value. x = x / base; // Deaccumulate the number. - byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. + byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -72,7 +72,7 @@ trait GenericRadix { for byte in buf.iter_mut().rev() { let n = zero - (x % base); // Get the current place value. x = x / base; // Deaccumulate the number. - byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. + byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index d77936c7ddd91..ad8ce1af1f6a1 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -626,12 +626,12 @@ macro_rules! todo { #[macro_export] #[unstable(feature = "maybe_uninit_array", issue = "53491")] macro_rules! uninitialized_array { - // This `into_initialized` is safe because an array of `MaybeUninit` does not + // This `assume_init` is safe because an array of `MaybeUninit` does not // require initialization. // FIXME(#49147): Could be replaced by an array initializer, once those can // be any const expression. ($t:ty; $size:expr) => (unsafe { - MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized() + MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init() }); } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 3d2fcdc979377..66bcf1f7d0101 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -622,7 +622,7 @@ pub unsafe fn zeroed() -> T { /// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html /// [`Drop`]: ../ops/trait.Drop.html #[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")] +#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { intrinsics::panic_if_uninhabited::(); @@ -1058,7 +1058,7 @@ impl DerefMut for ManuallyDrop { /// /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! /// // The equivalent code with `MaybeUninit<&i32>`: -/// let x: &i32 = unsafe { MaybeUninit::zeroed().into_initialized() }; // undefined behavior! +/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! /// ``` /// /// This is exploited by the compiler for various optimizations, such as eliding @@ -1073,7 +1073,7 @@ impl DerefMut for ManuallyDrop { /// /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! /// // The equivalent code with `MaybeUninit`: -/// let b: bool = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior! +/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! /// ``` /// /// Moreover, uninitialized memory is special in that the compiler knows that @@ -1087,7 +1087,7 @@ impl DerefMut for ManuallyDrop { /// /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! /// // The equivalent code with `MaybeUninit`: -/// let x: i32 = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior! +/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! /// ``` /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) @@ -1102,12 +1102,12 @@ impl DerefMut for ManuallyDrop { /// /// // Create an explicitly uninitialized reference. The compiler knows that data inside /// // a `MaybeUninit` may be invalid, and hence this is not UB: -/// let mut x = MaybeUninit::<&i32>::uninitialized(); +/// let mut x = MaybeUninit::<&i32>::uninit(); /// // Set it to a valid value. -/// x.set(&0); +/// x.write(&0); /// // Extract the initialized data -- this is only allowed *after* properly /// // initializing `x`! -/// let x = unsafe { x.into_initialized() }; +/// let x = unsafe { x.assume_init() }; /// ``` /// /// The compiler then knows to not make any incorrect assumptions or optimizations on this code. @@ -1148,10 +1148,19 @@ impl MaybeUninit { /// It is your responsibility to make sure `T` gets dropped if it got initialized. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub const fn uninitialized() -> MaybeUninit { + pub const fn uninit() -> MaybeUninit { MaybeUninit { uninit: () } } + /// Deprecated before stabilization. + #[unstable(feature = "maybe_uninit", issue = "53491")] + #[inline(always)] + // FIXME: still used by stdsimd + // #[rustc_deprecated(since = "1.35.0", reason = "use `uninit` instead")] + pub const fn uninitialized() -> MaybeUninit { + Self::uninit() + } + /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, @@ -1171,7 +1180,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<(u8, bool)>::zeroed(); - /// let x = unsafe { x.into_initialized() }; + /// let x = unsafe { x.assume_init() }; /// assert_eq!(x, (0, false)); /// ``` /// @@ -1185,14 +1194,14 @@ impl MaybeUninit { /// enum NotZero { One = 1, Two = 2 }; /// /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); - /// let x = unsafe { x.into_initialized() }; + /// let x = unsafe { x.assume_init() }; /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. /// // This is undefined behavior. /// ``` #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline] pub fn zeroed() -> MaybeUninit { - let mut u = MaybeUninit::::uninitialized(); + let mut u = MaybeUninit::::uninit(); unsafe { u.as_mut_ptr().write_bytes(0u8, 1); } @@ -1205,13 +1214,21 @@ impl MaybeUninit { /// reference to the (now safely initialized) contents of `self`. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub fn set(&mut self, val: T) -> &mut T { + pub fn write(&mut self, val: T) -> &mut T { unsafe { self.value = ManuallyDrop::new(val); self.get_mut() } } + /// Deprecated before stabilization. + #[unstable(feature = "maybe_uninit", issue = "53491")] + #[inline(always)] + #[rustc_deprecated(since = "1.35.0", reason = "use `write` instead")] + pub fn set(&mut self, val: T) -> &mut T { + self.write(val) + } + /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. /// @@ -1223,7 +1240,7 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::>::uninitialized(); + /// let mut x = MaybeUninit::>::uninit(); /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; @@ -1236,7 +1253,7 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let x = MaybeUninit::>::uninitialized(); + /// let x = MaybeUninit::>::uninit(); /// let x_vec = unsafe { &*x.as_ptr() }; /// // We have created a reference to an uninitialized vector! This is undefined behavior. /// ``` @@ -1260,7 +1277,7 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::>::uninitialized(); + /// let mut x = MaybeUninit::>::uninit(); /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } /// // Create a reference into the `MaybeUninit>`. /// // This is okay because we initialized it. @@ -1275,7 +1292,7 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::>::uninitialized(); + /// let mut x = MaybeUninit::>::uninit(); /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; /// // We have created a reference to an uninitialized vector! This is undefined behavior. /// ``` @@ -1306,9 +1323,9 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::::uninitialized(); + /// let mut x = MaybeUninit::::uninit(); /// unsafe { x.as_mut_ptr().write(true); } - /// let x_init = unsafe { x.into_initialized() }; + /// let x_init = unsafe { x.assume_init() }; /// assert_eq!(x_init, true); /// ``` /// @@ -1318,21 +1335,30 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let x = MaybeUninit::>::uninitialized(); - /// let x_init = unsafe { x.into_initialized() }; + /// let x = MaybeUninit::>::uninit(); + /// let x_init = unsafe { x.assume_init() }; /// // `x` had not been initialized yet, so this last line caused undefined behavior. /// ``` #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub unsafe fn into_initialized(self) -> T { + pub unsafe fn assume_init(self) -> T { intrinsics::panic_if_uninhabited::(); ManuallyDrop::into_inner(self.value) } + /// Deprecated before stabilization. + #[unstable(feature = "maybe_uninit", issue = "53491")] + #[inline(always)] + // FIXME: still used by stdsimd + // #[rustc_deprecated(since = "1.35.0", reason = "use `assume_init` instead")] + pub unsafe fn into_initialized(self) -> T { + self.assume_init() + } + /// Reads the value from the `MaybeUninit` container. The resulting `T` is subject /// to the usual drop handling. /// - /// Whenever possible, it is preferrable to use [`into_initialized`] instead, which + /// Whenever possible, it is preferrable to use [`assume_init`] instead, which /// prevents duplicating the content of the `MaybeUninit`. /// /// # Safety @@ -1342,11 +1368,11 @@ impl MaybeUninit { /// behavior. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read_initialized` multiple times, or first - /// calling `read_initialized` and then [`into_initialized`]), it is your responsibility + /// multiple copies of the data (by calling `read` multiple times, or first + /// calling `read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// - /// [`into_initialized`]: #method.into_initialized + /// [`assume_init`]: #method.assume_init /// /// # Examples /// @@ -1356,18 +1382,18 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::::uninitialized(); - /// x.set(13); - /// let x1 = unsafe { x.read_initialized() }; + /// let mut x = MaybeUninit::::uninit(); + /// x.write(13); + /// let x1 = unsafe { x.read() }; /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read_initialized() }; + /// let x2 = unsafe { x.read() }; /// assert_eq!(x1, x2); /// - /// let mut x = MaybeUninit::>>::uninitialized(); - /// x.set(None); - /// let x1 = unsafe { x.read_initialized() }; + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(None); + /// let x1 = unsafe { x.read() }; /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read_initialized() }; + /// let x2 = unsafe { x.read() }; /// assert_eq!(x1, x2); /// ``` /// @@ -1377,20 +1403,28 @@ impl MaybeUninit { /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// - /// let mut x = MaybeUninit::>>::uninitialized(); - /// x.set(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read_initialized() }; - /// let x2 = unsafe { x.read_initialized() }; + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(Some(vec![0,1,2])); + /// let x1 = unsafe { x.read() }; + /// let x2 = unsafe { x.read() }; /// // We now created two copies of the same vector, leading to a double-free when /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub unsafe fn read_initialized(&self) -> T { + pub unsafe fn read(&self) -> T { intrinsics::panic_if_uninhabited::(); self.as_ptr().read() } + /// Deprecated before stabilization. + #[unstable(feature = "maybe_uninit", issue = "53491")] + #[inline(always)] + #[rustc_deprecated(since = "1.35.0", reason = "use `read` instead")] + pub unsafe fn read_initialized(&self) -> T { + self.read() + } + /// Gets a reference to the contained value. /// /// # Safety diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a9a029d606d6f..1cb21aa6be0a2 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -296,7 +296,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } pub unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with. // We do not have to worry about drops: `MaybeUninit` does nothing when dropped. - let mut tmp = MaybeUninit::::uninitialized(); + let mut tmp = MaybeUninit::::uninit(); // Perform the swap copy_nonoverlapping(x, tmp.as_mut_ptr(), 1); @@ -388,7 +388,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t = mem::MaybeUninit::::uninitialized(); + let mut t = mem::MaybeUninit::::uninit(); let t = t.as_mut_ptr() as *mut u8; let x = x.add(i); let y = y.add(i); @@ -403,7 +403,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { if i < len { // Swap any remaining bytes - let mut t = mem::MaybeUninit::::uninitialized(); + let mut t = mem::MaybeUninit::::uninit(); let rem = len - i; let t = t.as_mut_ptr() as *mut u8; @@ -571,9 +571,9 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { - let mut tmp = MaybeUninit::::uninitialized(); + let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - tmp.into_initialized() + tmp.assume_init() } /// Reads the value from `src` without moving it. This leaves the @@ -638,11 +638,11 @@ pub unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { - let mut tmp = MaybeUninit::::uninitialized(); + let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); - tmp.into_initialized() + tmp.assume_init() } /// Overwrites a memory location with the given value without reading or diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 9b35b51349a02..8f10c3576a787 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -72,7 +72,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { } } - let mut rawarray = MaybeUninit::>::uninitialized(); + let mut rawarray = MaybeUninit::>::uninit(); let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T; let dim = mid.sub(left).add(right); From 853ae8d931c3fe4cd303edf7d80271c1930b9654 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Mar 2019 09:46:11 +0100 Subject: [PATCH 29/46] fix some uses I missed --- src/libstd/sys/sgx/ext/arch.rs | 8 ++++---- src/libstd/sys/sgx/rwlock.rs | 2 +- src/libstd/sys/windows/mutex.rs | 2 +- src/test/codegen/box-maybe-uninit.rs | 5 ++++- src/test/run-pass/panic-uninitialized-zeroed.rs | 6 +++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs index 53fb371947a99..5056e388112ce 100644 --- a/src/libstd/sys/sgx/ext/arch.rs +++ b/src/libstd/sys/sgx/ext/arch.rs @@ -28,7 +28,7 @@ const ENCLU_EGETKEY: u32 = 1; #[unstable(feature = "sgx_platform", issue = "56975")] pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> { unsafe { - let mut out = MaybeUninit::uninitialized(); + let mut out = MaybeUninit::uninit(); let error; asm!( @@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> ); match error { - 0 => Ok(out.into_initialized()), + 0 => Ok(out.assume_init()), err => Err(err), } } @@ -58,7 +58,7 @@ pub fn ereport( reportdata: &Align128<[u8; 64]>, ) -> Align512<[u8; 432]> { unsafe { - let mut report = MaybeUninit::uninitialized(); + let mut report = MaybeUninit::uninit(); asm!( "enclu" @@ -69,6 +69,6 @@ pub fn ereport( "{rdx}"(report.as_mut_ptr()) ); - report.into_initialized() + report.assume_init() } } diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 7b113267865b6..7e2d13b9e2476 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -280,7 +280,7 @@ mod tests { let mut init = MaybeUninit::::zeroed(); rwlock_new(&mut init); assert_eq!( - mem::transmute::<_, [u8; 128]>(init.into_initialized()).as_slice(), + mem::transmute::<_, [u8; 128]>(init.assume_init()).as_slice(), RWLOCK_INIT ) }; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 1aa910f05c9c3..37cbdcefcedcc 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -154,7 +154,7 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninitialized()) } + ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } } pub unsafe fn init(&mut self) { diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs index ad1d259a0da21..0dd67bb95ccaa 100644 --- a/src/test/codegen/box-maybe-uninit.rs +++ b/src/test/codegen/box-maybe-uninit.rs @@ -12,5 +12,8 @@ pub fn box_uninitialized() -> Box> { // CHECK-NOT: alloca // CHECK-NOT: memcpy // CHECK-NOT: memset - Box::new(MaybeUninit::uninitialized()) + Box::new(MaybeUninit::uninit()) } + +// FIXME: add a test for a bigger box. Currently broken, see +// https://github.com/rust-lang/rust/issues/58201. diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs index 31c0d2994d415..3f6e489bb8327 100644 --- a/src/test/run-pass/panic-uninitialized-zeroed.rs +++ b/src/test/run-pass/panic-uninitialized-zeroed.rs @@ -36,7 +36,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type !" })), @@ -63,7 +63,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Foo" })), @@ -90,7 +90,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Bar" })), From 4093bec80d39f94d69754d3a30cb14d9d4954424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 26 Mar 2019 17:04:00 +0100 Subject: [PATCH 30/46] Exclude UnusedBrokenConst from module lints --- src/librustc_lint/builtin.rs | 1 + src/librustc_lint/lib.rs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 304e6eb712e3c..492ac1bf14dcc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1360,6 +1360,7 @@ fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { promoted: None }; // trigger the query once for all constants since that will already report the errors + // FIXME: Use ensure here let _ = cx.tcx.const_eval(param_env.and(cid)); } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 2caaa0159921b..4c624a267af9b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -153,9 +153,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { TypeAliasBounds: TypeAliasBounds, - // May Depend on constants elsewhere - UnusedBrokenConst: UnusedBrokenConst, - TrivialConstraints: TrivialConstraints, TypeLimits: TypeLimits::new(), @@ -171,6 +168,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new()); late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ + // FIXME: Look into regression when this is used as a module lint + // May Depend on constants elsewhere + UnusedBrokenConst: UnusedBrokenConst, + // Uses attr::is_used which is untracked, can't be an incremental module pass. UnusedAttributes: UnusedAttributes, From c7ddb83980a89118937c8f9c264183f5abf73339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 10:18:18 -0700 Subject: [PATCH 31/46] Use `expect_no_suffix` for error --- src/libsyntax/parse/parser.rs | 9 +-------- src/test/ui/parser/issue-59418.rs | 5 ++--- src/test/ui/parser/issue-59418.stderr | 8 ++++---- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 38647bec982cc..8dacb27063793 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3205,14 +3205,7 @@ impl<'a> Parser<'a> { let field = ExprKind::Field(e, Ident::new(name, span)); e = self.mk_expr(lo.to(span), field, ThinVec::new()); - if let Some(suffix) = suffix { - let mut err = self.diagnostic().struct_span_err( - span, - "suffixes on tuple indexes are invalid", - ); - err.span_label(span, format!("invalid suffix `{}`", suffix)); - err.emit(); - } + self.expect_no_suffix(span, "tuple index", suffix); } token::Literal(token::Float(n), _suf) => { self.bump(); diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs index cab37e0d80920..d1afa6af320f0 100644 --- a/src/test/ui/parser/issue-59418.rs +++ b/src/test/ui/parser/issue-59418.rs @@ -3,11 +3,10 @@ struct X(i32,i32,i32); fn main() { let a = X(1, 2, 3); let b = a.1suffix; - //~^ ERROR suffixes on tuple indexes are invalid + //~^ ERROR tuple index with a suffix is invalid println!("{}", b); let c = (1, 2, 3); let d = c.1suffix; - //~^ ERROR suffixes on tuple indexes are invalid + //~^ ERROR tuple index with a suffix is invalid println!("{}", d); } - diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr index e50780de4f96b..4ca4bd73abc1c 100644 --- a/src/test/ui/parser/issue-59418.stderr +++ b/src/test/ui/parser/issue-59418.stderr @@ -1,14 +1,14 @@ -error: suffixes on tuple indexes are invalid +error: tuple index with a suffix is invalid --> $DIR/issue-59418.rs:5:15 | LL | let b = a.1suffix; - | ^^^^^^^ invalid suffix `suffix` + | ^^^^^^^ tuple index with a suffix is invalid -error: suffixes on tuple indexes are invalid +error: tuple index with a suffix is invalid --> $DIR/issue-59418.rs:9:15 | LL | let d = c.1suffix; - | ^^^^^^^ invalid suffix `suffix` + | ^^^^^^^ tuple index with a suffix is invalid error: aborting due to 2 previous errors From 1bb3694b1a6368f456c2e62cf234a332a21df2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 12:09:13 -0700 Subject: [PATCH 32/46] Reword invalid suffixe errors --- src/libsyntax/parse/parser.rs | 13 ++++----- src/test/ui/parser/bad-lit-suffixes.rs | 16 +++++------ src/test/ui/parser/bad-lit-suffixes.stderr | 32 +++++++++++----------- src/test/ui/parser/issue-59418.rs | 4 +-- src/test/ui/parser/issue-59418.stderr | 8 +++--- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8dacb27063793..bb3dc8edfb001 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1119,9 +1119,8 @@ impl<'a> Parser<'a> { if text.is_empty() { self.span_bug(sp, "found empty literal suffix in Some") } - let msg = format!("{} with a suffix is invalid", kind); - self.struct_span_err(sp, &msg) - .span_label(sp, msg) + self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + .span_label(sp, format!("invalid suffix `{}`", text)) .emit(); } } @@ -2150,7 +2149,7 @@ impl<'a> Parser<'a> { if suffix_illegal { let sp = self.span; - self.expect_no_suffix(sp, lit.literal_name(), suf) + self.expect_no_suffix(sp, &format!("a {}", lit.literal_name()), suf) } result.unwrap() @@ -3205,7 +3204,7 @@ impl<'a> Parser<'a> { let field = ExprKind::Field(e, Ident::new(name, span)); e = self.mk_expr(lo.to(span), field, ThinVec::new()); - self.expect_no_suffix(span, "tuple index", suffix); + self.expect_no_suffix(span, "a tuple index", suffix); } token::Literal(token::Float(n), _suf) => { self.bump(); @@ -7791,7 +7790,7 @@ impl<'a> Parser<'a> { match self.token { token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { let sp = self.span; - self.expect_no_suffix(sp, "ABI spec", suf); + self.expect_no_suffix(sp, "an ABI spec", suf); self.bump(); match abi::lookup(&s.as_str()) { Some(abi) => Ok(Some(abi)), @@ -8612,7 +8611,7 @@ impl<'a> Parser<'a> { match self.parse_optional_str() { Some((s, style, suf)) => { let sp = self.prev_span; - self.expect_no_suffix(sp, "string literal", suf); + self.expect_no_suffix(sp, "a string literal", suf); Ok((s, style)) } _ => { diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs index 391e7f0acf979..75bed3088587c 100644 --- a/src/test/ui/parser/bad-lit-suffixes.rs +++ b/src/test/ui/parser/bad-lit-suffixes.rs @@ -2,20 +2,20 @@ extern - "C"suffix //~ ERROR ABI spec with a suffix is invalid + "C"suffix //~ ERROR suffixes on an ABI spec are invalid fn foo() {} extern - "C"suffix //~ ERROR ABI spec with a suffix is invalid + "C"suffix //~ ERROR suffixes on an ABI spec are invalid {} fn main() { - ""suffix; //~ ERROR string literal with a suffix is invalid - b""suffix; //~ ERROR byte string literal with a suffix is invalid - r#""#suffix; //~ ERROR string literal with a suffix is invalid - br#""#suffix; //~ ERROR byte string literal with a suffix is invalid - 'a'suffix; //~ ERROR char literal with a suffix is invalid - b'a'suffix; //~ ERROR byte literal with a suffix is invalid + ""suffix; //~ ERROR suffixes on a string literal are invalid + b""suffix; //~ ERROR suffixes on a byte string literal are invalid + r#""#suffix; //~ ERROR suffixes on a string literal are invalid + br#""#suffix; //~ ERROR suffixes on a byte string literal are invalid + 'a'suffix; //~ ERROR suffixes on a char literal are invalid + b'a'suffix; //~ ERROR suffixes on a byte literal are invalid 1234u1024; //~ ERROR invalid width `1024` for integer literal 1234i1024; //~ ERROR invalid width `1024` for integer literal diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr index 3d4d7b4a78b43..de194f4820de0 100644 --- a/src/test/ui/parser/bad-lit-suffixes.stderr +++ b/src/test/ui/parser/bad-lit-suffixes.stderr @@ -1,50 +1,50 @@ -error: ABI spec with a suffix is invalid +error: suffixes on an ABI spec are invalid --> $DIR/bad-lit-suffixes.rs:5:5 | LL | "C"suffix - | ^^^^^^^^^ ABI spec with a suffix is invalid + | ^^^^^^^^^ invalid suffix `suffix` -error: ABI spec with a suffix is invalid +error: suffixes on an ABI spec are invalid --> $DIR/bad-lit-suffixes.rs:9:5 | LL | "C"suffix - | ^^^^^^^^^ ABI spec with a suffix is invalid + | ^^^^^^^^^ invalid suffix `suffix` -error: string literal with a suffix is invalid +error: suffixes on a string literal are invalid --> $DIR/bad-lit-suffixes.rs:13:5 | LL | ""suffix; - | ^^^^^^^^ string literal with a suffix is invalid + | ^^^^^^^^ invalid suffix `suffix` -error: byte string literal with a suffix is invalid +error: suffixes on a byte string literal are invalid --> $DIR/bad-lit-suffixes.rs:14:5 | LL | b""suffix; - | ^^^^^^^^^ byte string literal with a suffix is invalid + | ^^^^^^^^^ invalid suffix `suffix` -error: string literal with a suffix is invalid +error: suffixes on a string literal are invalid --> $DIR/bad-lit-suffixes.rs:15:5 | LL | r#""#suffix; - | ^^^^^^^^^^^ string literal with a suffix is invalid + | ^^^^^^^^^^^ invalid suffix `suffix` -error: byte string literal with a suffix is invalid +error: suffixes on a byte string literal are invalid --> $DIR/bad-lit-suffixes.rs:16:5 | LL | br#""#suffix; - | ^^^^^^^^^^^^ byte string literal with a suffix is invalid + | ^^^^^^^^^^^^ invalid suffix `suffix` -error: char literal with a suffix is invalid +error: suffixes on a char literal are invalid --> $DIR/bad-lit-suffixes.rs:17:5 | LL | 'a'suffix; - | ^^^^^^^^^ char literal with a suffix is invalid + | ^^^^^^^^^ invalid suffix `suffix` -error: byte literal with a suffix is invalid +error: suffixes on a byte literal are invalid --> $DIR/bad-lit-suffixes.rs:18:5 | LL | b'a'suffix; - | ^^^^^^^^^^ byte literal with a suffix is invalid + | ^^^^^^^^^^ invalid suffix `suffix` error: invalid width `1024` for integer literal --> $DIR/bad-lit-suffixes.rs:20:5 diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs index d1afa6af320f0..a37af2180bf1b 100644 --- a/src/test/ui/parser/issue-59418.rs +++ b/src/test/ui/parser/issue-59418.rs @@ -3,10 +3,10 @@ struct X(i32,i32,i32); fn main() { let a = X(1, 2, 3); let b = a.1suffix; - //~^ ERROR tuple index with a suffix is invalid + //~^ ERROR suffixes on a tuple index are invalid println!("{}", b); let c = (1, 2, 3); let d = c.1suffix; - //~^ ERROR tuple index with a suffix is invalid + //~^ ERROR suffixes on a tuple index are invalid println!("{}", d); } diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr index 4ca4bd73abc1c..ca7d4cfda7294 100644 --- a/src/test/ui/parser/issue-59418.stderr +++ b/src/test/ui/parser/issue-59418.stderr @@ -1,14 +1,14 @@ -error: tuple index with a suffix is invalid +error: suffixes on a tuple index are invalid --> $DIR/issue-59418.rs:5:15 | LL | let b = a.1suffix; - | ^^^^^^^ tuple index with a suffix is invalid + | ^^^^^^^ invalid suffix `suffix` -error: tuple index with a suffix is invalid +error: suffixes on a tuple index are invalid --> $DIR/issue-59418.rs:9:15 | LL | let d = c.1suffix; - | ^^^^^^^ tuple index with a suffix is invalid + | ^^^^^^^ invalid suffix `suffix` error: aborting due to 2 previous errors From 8d1cc72cf9fca507f4e14fad88f7269594305846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 Mar 2019 12:32:32 -0700 Subject: [PATCH 33/46] Add specific message for tuple struct invoked with suffixed numeric field name --- src/libsyntax/parse/parser.rs | 3 ++- src/test/ui/parser/issue-59418.rs | 6 ++++++ src/test/ui/parser/issue-59418.stderr | 14 +++++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bb3dc8edfb001..71dde91e65455 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2491,7 +2491,8 @@ impl<'a> Parser<'a> { } fn parse_field_name(&mut self) -> PResult<'a, Ident> { - if let token::Literal(token::Integer(name), None) = self.token { + if let token::Literal(token::Integer(name), suffix) = self.token { + self.expect_no_suffix(self.span, "a tuple index", suffix); self.bump(); Ok(Ident::new(name, self.prev_span)) } else { diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs index a37af2180bf1b..0fa191d4a7ef4 100644 --- a/src/test/ui/parser/issue-59418.rs +++ b/src/test/ui/parser/issue-59418.rs @@ -9,4 +9,10 @@ fn main() { let d = c.1suffix; //~^ ERROR suffixes on a tuple index are invalid println!("{}", d); + let s = X { 0suffix: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match s { + X { 0suffix: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } } diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr index ca7d4cfda7294..347051e9f921c 100644 --- a/src/test/ui/parser/issue-59418.stderr +++ b/src/test/ui/parser/issue-59418.stderr @@ -10,5 +10,17 @@ error: suffixes on a tuple index are invalid LL | let d = c.1suffix; | ^^^^^^^ invalid suffix `suffix` -error: aborting due to 2 previous errors +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:12:17 + | +LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:15:13 + | +LL | X { 0suffix: _, .. } => {} + | ^^^^^^^ invalid suffix `suffix` + +error: aborting due to 4 previous errors From 24a0caec832d774ede930597692b291286176802 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 27 Mar 2019 05:35:18 +0900 Subject: [PATCH 34/46] librustc_driver => 2018 --- src/librustc_driver/Cargo.toml | 5 +++-- src/librustc_driver/lib.rs | 31 ++----------------------------- src/librustc_driver/pretty.rs | 32 ++++++++++++++++++-------------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index a77e497af7b87..5432f80a1712c 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_driver" version = "0.0.0" +edition = "2018" [lib] name = "rustc_driver" @@ -13,14 +14,14 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } -rustc-rayon = "0.1.2" +rayon = { version = "0.1.2", package = "rustc-rayon" } scoped-tls = "1.0" rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } rustc_borrowck = { path = "../librustc_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } +errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_incremental = { path = "../librustc_incremental" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 25984616b878b..4b7cffaad5509 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -16,40 +16,13 @@ #![recursion_limit="256"] -extern crate arena; +#![deny(rust_2018_idioms)] + pub extern crate getopts; -extern crate graphviz; -extern crate env_logger; #[cfg(unix)] extern crate libc; -extern crate rustc_rayon as rayon; -extern crate rustc; -extern crate rustc_allocator; -extern crate rustc_target; -extern crate rustc_borrowck; -extern crate rustc_data_structures; -extern crate rustc_errors as errors; -extern crate rustc_passes; -extern crate rustc_lint; -extern crate rustc_plugin; -extern crate rustc_privacy; -extern crate rustc_incremental; -extern crate rustc_metadata; -extern crate rustc_mir; -extern crate rustc_resolve; -extern crate rustc_save_analysis; -extern crate rustc_traits; -extern crate rustc_codegen_utils; -extern crate rustc_typeck; -extern crate rustc_interface; -extern crate scoped_tls; -extern crate serialize; -extern crate smallvec; #[macro_use] extern crate log; -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; use pretty::{PpMode, UserIdentifiedItem}; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index ace5198deaf2e..5cefc35607db0 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -35,9 +35,9 @@ pub use self::UserIdentifiedItem::*; pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; -use abort_on_err; +use crate::abort_on_err; -use source_name; +use crate::source_name; #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { @@ -191,7 +191,7 @@ impl PpSourceMode { tcx: TyCtxt<'tcx, 'tcx, 'tcx>, f: F ) -> A - where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A + where F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A { match *self { PpmNormal => { @@ -296,7 +296,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { impl<'hir> pprust::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { if let Some(tcx) = self.tcx { pprust_hir::PpAnn::nested(tcx.hir(), state, nested) @@ -322,13 +322,13 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { } impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { - fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => Ok(()), @@ -373,7 +373,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { } impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { if let Some(ref tcx) = self.tcx { pprust_hir::PpAnn::nested(tcx.hir(), state, nested) @@ -381,13 +381,13 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { Ok(()) } } - fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Name(_) => Ok(()), pprust_hir::AnnNode::Item(item) => { @@ -434,7 +434,7 @@ impl<'a> PrinterSupport for HygieneAnnotation<'a> { } impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { - fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Ident(&ast::Ident { name, span }) => { s.s.space()?; @@ -476,7 +476,7 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { } impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { let old_tables = self.tables.get(); if let pprust_hir::Nested::Body(id) = nested { @@ -486,13 +486,13 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { self.tables.set(old_tables); Ok(()) } - fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(expr) => { s.s.space()?; @@ -580,7 +580,11 @@ impl UserIdentifiedItem { } } - fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId { + fn to_one_node_id(self, + user_option: &str, + sess: &Session, + map: &hir_map::Map<'_>) + -> ast::NodeId { let fail_because = |is_wrong_because| -> ast::NodeId { let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \ {}, which {}", From a365287e10c1bbdc2cb5ba33ce71b7a1d56d79f6 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 26 Mar 2019 23:45:40 +0100 Subject: [PATCH 35/46] fix: Make incremental artifact deletion more robust Should fix the intermittent errors reported in #57958 cc #48614 --- src/librustc_incremental/persist/fs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 7dcd5c94bf298..7f697b5448464 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -886,7 +886,10 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> { fn safe_remove_file(p: &Path) -> io::Result<()> { if p.exists() { let canonicalized = p.canonicalize()?; - std_fs::remove_file(canonicalized) + match std_fs::remove_file(canonicalized) { + Err(ref err) if err.kind() == io::ErrorKind::NotFound => Ok(()), + result => result, + } } else { Ok(()) } From 8733b2ab0c6bfe60df594e41ee9b1ce1f8caeaa0 Mon Sep 17 00:00:00 2001 From: Tim Diekmann <21277928+TimDiekmann@users.noreply.github.com> Date: Wed, 27 Mar 2019 00:09:12 +0100 Subject: [PATCH 36/46] Add `Default` to `std::alloc::System` --- src/libstd/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index a13da2901df94..4241f47b661d7 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -130,7 +130,7 @@ pub use alloc_crate::alloc::*; /// program opts in to using jemalloc as the global allocator, `System` will /// still allocate memory using `malloc` and `HeapAlloc`. #[stable(feature = "alloc_system_type", since = "1.28.0")] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] pub struct System; // The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. From 892f7c430dddbbd5a2e7c6146b19a762ed1e40e8 Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Wed, 27 Mar 2019 10:57:03 +0900 Subject: [PATCH 37/46] renames EvalContext to InterpretCx in docs and comments. --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc_mir/const_eval.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 9fb023156022a..0dd8316852780 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -344,7 +344,7 @@ impl<'tcx> AllocMap<'tcx> { } } - /// Returns `None` in case the `AllocId` is dangling. An `EvalContext` can still have a + /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is /// illegal and will likely ICE. /// This function exists to allow const eval to detect the difference between evaluation- diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 211573ab49a1c..6ab89f80ef528 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -34,7 +34,7 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000; /// Should be a power of two for performance reasons. const DETECTOR_SNAPSHOT_PERIOD: isize = 256; -/// The `EvalContext` is only meant to be used to do field and index projections into constants for +/// The `InterpretCx` is only meant to be used to do field and index projections into constants for /// `simd_shuffle` and const patterns in match arms. /// /// The function containing the `match` that is currently being analyzed may have generic bounds From 61b6c56f50af6ca2848f4bd623c8b2cd2b24cb77 Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Wed, 27 Mar 2019 01:46:24 -0400 Subject: [PATCH 38/46] Minor rewordings and add `dyn` keyword --- src/libcore/ptr.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 55af518b886b0..3121346988e82 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2523,26 +2523,26 @@ impl Eq for *mut T {} /// fn main() { /// let wrapper = Wrapper { member: 10 }; /// -/// // Pointers are equal address +/// // Pointers have equal addresses. /// assert!(std::ptr::eq( /// &wrapper as *const Wrapper as *const u8, /// &wrapper.member as *const i32 as *const u8 /// )); /// -/// // Objects have equal addresses, but `Trait` has different implementations +/// // Objects have equal addresses, but `Trait` has different implementations. /// assert!(!std::ptr::eq( -/// &wrapper as &Trait, -/// &wrapper.member as &Trait, +/// &wrapper as &dyn Trait, +/// &wrapper.member as &dyn Trait, /// )); /// assert!(!std::ptr::eq( -/// &wrapper as &Trait as *const Trait, -/// &wrapper.member as &Trait as *const Trait, +/// &wrapper as &dyn Trait as *const dyn Trait, +/// &wrapper.member as &dyn Trait as *const dyn Trait, /// )); /// -/// // Converting the reference to a `*const u8` compares by address +/// // Converting the reference to a `*const u8` compares by address. /// assert!(std::ptr::eq( -/// &wrapper as &Trait as *const Trait as *const u8, -/// &wrapper.member as &Trait as *const Trait as *const u8, +/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, +/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, /// )); /// } /// ``` From 14f3f6c71294fbbcb0a32286d942a4080156c6bc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 26 Mar 2019 19:07:13 +0100 Subject: [PATCH 39/46] librustc_interface => 2018 --- src/librustc_interface/Cargo.toml | 1 + src/librustc_interface/interface.rs | 10 +++++----- src/librustc_interface/lib.rs | 27 ++------------------------- src/librustc_interface/passes.rs | 12 +++++++----- src/librustc_interface/profile/mod.rs | 3 ++- src/librustc_interface/queries.rs | 5 +++-- src/librustc_interface/util.rs | 1 + 7 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 294e23dc6177c..356547db88675 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_interface" version = "0.0.0" +edition = "2018" [lib] name = "rustc_interface" diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index ec6b26afb8c50..bec868be505b5 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -1,4 +1,8 @@ -use queries::Queries; +use crate::queries::Queries; +use crate::util; +use crate::profile; +pub use crate::passes::BoxedResolver; + use rustc::lint; use rustc::session::config::{self, Input}; use rustc::session::{DiagnosticOutput, Session}; @@ -15,10 +19,6 @@ use std::result; use std::sync::{Arc, Mutex}; use syntax; use syntax::source_map::{FileLoader, SourceMap}; -use util; -use profile; - -pub use passes::BoxedResolver; pub type Result = result::Result; diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 6a931c249b5bf..3314681b6981a 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -6,37 +6,14 @@ #![feature(generators)] #![cfg_attr(unix, feature(libc))] +#![deny(rust_2018_idioms)] + #![allow(unused_imports)] #![recursion_limit="256"] #[cfg(unix)] extern crate libc; -#[macro_use] -extern crate log; -extern crate rustc; -extern crate rustc_codegen_utils; -extern crate rustc_allocator; -extern crate rustc_borrowck; -extern crate rustc_incremental; -extern crate rustc_traits; -#[macro_use] -extern crate rustc_data_structures; -extern crate rustc_errors; -extern crate rustc_lint; -extern crate rustc_metadata; -extern crate rustc_mir; -extern crate rustc_passes; -extern crate rustc_plugin; -extern crate rustc_privacy; -extern crate rustc_rayon as rayon; -extern crate rustc_resolve; -extern crate rustc_typeck; -extern crate smallvec; -extern crate serialize; -extern crate syntax; -extern crate syntax_pos; -extern crate syntax_ext; pub mod interface; mod passes; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index c199829b298c0..318857c3406e3 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -1,7 +1,8 @@ -use interface::{Compiler, Result}; -use util; -use proc_macro_decls; +use crate::interface::{Compiler, Result}; +use crate::util; +use crate::proc_macro_decls; +use log::{debug, info, warn, log_enabled}; use rustc::dep_graph::DepGraph; use rustc::hir; use rustc::hir::lowering::lower_crate; @@ -20,6 +21,7 @@ use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; @@ -758,7 +760,7 @@ pub fn prepare_outputs( Ok(outputs) } -pub fn default_provide(providers: &mut ty::query::Providers) { +pub fn default_provide(providers: &mut ty::query::Providers<'_>) { providers.analysis = analysis; proc_macro_decls::provide(providers); plugin::build::provide(providers); @@ -783,7 +785,7 @@ pub fn default_provide(providers: &mut ty::query::Providers) { lint::provide(providers); } -pub fn default_provide_extern(providers: &mut ty::query::Providers) { +pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) { cstore::provide_extern(providers); } diff --git a/src/librustc_interface/profile/mod.rs b/src/librustc_interface/profile/mod.rs index eb13a5668f927..d0c8dff207083 100644 --- a/src/librustc_interface/profile/mod.rs +++ b/src/librustc_interface/profile/mod.rs @@ -1,8 +1,9 @@ +use log::debug; +use rustc::dep_graph::DepNode; use rustc::session::Session; use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan}; use std::sync::mpsc::{Receiver}; use std::io::{Write}; -use rustc::dep_graph::{DepNode}; use std::time::{Duration, Instant}; pub mod trace; diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 57ced0464d9fa..570509ffb2b8c 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -1,5 +1,6 @@ -use interface::{Compiler, Result}; -use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; +use crate::interface::{Compiler, Result}; +use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; + use rustc_incremental::DepGraphFuture; use rustc_data_structures::sync::Lrc; use rustc::session::config::{Input, OutputFilenames, OutputType}; diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index b1ef4e315d98d..6e4f2bf24e32f 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -1,3 +1,4 @@ +use log::info; use rustc::session::config::{Input, OutputFilenames, ErrorOutputType}; use rustc::session::{self, config, early_error, filesearch, Session, DiagnosticOutput}; use rustc::session::CrateDisambiguator; From bf1068b1370f7bc3e17164cb4abd010b15073fa8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 27 Mar 2019 09:48:50 +0100 Subject: [PATCH 40/46] librustc_interface => 2018; rename rustc-rayon to rayon in Cargo.toml --- src/librustc_interface/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 356547db88675..ec934ee48212c 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] log = "0.4" -rustc-rayon = "0.1.1" +rayon = { version = "0.1.1", package = "rustc-rayon" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } scoped-tls = "1.0" syntax = { path = "../libsyntax" } From 7945eff0805d91d3c0ca10df872bcabdd88aa4b6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 26 Mar 2019 15:02:02 +0100 Subject: [PATCH 41/46] generalize diagnostic for x = y where type bool is expected. --- src/librustc_typeck/check/coercion.rs | 7 +- src/librustc_typeck/check/demand.rs | 83 ++++++++++++-------- src/librustc_typeck/check/mod.rs | 106 +++++++++++++------------- 3 files changed, 111 insertions(+), 85 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 6f3cd56c7bf5b..ac8b639edbfa3 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1233,7 +1233,12 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> augment_error(&mut db); } - db.emit(); + if expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some() { + // Error reported in `check_assign` so avoid emitting error again. + db.delay_as_bug(); + } else { + db.emit(); + } self.final_ty = Some(fcx.tcx.types.err); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index b1a249d821bec..60fa266f0bbe1 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -119,44 +119,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - // If the expected type is an enum (Issue #55250) with any variants whose - // sole field is of the found type, suggest such variants. (Issue #42764) - if let ty::Adt(expected_adt, substs) = expected.sty { - if expected_adt.is_enum() { - let mut compatible_variants = expected_adt.variants - .iter() - .filter(|variant| variant.fields.len() == 1) - .filter_map(|variant| { - let sole_field = &variant.fields[0]; - let sole_field_ty = sole_field.ty(self.tcx, substs); - if self.can_coerce(expr_ty, sole_field_ty) { - let variant_path = self.tcx.def_path_str(variant.def_id); - // FIXME #56861: DRYer prelude filtering - Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) - } else { - None - } - }).peekable(); - - if compatible_variants.peek().is_some() { - let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); - let suggestions = compatible_variants - .map(|v| format!("{}({})", v, expr_text)); - err.span_suggestions( - expr.span, - "try using a variant of the expected type", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } + if self.is_assign_to_bool(expr, expected) { + // Error reported in `check_assign` so avoid emitting error again. + err.delay_as_bug(); + return (expected, None) } + self.suggest_compatible_variants(&mut err, expr, expected, expr_ty); self.suggest_ref_or_into(&mut err, expr, expected, expr_ty); (expected, Some(err)) } + /// Returns whether the expected type is `bool` and the expression is `x = y`. + pub fn is_assign_to_bool(&self, expr: &hir::Expr, expected: Ty<'tcx>) -> bool { + if let hir::ExprKind::Assign(..) = expr.node { + return expected == self.tcx.types.bool; + } + false + } + + /// If the expected type is an enum (Issue #55250) with any variants whose + /// sole field is of the found type, suggest such variants. (Issue #42764) + fn suggest_compatible_variants( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + expected: Ty<'tcx>, + expr_ty: Ty<'tcx>, + ) { + if let ty::Adt(expected_adt, substs) = expected.sty { + if !expected_adt.is_enum() { + return; + } + + let mut compatible_variants = expected_adt.variants + .iter() + .filter(|variant| variant.fields.len() == 1) + .filter_map(|variant| { + let sole_field = &variant.fields[0]; + let sole_field_ty = sole_field.ty(self.tcx, substs); + if self.can_coerce(expr_ty, sole_field_ty) { + let variant_path = self.tcx.def_path_str(variant.def_id); + // FIXME #56861: DRYer prelude filtering + Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) + } else { + None + } + }).peekable(); + + if compatible_variants.peek().is_some() { + let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); + let suggestions = compatible_variants + .map(|v| format!("{}({})", v, expr_text)); + let msg = "try using a variant of the expected type"; + err.span_suggestions(expr.span, msg, suggestions, Applicability::MaybeIncorrect); + } + } + } + pub fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>) -> Vec { let mut methods = self.probe_for_return_type(span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b11bd9c2408bf..804fe9c5b5dc9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -246,9 +246,6 @@ pub enum Expectation<'tcx> { /// We know nothing about what type this expression should have. NoExpectation, - /// This expression is an `if` condition, it must resolve to `bool`. - ExpectIfCondition, - /// This expression should have the type given (or some subtype). ExpectHasType(Ty<'tcx>), @@ -328,7 +325,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { match self { NoExpectation => NoExpectation, - ExpectIfCondition => ExpectIfCondition, ExpectCastableToType(t) => { ExpectCastableToType(fcx.resolve_type_vars_if_possible(&t)) } @@ -344,7 +340,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn to_option(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { NoExpectation => None, - ExpectIfCondition => Some(fcx.tcx.types.bool), ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), @@ -358,7 +353,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { ExpectHasType(ty) => Some(ty), - ExpectIfCondition => Some(fcx.tcx.types.bool), NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } @@ -3150,25 +3144,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { - // Add help to type error if this is an `if` condition with an assignment. - if let (ExpectIfCondition, &ExprKind::Assign(ref lhs, ref rhs)) - = (expected, &expr.node) - { - let msg = "try comparing for equality"; - if let (Ok(left), Ok(right)) = ( - self.tcx.sess.source_map().span_to_snippet(lhs.span), - self.tcx.sess.source_map().span_to_snippet(rhs.span)) - { - err.span_suggestion( - expr.span, - msg, - format!("{} == {}", left, right), - Applicability::MaybeIncorrect); - } else { - err.help(msg); - } + if self.is_assign_to_bool(expr, expected_ty) { + // Error reported in `check_assign` so avoid emitting error again. + // FIXME(centril): Consider removing if/when `if` desugars to `match`. + err.delay_as_bug(); + } else { + err.emit(); } - err.emit(); } ty } @@ -3339,7 +3321,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_else_expr: Option<&'gcx hir::Expr>, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { - let cond_ty = self.check_expr_meets_expectation_or_error(cond_expr, ExpectIfCondition); + let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool); let cond_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -4424,34 +4406,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.types.never } ExprKind::Assign(ref lhs, ref rhs) => { - let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); - - match expected { - ExpectIfCondition => { - self.tcx.sess.delay_span_bug(lhs.span, "invalid lhs expression in if;\ - expected error elsehwere"); - } - _ => { - // Only check this if not in an `if` condition, as the - // mistyped comparison help is more appropriate. - if !lhs.is_place_expr() { - struct_span_err!(self.tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label(expr.span, "left-hand of expression not valid") - .emit(); - } - } - } - - self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); - - if lhs_ty.references_error() || rhs_ty.references_error() { - tcx.types.err - } else { - tcx.mk_unit() - } + self.check_assign(expr, expected, lhs, rhs) } ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => { self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), @@ -4752,6 +4707,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// Type check assignment expression `expr` of form `lhs = rhs`. + /// The expected type is `()` and is passsed to the function for the purposes of diagnostics. + fn check_assign( + &self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>, + lhs: &'gcx hir::Expr, + rhs: &'gcx hir::Expr, + ) -> Ty<'tcx> { + let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); + + let expected_ty = expected.coercion_target_type(self, expr.span); + if expected_ty == self.tcx.types.bool { + // The expected type is `bool` but this will result in `()` so we can reasonably + // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. + // The likely cause of this is `if foo = bar { .. }`. + let actual_ty = self.tcx.mk_unit(); + let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); + let msg = "try comparing for equality"; + let left = self.tcx.sess.source_map().span_to_snippet(lhs.span); + let right = self.tcx.sess.source_map().span_to_snippet(rhs.span); + if let (Ok(left), Ok(right)) = (left, right) { + let help = format!("{} == {}", left, right); + err.span_suggestion(expr.span, msg, help, Applicability::MaybeIncorrect); + } else { + err.help(msg); + } + err.emit(); + } else if !lhs.is_place_expr() { + struct_span_err!(self.tcx.sess, expr.span, E0070, + "invalid left-hand side expression") + .span_label(expr.span, "left-hand of expression not valid") + .emit(); + } + + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); + + if lhs_ty.references_error() || rhs_ty.references_error() { + self.tcx.types.err + } else { + self.tcx.mk_unit() + } + } + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. // The newly resolved definition is written into `type_dependent_defs`. fn finish_resolving_struct_path(&self, From 05d59feb64cac786da37072dc3a52348e99756f3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 26 Mar 2019 14:56:32 +0100 Subject: [PATCH 42/46] add test for assignment x = y where type bool is expected. --- .../type-check/assignment-expected-bool.rs | 29 ++++ .../assignment-expected-bool.stderr | 135 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 src/test/ui/type/type-check/assignment-expected-bool.rs create mode 100644 src/test/ui/type/type-check/assignment-expected-bool.stderr diff --git a/src/test/ui/type/type-check/assignment-expected-bool.rs b/src/test/ui/type/type-check/assignment-expected-bool.rs new file mode 100644 index 0000000000000..bb5ee46c9e17a --- /dev/null +++ b/src/test/ui/type/type-check/assignment-expected-bool.rs @@ -0,0 +1,29 @@ +// The purpose of this text is to ensure that we get good +// diagnostics when a `bool` is expected but that due to +// an assignment expression `x = y` the type is `()`. + +fn main() { + let _: bool = 0 = 0; //~ ERROR mismatched types [E0308] + + let _: bool = match 0 { + 0 => 0 = 0, //~ ERROR mismatched types [E0308] + _ => 0 = 0, //~ ERROR mismatched types [E0308] + }; + + let _: bool = match true { + true => 0 = 0, //~ ERROR mismatched types [E0308] + _ => (), + }; + + if 0 = 0 {} //~ ERROR mismatched types [E0308] + + let _: bool = if { 0 = 0 } { //~ ERROR mismatched types [E0308] + 0 = 0 //~ ERROR mismatched types [E0308] + } else { + 0 = 0 //~ ERROR mismatched types [E0308] + }; + + let _ = (0 = 0) //~ ERROR mismatched types [E0308] + && { 0 = 0 } //~ ERROR mismatched types [E0308] + || (0 = 0); //~ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr new file mode 100644 index 0000000000000..e929735734889 --- /dev/null +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -0,0 +1,135 @@ +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:6:19 + | +LL | let _: bool = 0 = 0; + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:9:14 + | +LL | 0 => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:10:14 + | +LL | _ => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:14:17 + | +LL | true => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:18:8 + | +LL | if 0 = 0 {} + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:20:24 + | +LL | let _: bool = if { 0 = 0 } { + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:21:9 + | +LL | 0 = 0 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:23:9 + | +LL | 0 = 0 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:26:13 + | +LL | let _ = (0 = 0) + | ^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:27:14 + | +LL | && { 0 = 0 } + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:28:12 + | +LL | || (0 = 0); + | ^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0308`. From 0b9c589beb81499e623d76a142f0ee68910e138c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 26 Mar 2019 14:57:17 +0100 Subject: [PATCH 43/46] adjust assignment-in-if test accordingly. --- .../ui/type/type-check/assignment-in-if.rs | 9 ++++++-- .../type/type-check/assignment-in-if.stderr | 23 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/test/ui/type/type-check/assignment-in-if.rs b/src/test/ui/type/type-check/assignment-in-if.rs index 232b0a00b307d..77b122b0a794a 100644 --- a/src/test/ui/type/type-check/assignment-in-if.rs +++ b/src/test/ui/type/type-check/assignment-in-if.rs @@ -31,8 +31,13 @@ fn main() { //~^ ERROR mismatched types println!("{}", x); } - if (if true { x = 4 } else { x = 5 }) { - //~^ ERROR mismatched types + if ( + if true { + x = 4 //~ ERROR mismatched types + } else { + x = 5 //~ ERROR mismatched types + } + ) { println!("{}", x); } } diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr index 403f7b4f7ae89..87b8d17c21bcc 100644 --- a/src/test/ui/type/type-check/assignment-in-if.stderr +++ b/src/test/ui/type/type-check/assignment-in-if.stderr @@ -47,14 +47,29 @@ LL | if 3 = x { found type `()` error[E0308]: mismatched types - --> $DIR/assignment-in-if.rs:34:8 + --> $DIR/assignment-in-if.rs:36:13 | -LL | if (if true { x = 4 } else { x = 5 }) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found () +LL | x = 4 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == 4` | = note: expected type `bool` found type `()` -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:38:13 + | +LL | x = 5 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == 5` + | + = note: expected type `bool` + found type `()` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. From ce1c5e0a61ab05bd0a944e27c91e2001844516d9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 27 Mar 2019 10:19:35 +0100 Subject: [PATCH 44/46] add negative test case in assignment-expected-bool --- .../type-check/assignment-expected-bool.rs | 5 +++++ .../assignment-expected-bool.stderr | 20 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/test/ui/type/type-check/assignment-expected-bool.rs b/src/test/ui/type/type-check/assignment-expected-bool.rs index bb5ee46c9e17a..03830fea062cf 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.rs +++ b/src/test/ui/type/type-check/assignment-expected-bool.rs @@ -26,4 +26,9 @@ fn main() { let _ = (0 = 0) //~ ERROR mismatched types [E0308] && { 0 = 0 } //~ ERROR mismatched types [E0308] || (0 = 0); //~ ERROR mismatched types [E0308] + + // A test to check that not expecting `bool` behaves well: + let _: usize = 0 = 0; + //~^ ERROR mismatched types [E0308] + //~| ERROR invalid left-hand side expression [E0070] } diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr index e929735734889..fed8b91346582 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.stderr +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -130,6 +130,22 @@ LL | || (0 = 0); = note: expected type `bool` found type `()` -error: aborting due to 11 previous errors +error[E0070]: invalid left-hand side expression + --> $DIR/assignment-expected-bool.rs:31:20 + | +LL | let _: usize = 0 = 0; + | ^^^^^ left-hand of expression not valid + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:31:20 + | +LL | let _: usize = 0 = 0; + | ^^^^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 13 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors occurred: E0070, E0308. +For more information about an error, try `rustc --explain E0070`. From 2368aa8e97e9f3d3df1a75dc798e0e3f4cced7da Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Wed, 27 Mar 2019 19:30:33 +0900 Subject: [PATCH 45/46] Add some tests --- .../existential-types-with-cycle-error.rs | 12 ++++++++ .../existential-types-with-cycle-error.stderr | 30 +++++++++++++++++++ .../existential-types-with-cycle-error2.rs | 16 ++++++++++ ...existential-types-with-cycle-error2.stderr | 30 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 src/test/ui/existential_types/existential-types-with-cycle-error.rs create mode 100644 src/test/ui/existential_types/existential-types-with-cycle-error.stderr create mode 100644 src/test/ui/existential_types/existential-types-with-cycle-error2.rs create mode 100644 src/test/ui/existential_types/existential-types-with-cycle-error2.stderr diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.rs b/src/test/ui/existential_types/existential-types-with-cycle-error.rs new file mode 100644 index 0000000000000..3f0190892ebb3 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error.rs @@ -0,0 +1,12 @@ +#![feature(existential_type)] + +existential type Foo: Fn() -> Foo; +//~^ ERROR: cycle detected when processing `Foo` + +fn crash(x: Foo) -> Foo { + x +} + +fn main() { + +} diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr new file mode 100644 index 0000000000000..56057a9caa4a5 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when processing `Foo` + --> $DIR/existential-types-with-cycle-error.rs:3:1 + | +LL | existential type Foo: Fn() -> Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires processing `crash`... + --> $DIR/existential-types-with-cycle-error.rs:6:25 + | +LL | fn crash(x: Foo) -> Foo { + | _________________________^ +LL | | x +LL | | } + | |_^ + = note: ...which again requires processing `Foo`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/existential-types-with-cycle-error.rs:1:1 + | +LL | / #![feature(existential_type)] +LL | | +LL | | existential type Foo: Fn() -> Foo; +LL | | +... | +LL | | +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.rs b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs new file mode 100644 index 0000000000000..29410309ef26e --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs @@ -0,0 +1,16 @@ +#![feature(existential_type)] + +pub trait Bar { + type Item; +} + +existential type Foo: Bar; +//~^ ERROR: cycle detected when processing `Foo` + +fn crash(x: Foo) -> Foo { + x +} + +fn main() { + +} diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr new file mode 100644 index 0000000000000..8c7bf52470ab2 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when processing `Foo` + --> $DIR/existential-types-with-cycle-error2.rs:7:1 + | +LL | existential type Foo: Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires processing `crash`... + --> $DIR/existential-types-with-cycle-error2.rs:10:25 + | +LL | fn crash(x: Foo) -> Foo { + | _________________________^ +LL | | x +LL | | } + | |_^ + = note: ...which again requires processing `Foo`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/existential-types-with-cycle-error2.rs:1:1 + | +LL | / #![feature(existential_type)] +LL | | +LL | | pub trait Bar { +LL | | type Item; +... | +LL | | +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. From ba21e0b368d891102c299afe1410dd886598cda4 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 27 Mar 2019 12:28:17 +0100 Subject: [PATCH 46/46] Include id in Thread's Debug implementation Since Rust 1.19.0, id is a stable method, so there is no reason to not include it in Debug implementation. --- src/libstd/thread/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 08f0aa2f0d206..63fa46e2eddd6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1256,7 +1256,10 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Thread { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.name(), f) + f.debug_struct("Thread") + .field("id", &self.id()) + .field("name", &self.name()) + .finish() } }