From 0c88dd663a7095ccc405a2036047a90981137a51 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 23 Jun 2020 22:42:35 -0400 Subject: [PATCH 01/17] Update Box::from_raw example to generalize better I know very little about rust, so I saw this example and tried to generalize it by writing, ``` let layout = Layout::new::(); let new_obj = unsafe { let ptr = alloc(layout) as *mut T; *ptr = obj; Box::from_raw(ptr) }; ``` for some more complicated `T`, which ended up crashing with SIGSEGV, because it tried to `drop_in_place` the previous object in `ptr` which is of course garbage. I also added a comment that explains why `.write` is used, but I think adding that comment is optional and may be too verbose here. I do however think that changing this example is a good idea to suggest the correct generalization. `.write` is also used in most of the rest of the documentation here, even if the example is `i32`, so it would additionally be more consistent. --- src/liballoc/boxed.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d10cbf1afab30..02634825c2108 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -382,7 +382,10 @@ impl Box { /// /// unsafe { /// let ptr = alloc(Layout::new::()) as *mut i32; - /// *ptr = 5; + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); /// let x = Box::from_raw(ptr); /// } /// ``` From 2bbc2b3de42f3b14ccc8b62c2acffc8840177777 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Thu, 25 Jun 2020 11:18:53 +0200 Subject: [PATCH 02/17] Document the static keyword --- src/libstd/keyword_docs.rs | 80 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a4996d9eee810..746165beab8f5 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1030,9 +1030,85 @@ mod self_upper_keyword {} // /// A place that is valid for the duration of a program. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `static` item is similar to a [`const`] item in that it lives for the +/// entire duration of the program and need to have its type explicited, with a +/// `static` lifetime, outliving any other lifetime. Added to that, `static` +/// items represent a precise memory location. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// Static items do not call [`drop`] at the end of the program. +/// +/// There are two types of `static` items: those declared in association with +/// the [`mut`] keyword and those without. +/// +/// # Simple `static`s +/// +/// Non-[`mut`] `static` items that contain a type that is not interior mutable +/// may be placed in read-only memory. All access to a `static` item are +/// considered safe but some restrictions apply. See the [Reference] for more +/// information. +/// +/// ```rust +/// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; +/// +/// let r1 = &FOO as *const _; +/// let r2 = &FOO as *const _; +/// // With a strictly read-only static, references will have the same adress +/// assert_eq!(r1, r2); +/// ``` +/// +/// # Mutable `static`s +/// +/// If a `static` item is declared with the [`mut`] keyword, then it is allowed +/// to be modified by the program. To make concurrency bugs hard to run into, +/// all access to a `static mut` require an [`unsafe`] block. Care should be +/// taken to ensure access (both read and write) are thread-safe. +/// +/// Despite their unsafety, mutable `static`s are very useful: they can be used +/// to represent global state shared by the whole program or be used in +/// [`extern`] blocks to bind to variables from C libraries. +/// +/// As global state: +/// +/// ```rust +/// # #![allow(unused_variables)] +/// # fn main() {} +/// # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } +/// static mut LEVELS: u32 = 0; +/// +/// // This violates the idea of no shared state, and this doesn't internally +/// // protect against races, so this function is `unsafe` +/// unsafe fn bump_levels_unsafe1() -> u32 { +/// let ret = LEVELS; +/// LEVELS += 1; +/// return ret; +/// } +/// +/// // Assuming that we have an atomic_add function which returns the old value, +/// // this function is "safe" but the meaning of the return value may not be +/// // what callers expect, so it's still marked as `unsafe` +/// unsafe fn bump_levels_unsafe2() -> u32 { +/// return atomic_add(&mut LEVELS, 1); +/// } +/// ``` +/// +/// In an [`extern`] block: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// extern "C" { +/// static mut ERROR_MESSAGE: *mut std::os::raw::c_char; +/// } +/// ``` +/// +/// Mutable `static`s, just like simple `static`s, have some restrictions that +/// apply to them. See the [Reference] for more information. +/// +/// [`const`]: keyword.const.html +/// [`extern`]: keyword.extern.html +/// [`mut`]: keyword.mut.html +/// [`unsafe`]: keyword.unsafe.html +/// [`drop`]: mem/fn.drop.html +/// [Reference]: ../reference/items/static-items.html#static-items mod static_keyword {} #[doc(keyword = "struct")] From b71a3e1e3a20e7db3b8167d19002c372ffe69c54 Mon Sep 17 00:00:00 2001 From: Tyler Ruckinger Date: Fri, 26 Jun 2020 00:43:34 -0400 Subject: [PATCH 03/17] Map ERROR_INVALID_PARAMETER to InvalidInput --- src/libstd/sys/windows/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 640c9f3636d4b..193ab5b47ef13 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -61,6 +61,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, + c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput, c::ERROR_SEM_TIMEOUT | c::WAIT_TIMEOUT | c::ERROR_DRIVER_CANCEL_TIMEOUT From 0d0865fea59da88498ed80ccff1180e450f34ae5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 27 Jun 2020 11:47:18 +0200 Subject: [PATCH 04/17] Make `rustc_peek` a safe intrinsic --- src/librustc_typeck/check/intrinsic.rs | 2 +- src/test/ui/mir-dataflow/def-inits-1.rs | 18 +++++------ src/test/ui/mir-dataflow/def-inits-1.stderr | 24 +++++++-------- .../mir-dataflow/indirect-mutation-offset.rs | 2 +- .../indirect-mutation-offset.stderr | 6 ++-- src/test/ui/mir-dataflow/inits-1.rs | 18 +++++------ src/test/ui/mir-dataflow/inits-1.stderr | 18 +++++------ src/test/ui/mir-dataflow/liveness-ptr.rs | 6 ++-- src/test/ui/mir-dataflow/liveness-ptr.stderr | 6 ++-- src/test/ui/mir-dataflow/uninits-1.rs | 18 +++++------ src/test/ui/mir-dataflow/uninits-1.stderr | 30 +++++++++---------- src/test/ui/mir-dataflow/uninits-2.rs | 4 +-- src/test/ui/mir-dataflow/uninits-2.stderr | 6 ++-- 13 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 1c0b22ca7370b..5cf98109615c2 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -75,7 +75,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely" | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32" - | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal, + | "rustc_peek" | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs index 91d41e9b5794e..30460824a1678 100644 --- a/src/test/ui/mir-dataflow/def-inits-1.rs +++ b/src/test/ui/mir-dataflow/def-inits-1.rs @@ -11,13 +11,13 @@ struct S(i32); fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { let ret; // `ret` starts off uninitialized - unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set // All function formal parameters start off initialized. - unsafe { rustc_peek(&x) }; - unsafe { rustc_peek(&y) }; - unsafe { rustc_peek(&z) }; + rustc_peek(&x); + rustc_peek(&y); + rustc_peek(&z); ret = if test { ::std::mem::replace(x, y) @@ -27,21 +27,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { }; // `z` may be uninitialized here. - unsafe { rustc_peek(&z); } //~ ERROR rustc_peek: bit not set + rustc_peek(&z); //~ ERROR rustc_peek: bit not set // `y` is definitely uninitialized here. - unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set + rustc_peek(&y); //~ ERROR rustc_peek: bit not set // `x` is still (definitely) initialized (replace above is a reborrow). - unsafe { rustc_peek(&x); } + rustc_peek(&x); ::std::mem::drop(x); // `x` is *definitely* uninitialized here - unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + rustc_peek(&x); //~ ERROR rustc_peek: bit not set // `ret` is now definitely initialized (via `if` above). - unsafe { rustc_peek(&ret); } + rustc_peek(&ret); ret } diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr index 48d8450489488..e2bddb54d9ba8 100644 --- a/src/test/ui/mir-dataflow/def-inits-1.stderr +++ b/src/test/ui/mir-dataflow/def-inits-1.stderr @@ -1,26 +1,26 @@ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:14:14 + --> $DIR/def-inits-1.rs:14:5 | -LL | unsafe { rustc_peek(&ret); } - | ^^^^^^^^^^^^^^^^ +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:30:14 + --> $DIR/def-inits-1.rs:30:5 | -LL | unsafe { rustc_peek(&z); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&z); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:33:14 + --> $DIR/def-inits-1.rs:33:5 | -LL | unsafe { rustc_peek(&y); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:41:14 + --> $DIR/def-inits-1.rs:41:5 | -LL | unsafe { rustc_peek(&x); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs index caa307e269fe7..374a9f75a134b 100644 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs +++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs @@ -38,7 +38,7 @@ const BOO: i32 = { *rmut_cell = 42; // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!! let val = *rmut_cell; - unsafe { rustc_peek(x) }; //~ ERROR rustc_peek: bit not set + rustc_peek(x); //~ ERROR rustc_peek: bit not set val }; diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr index 8d3548ececdd9..1d5287c15ab79 100644 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr +++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr @@ -1,8 +1,8 @@ error: rustc_peek: bit not set - --> $DIR/indirect-mutation-offset.rs:41:14 + --> $DIR/indirect-mutation-offset.rs:41:5 | -LL | unsafe { rustc_peek(x) }; - | ^^^^^^^^^^^^^ +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs index 4a4786a2a7378..8fb1d4bc736d6 100644 --- a/src/test/ui/mir-dataflow/inits-1.rs +++ b/src/test/ui/mir-dataflow/inits-1.rs @@ -11,13 +11,13 @@ struct S(i32); fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { let ret; // `ret` starts off uninitialized, so we get an error report here. - unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set // All function formal parameters start off initialized. - unsafe { rustc_peek(&x) }; - unsafe { rustc_peek(&y) }; - unsafe { rustc_peek(&z) }; + rustc_peek(&x); + rustc_peek(&y); + rustc_peek(&z); ret = if test { ::std::mem::replace(x, y) @@ -28,21 +28,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { // `z` may be initialized here. - unsafe { rustc_peek(&z); } + rustc_peek(&z); // `y` is definitely uninitialized here. - unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set + rustc_peek(&y); //~ ERROR rustc_peek: bit not set // `x` is still (definitely) initialized (replace above is a reborrow). - unsafe { rustc_peek(&x); } + rustc_peek(&x); ::std::mem::drop(x); // `x` is *definitely* uninitialized here - unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + rustc_peek(&x); //~ ERROR rustc_peek: bit not set // `ret` is now definitely initialized (via `if` above). - unsafe { rustc_peek(&ret); } + rustc_peek(&ret); ret } diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr index 23d0679cb1ac1..7a00a70af6f84 100644 --- a/src/test/ui/mir-dataflow/inits-1.stderr +++ b/src/test/ui/mir-dataflow/inits-1.stderr @@ -1,20 +1,20 @@ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:14:14 + --> $DIR/inits-1.rs:14:5 | -LL | unsafe { rustc_peek(&ret); } - | ^^^^^^^^^^^^^^^^ +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:34:14 + --> $DIR/inits-1.rs:34:5 | -LL | unsafe { rustc_peek(&y); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:42:14 + --> $DIR/inits-1.rs:42:5 | -LL | unsafe { rustc_peek(&x); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/liveness-ptr.rs b/src/test/ui/mir-dataflow/liveness-ptr.rs index 34097d7526a6e..786da523a3391 100644 --- a/src/test/ui/mir-dataflow/liveness-ptr.rs +++ b/src/test/ui/mir-dataflow/liveness-ptr.rs @@ -10,17 +10,17 @@ fn foo() -> i32 { x = 0; // `x` is live here since it is used in the next statement... - unsafe { rustc_peek(x); } + rustc_peek(x); p = &x; // ... but not here, even while it can be accessed through `p`. - unsafe { rustc_peek(x); } //~ ERROR rustc_peek: bit not set + rustc_peek(x); //~ ERROR rustc_peek: bit not set let tmp = unsafe { *p }; x = tmp + 1; - unsafe { rustc_peek(x); } + rustc_peek(x); x } diff --git a/src/test/ui/mir-dataflow/liveness-ptr.stderr b/src/test/ui/mir-dataflow/liveness-ptr.stderr index 3397d0c5a121d..858cdbac3d312 100644 --- a/src/test/ui/mir-dataflow/liveness-ptr.stderr +++ b/src/test/ui/mir-dataflow/liveness-ptr.stderr @@ -1,8 +1,8 @@ error: rustc_peek: bit not set - --> $DIR/liveness-ptr.rs:18:14 + --> $DIR/liveness-ptr.rs:18:5 | -LL | unsafe { rustc_peek(x); } - | ^^^^^^^^^^^^^ +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs index 66b3f458a5159..c2b4284a7b4f8 100644 --- a/src/test/ui/mir-dataflow/uninits-1.rs +++ b/src/test/ui/mir-dataflow/uninits-1.rs @@ -11,13 +11,13 @@ struct S(i32); fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { let ret; // `ret` starts off uninitialized - unsafe { rustc_peek(&ret); } + rustc_peek(&ret); // All function formal parameters start off initialized. - unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set - unsafe { rustc_peek(&y) }; //~ ERROR rustc_peek: bit not set - unsafe { rustc_peek(&z) }; //~ ERROR rustc_peek: bit not set + rustc_peek(&x); //~ ERROR rustc_peek: bit not set + rustc_peek(&y); //~ ERROR rustc_peek: bit not set + rustc_peek(&z); //~ ERROR rustc_peek: bit not set ret = if test { ::std::mem::replace(x, y) @@ -27,21 +27,21 @@ fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { }; // `z` may be uninitialized here. - unsafe { rustc_peek(&z); } + rustc_peek(&z); // `y` is definitely uninitialized here. - unsafe { rustc_peek(&y); } + rustc_peek(&y); // `x` is still (definitely) initialized (replace above is a reborrow). - unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + rustc_peek(&x); //~ ERROR rustc_peek: bit not set ::std::mem::drop(x); // `x` is *definitely* uninitialized here - unsafe { rustc_peek(&x); } + rustc_peek(&x); // `ret` is now definitely initialized (via `if` above). - unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + rustc_peek(&ret); //~ ERROR rustc_peek: bit not set ret } diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr index 5f6dbde212d0a..c52f5ac7bd9b6 100644 --- a/src/test/ui/mir-dataflow/uninits-1.stderr +++ b/src/test/ui/mir-dataflow/uninits-1.stderr @@ -1,32 +1,32 @@ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:18:14 + --> $DIR/uninits-1.rs:18:5 | -LL | unsafe { rustc_peek(&x) }; - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:19:14 + --> $DIR/uninits-1.rs:19:5 | -LL | unsafe { rustc_peek(&y) }; - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&y); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:20:14 + --> $DIR/uninits-1.rs:20:5 | -LL | unsafe { rustc_peek(&z) }; - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&z); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:36:14 + --> $DIR/uninits-1.rs:36:5 | -LL | unsafe { rustc_peek(&x); } - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:44:14 + --> $DIR/uninits-1.rs:44:5 | -LL | unsafe { rustc_peek(&ret); } - | ^^^^^^^^^^^^^^^^ +LL | rustc_peek(&ret); + | ^^^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs index 2ccf1c7f9d6c6..c584ee74afb48 100644 --- a/src/test/ui/mir-dataflow/uninits-2.rs +++ b/src/test/ui/mir-dataflow/uninits-2.rs @@ -11,12 +11,12 @@ struct S(i32); fn foo(x: &mut S) { // `x` is initialized here, so maybe-uninit bit is 0. - unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set + rustc_peek(&x); //~ ERROR rustc_peek: bit not set ::std::mem::drop(x); // `x` definitely uninitialized here, so maybe-uninit bit is 1. - unsafe { rustc_peek(&x) }; + rustc_peek(&x); } fn main() { foo(&mut S(13)); diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr index dcb61371994db..0ef954e35a4d8 100644 --- a/src/test/ui/mir-dataflow/uninits-2.stderr +++ b/src/test/ui/mir-dataflow/uninits-2.stderr @@ -1,8 +1,8 @@ error: rustc_peek: bit not set - --> $DIR/uninits-2.rs:14:14 + --> $DIR/uninits-2.rs:14:5 | -LL | unsafe { rustc_peek(&x) }; - | ^^^^^^^^^^^^^^ +LL | rustc_peek(&x); + | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation From 765bd47fa0f0e0d5d893283a94c76e2b1009d680 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 27 Jun 2020 11:35:12 -0400 Subject: [PATCH 05/17] Recover extra trailing angle brackets in struct definition This commit applies the existing 'extra angle bracket recovery' logic when parsing fields in struct definitions. This allows us to continue parsing the struct's fields, avoiding spurious 'missing field' errors in code that tries to use the struct. --- src/librustc_parse/parser/diagnostics.rs | 19 ++++++++---- src/librustc_parse/parser/expr.rs | 2 +- src/librustc_parse/parser/item.rs | 29 ++++++++++++++++++- src/librustc_parse/parser/path.rs | 2 +- .../recover-field-extra-angle-brackets.rs | 14 +++++++++ .../recover-field-extra-angle-brackets.stderr | 8 +++++ 6 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/parser/recover-field-extra-angle-brackets.rs create mode 100644 src/test/ui/parser/recover-field-extra-angle-brackets.stderr diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index fc9ffc3092447..4b060bf108f4e 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -376,7 +376,14 @@ impl<'a> Parser<'a> { /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); /// ^^ help: remove extra angle brackets /// ``` - pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + /// + /// If `true` is returned, then trailing brackets were recovered, tokens were consumed + /// up until one of the tokens in 'end' was encountered, and an error was emitted. + pub(super) fn check_trailing_angle_brackets( + &mut self, + segment: &PathSegment, + end: &[&TokenKind], + ) -> bool { // This function is intended to be invoked after parsing a path segment where there are two // cases: // @@ -409,7 +416,7 @@ impl<'a> Parser<'a> { parsed_angle_bracket_args, ); if !parsed_angle_bracket_args { - return; + return false; } // Keep the span at the start so we can highlight the sequence of `>` characters to be @@ -447,18 +454,18 @@ impl<'a> Parser<'a> { number_of_gt, number_of_shr, ); if number_of_gt < 1 && number_of_shr < 1 { - return; + return false; } // Finally, double check that we have our end token as otherwise this is the // second case. if self.look_ahead(position, |t| { trace!("check_trailing_angle_brackets: t={:?}", t); - *t == end + end.contains(&&t.kind) }) { // Eat from where we started until the end token so that parsing can continue // as if we didn't have those extra angle brackets. - self.eat_to_tokens(&[&end]); + self.eat_to_tokens(end); let span = lo.until(self.token.span); let total_num_of_gt = number_of_gt + number_of_shr * 2; @@ -473,7 +480,9 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); + return true; } + false } /// Check to see if a pair of chained operators looks like an attempt at chained comparison, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 2745b18a8cd51..fb38fdc26c782 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -867,7 +867,7 @@ impl<'a> Parser<'a> { let fn_span_lo = self.token.span; let segment = self.parse_path_segment(PathStyle::Expr)?; - self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); + self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]); if self.check(&token::OpenDelim(token::Paren)) { // Method call `expr.f()` diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 10df16964da08..fa6264c98e4f0 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; -use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind}; +use rustc_ast::ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; @@ -1262,6 +1262,25 @@ impl<'a> Parser<'a> { sp, &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)), ); + + // Try to recover extra trailing angle brackets + let mut recovered = false; + if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind { + if let Some(last_segment) = segments.last() { + recovered = self.check_trailing_angle_brackets( + last_segment, + &[&token::Comma, &token::CloseDelim(token::Brace)], + ); + if recovered { + // Handle a case like `Vec>,` where we can continue parsing fields + // after the comma + self.eat(&token::Comma); + // `check_trailing_angle_brackets` already emitted a nicer error + err.cancel(); + } + } + } + if self.token.is_ident() { // This is likely another field; emit the diagnostic and keep going err.span_suggestion( @@ -1271,6 +1290,14 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.emit(); + recovered = true; + } + + if recovered { + // Make sure an error was emitted (either by recovering an angle bracket, + // or by finding an identifier as the next token), since we're + // going to continue parsing + assert!(self.sess.span_diagnostic.has_errors()); } else { return Err(err); } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 5210614548da3..67e9b3af4a8cf 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -169,7 +169,7 @@ impl<'a> Parser<'a> { // `PathStyle::Expr` is only provided at the root invocation and never in // `parse_path_segment` to recurse and therefore can be checked to maintain // this invariant. - self.check_trailing_angle_brackets(&segment, token::ModSep); + self.check_trailing_angle_brackets(&segment, &[&token::ModSep]); } segments.push(segment); diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.rs b/src/test/ui/parser/recover-field-extra-angle-brackets.rs new file mode 100644 index 0000000000000..5e0e00bcb5e8d --- /dev/null +++ b/src/test/ui/parser/recover-field-extra-angle-brackets.rs @@ -0,0 +1,14 @@ +// Tests that we recover from extra trailing angle brackets +// in a struct field + +struct BadStruct { + first: Vec>, //~ ERROR unmatched angle bracket + second: bool +} + +fn bar(val: BadStruct) { + val.first; + val.second; +} + +fn main() {} diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.stderr b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr new file mode 100644 index 0000000000000..318e55f6e99ac --- /dev/null +++ b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr @@ -0,0 +1,8 @@ +error: unmatched angle bracket + --> $DIR/recover-field-extra-angle-brackets.rs:5:19 + | +LL | first: Vec>, + | ^ help: remove extra angle bracket + +error: aborting due to previous error + From 3fc5593ea80819f940f6edef3108d15ef2ad7956 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sat, 27 Jun 2020 18:33:15 +0200 Subject: [PATCH 06/17] Document the type keyword --- src/libstd/keyword_docs.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index d972cf6db18cf..3b493c4244de6 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1463,9 +1463,33 @@ mod true_keyword {} // /// Define an alias for an existing type. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// The syntax is `type Name = ExistingType;`. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// # Examples +/// +/// `type` does **not** create a new type: +/// +/// ```rust +/// type Meters = u32; +/// type Kilograms = u32; +/// +/// let m: Meters = 3; +/// let k: Kilograms = 3; +/// +/// assert_eq!(m, k); +/// ``` +/// +/// In traits, using `type` allows the usage of an associated type without +/// knowing about it when declaring the [`trait`]: +/// +/// ```rust +/// trait Iterator { +/// type Item; +/// fn next(&mut self) -> Option; +/// } +/// ``` +/// +/// [`trait`]: keyword.trait.html mod type_keyword {} #[doc(keyword = "unsafe")] From 517d361a1f78cf13d589d0f6b94f5ca005bef540 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 27 Jun 2020 13:54:56 -0400 Subject: [PATCH 07/17] Use an 'approximate' universal upper bound when reporting region errors Fixes #67765 When reporting errors during MIR region inference, we sometimes use `universal_upper_bound` to obtain a named universal region that we can display to the user. However, this is not always possible - in a case like `fn foo<'a, 'b>() { .. }`, the only upper bound for a region containing `'a` and `'b` is `'static`. When displaying diagnostics, it's usually better to display *some* named region (even if there are multiple involved) rather than fall back to a generic error involving `'static`. This commit adds a new `approx_universal_upper_bound` method, which uses the lowest-numbered universal region if the only alternative is to return `'static`. --- .../borrow_check/diagnostics/region_errors.rs | 4 ++- .../borrow_check/region_infer/mod.rs | 34 +++++++++++++++++++ .../borrow_check/region_infer/opaque_types.rs | 3 +- .../issue-67765-async-diagnostic.rs | 16 +++++++++ .../issue-67765-async-diagnostic.stderr | 12 +++++++ ...ure-doesnt-life-long-enough-issue-67634.rs | 2 +- ...doesnt-life-long-enough-issue-67634.stderr | 24 ++++++++----- src/test/ui/return-disjoint-regions.rs | 7 ++++ src/test/ui/return-disjoint-regions.stderr | 11 ++++++ 9 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/async-await/issue-67765-async-diagnostic.rs create mode 100644 src/test/ui/async-await/issue-67765-async-diagnostic.stderr create mode 100644 src/test/ui/return-disjoint-regions.rs create mode 100644 src/test/ui/return-disjoint-regions.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index f1923b9e81c66..fa4846a20cbfb 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -122,7 +122,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.regioncx.universal_regions().is_universal_region(r) { Some(r) } else { - let upper_bound = self.regioncx.universal_upper_bound(r); + // We just want something nameable, even if it's not + // actually an upper bound. + let upper_bound = self.regioncx.approx_universal_upper_bound(r); if self.regioncx.upper_bound_in_region_scc(r, upper_bound) { self.to_error_region_vid(upper_bound) diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 3e459bd52f757..081125cb625c2 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1114,6 +1114,40 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub } + /// Like `universal_upper_bound`, but returns an approximation more suitable + /// for diagnostics. If `r` contains multiple disjoint universal regions + /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. + /// This corresponds to picking named regions over unnamed regions + /// (e.g. picking early-bound regions over a closure late-bound region). + /// + /// This means that the returned value may not be a true upper bound, since + /// only 'static is known to outlive disjoint universal regions. + /// Therefore, this method should only be used in diagnostic code, + /// where displaying *some* named universal region is better than + /// falling back to 'static. + pub(in crate::borrow_check) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { + debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + + // Find the smallest universal region that contains all other + // universal regions within `region`. + let mut lub = self.universal_regions.fr_fn_body; + let r_scc = self.constraint_sccs.scc(r); + let static_r = self.universal_regions.fr_static; + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); + debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + if ur != static_r && lub != static_r && new_lub == static_r { + lub = std::cmp::min(ur, lub); + } else { + lub = new_lub; + } + } + + debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); + + lub + } + /// Tests if `test` is true when applied to `lower_bound` at /// `point`. fn eval_verify_bound( diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index 7e352bfba77bc..325dca8c8ca99 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -141,7 +141,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { { tcx.fold_regions(&ty, &mut false, |region, _| match *region { ty::ReVar(vid) => { - let upper_bound = self.universal_upper_bound(vid); + // Find something that we can name + let upper_bound = self.approx_universal_upper_bound(vid); self.definitions[upper_bound].external_name.unwrap_or(region) } _ => region, diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.rs b/src/test/ui/async-await/issue-67765-async-diagnostic.rs new file mode 100644 index 0000000000000..5093916e73a45 --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.rs @@ -0,0 +1,16 @@ +// edition:2018 +// +// Regression test for issue #67765 +// Tests that we point at the proper location when giving +// a lifetime error. +fn main() {} + +async fn func<'a>() -> Result<(), &'a str> { + let s = String::new(); + + let b = &s[..]; + + Err(b)?; //~ ERROR cannot return value referencing local variable `s` + + Ok(()) +} diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr new file mode 100644 index 0000000000000..78253042bee1c --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local variable `s` + --> $DIR/issue-67765-async-diagnostic.rs:13:11 + | +LL | let b = &s[..]; + | - `s` is borrowed here +LL | +LL | Err(b)?; + | ^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs index 19d7f0190479e..8deb365515840 100644 --- a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs @@ -1,3 +1,3 @@ fn main() { - [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR `a` does not live long enough + [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR closure may outlive } diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr index cb0b481e74876..34470119112fb 100644 --- a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr @@ -1,15 +1,21 @@ -error[E0597]: `a` does not live long enough - --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:49 +error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:44 | LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); - | - ^- ...but `a` will be dropped here, when the enclosing closure returns - | | | - | | `a` would have to be valid for `'_`... - | has type `&i32` + | ^^^ - `a` is borrowed here + | | + | may outlive borrowed value `a` | - = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments - = note: to learn more, visit +note: closure is returned here + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:29 + | +LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword + | +LL | [0].iter().flat_map(|a| [0].iter().map(move |_| &a)); + | ^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/return-disjoint-regions.rs b/src/test/ui/return-disjoint-regions.rs new file mode 100644 index 0000000000000..d0feb3b65e12a --- /dev/null +++ b/src/test/ui/return-disjoint-regions.rs @@ -0,0 +1,7 @@ +// See https://github.com/rust-lang/rust/pull/67911#issuecomment-576023915 +fn f<'a, 'b>(x: i32) -> (&'a i32, &'b i32) { + let y = &x; + (y, y) //~ ERROR cannot return +} + +fn main() {} diff --git a/src/test/ui/return-disjoint-regions.stderr b/src/test/ui/return-disjoint-regions.stderr new file mode 100644 index 0000000000000..ed159298804ae --- /dev/null +++ b/src/test/ui/return-disjoint-regions.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing function parameter `x` + --> $DIR/return-disjoint-regions.rs:4:5 + | +LL | let y = &x; + | -- `x` is borrowed here +LL | (y, y) + | ^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. From 7055c23d2cb3baabbae6af7ab196e43035260856 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Jun 2020 17:45:08 +0300 Subject: [PATCH 08/17] ast_pretty: Pass some token streams and trees by reference --- src/librustc_ast_pretty/pprust.rs | 38 +++++++++++----------- src/librustc_builtin_macros/log_syntax.rs | 2 +- src/librustc_builtin_macros/source_util.rs | 2 +- src/librustc_expand/mbe/macro_rules.rs | 4 +-- src/librustc_expand/proc_macro_server.rs | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 86faa1f086ce2..501cd3748282b 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::util::{classify, comments}; use rustc_span::edition::Edition; @@ -293,7 +293,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(ref e) => expr_to_string(e), - token::NtTT(ref tree) => tt_to_string(tree.clone()), + token::NtTT(ref tree) => tt_to_string(tree), token::NtVis(ref e) => vis_to_string(e), } } @@ -314,11 +314,11 @@ pub fn expr_to_string(e: &ast::Expr) -> String { to_string(|s| s.print_expr(e)) } -pub fn tt_to_string(tt: tokenstream::TokenTree) -> String { +pub fn tt_to_string(tt: &TokenTree) -> String { to_string(|s| s.print_tt(tt, false)) } -pub fn tts_to_string(tokens: TokenStream) -> String { +pub fn tts_to_string(tokens: &TokenStream) -> String { to_string(|s| s.print_tts(tokens, false)) } @@ -585,7 +585,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere false, None, delim.to_token(), - tokens.clone(), + tokens, true, span, ), @@ -594,7 +594,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere if let MacArgs::Eq(_, tokens) = &item.args { self.space(); self.word_space("="); - self.print_tts(tokens.clone(), true); + self.print_tts(tokens, true); } } } @@ -635,9 +635,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere /// appropriate macro, transcribe back into the grammar we just parsed from, /// and then pretty-print the resulting AST nodes (so, e.g., we print /// expression arguments as expressions). It can be done! I think. - fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) { + fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { match tt { - TokenTree::Token(ref token) => { + TokenTree::Token(token) => { self.word(token_to_string_ext(&token, convert_dollar_crate)); if let token::DocComment(..) = token.kind { self.hardbreak() @@ -648,7 +648,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere None, false, None, - delim, + *delim, tts, convert_dollar_crate, dspan.entire(), @@ -657,14 +657,14 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) { - let mut iter = tts.into_trees().peekable(); + fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { + let mut iter = tts.trees().peekable(); while let Some(tt) = iter.next() { - let show_space = - if let Some(next) = iter.peek() { tt_prepend_space(next, &tt) } else { false }; - self.print_tt(tt, convert_dollar_crate); - if show_space { - self.space(); + self.print_tt(&tt, convert_dollar_crate); + if let Some(next) = iter.peek() { + if tt_prepend_space(next, &tt) { + self.space(); + } } } } @@ -675,7 +675,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang: bool, ident: Option, delim: DelimToken, - tts: TokenStream, + tts: &TokenStream, convert_dollar_crate: bool, span: Span, ) { @@ -1253,7 +1253,7 @@ impl<'a> State<'a> { has_bang, Some(item.ident), macro_def.body.delim(), - macro_def.body.inner_tokens(), + ¯o_def.body.inner_tokens(), true, item.span, ); @@ -1577,7 +1577,7 @@ impl<'a> State<'a> { true, None, m.args.delim(), - m.args.inner_tokens(), + &m.args.inner_tokens(), true, m.span(), ); diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs index ae3a889428ae4..ede34a7612589 100644 --- a/src/librustc_builtin_macros/log_syntax.rs +++ b/src/librustc_builtin_macros/log_syntax.rs @@ -7,7 +7,7 @@ pub fn expand_log_syntax<'cx>( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - println!("{}", pprust::tts_to_string(tts)); + println!("{}", pprust::tts_to_string(&tts)); // any so that `log_syntax` can be invoked as an expression and item. base::DummyResult::any_valid(sp) diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 1b164eae5a345..e46cf67e64d66 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -71,7 +71,7 @@ pub fn expand_stringify( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let s = pprust::tts_to_string(tts); + let s = pprust::tts_to_string(&tts); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 8cdb5b09c9e8b..28a3970918ee6 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -224,7 +224,7 @@ fn generic_extension<'cx>( let sess = cx.parse_sess; if cx.trace_macros() { - let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); + let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg)); trace_macros_note(&mut cx.expansions, sp, msg); } @@ -300,7 +300,7 @@ fn generic_extension<'cx>( } if cx.trace_macros() { - let msg = format!("to `{}`", pprust::tts_to_string(tts.clone())); + let msg = format!("to `{}`", pprust::tts_to_string(&tts)); trace_macros_note(&mut cx.expansions, sp, msg); } diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index c88b5a37f718a..e5e530227e43a 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -413,7 +413,7 @@ impl server::TokenStream for Rustc<'_> { ) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { - pprust::tts_to_string(stream.clone()) + pprust::tts_to_string(stream) } fn from_token_tree( &mut self, From 14d03702735ccca48f5b954db6c01e9cedb14f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 28 Jun 2020 00:00:00 +0000 Subject: [PATCH 09/17] Remove defunct `-Z print-region-graph` --- src/librustc_interface/tests.rs | 1 - src/librustc_session/options.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index d861b444c8816..e35dbbc0c2f24 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -500,7 +500,6 @@ fn test_debugging_options_tracking_hash() { untracked!(print_link_args, true); untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); - untracked!(print_region_graph, true); untracked!(print_type_sizes, true); untracked!(query_dep_graph, true); untracked!(query_stats, true); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 9337f241d7022..ed5fd6dc7028b 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -958,9 +958,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], "print the result of the monomorphization collection pass"), - print_region_graph: bool = (false, parse_bool, [UNTRACKED], - "prints region inference graph. \ - Use with RUST_REGION_GRAPH=help for more info (default: no)"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered (default: no)"), profile: bool = (false, parse_bool, [TRACKED], From 7231e575461d1246c247b2ac3e97c1adcab49737 Mon Sep 17 00:00:00 2001 From: James Box Date: Sat, 27 Jun 2020 22:55:42 -0500 Subject: [PATCH 10/17] Fix wording for anonymous parameter name help --- src/librustc_parse/parser/diagnostics.rs | 2 +- src/test/ui/anon-params/anon-params-denied-2018.stderr | 8 ++++---- src/test/ui/parser/inverted-parameters.rs | 2 +- src/test/ui/parser/inverted-parameters.stderr | 2 +- src/test/ui/parser/omitted-arg-in-item-fn.stderr | 2 +- src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr | 2 +- src/test/ui/span/issue-34264.stderr | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index fc9ffc3092447..e27bbc532cfc4 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1415,7 +1415,7 @@ impl<'a> Parser<'a> { if self.token != token::Lt { err.span_suggestion( pat.span, - "if this was a parameter name, give it a type", + "if this is a parameter name, give it a type", format!("{}: TypeName", ident), Applicability::HasPlaceholders, ); diff --git a/src/test/ui/anon-params/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr index e7a806a846820..840294db0830a 100644 --- a/src/test/ui/anon-params/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params/anon-params-denied-2018.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: i32); | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(i32: TypeName); | ^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar_with_default_impl(self: String, String) {} | ^^^^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String: TypeName, String) {} | ^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn bar_with_default_impl(String, String) {} | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String, String: TypeName) {} | ^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | fn baz(a:usize, b, c: usize) -> usize { | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn baz(a:usize, b: TypeName, c: usize) -> usize { | ^^^^^^^^^^^ diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index 6f19ee9c7dc0d..5c4272504e061 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -20,7 +20,7 @@ fn pattern((i32, i32) (a, b)) {} fn fizz(i32) {} //~^ ERROR expected one of `:`, `@` -//~| HELP if this was a parameter name, give it a type +//~| HELP if this is a parameter name, give it a type //~| HELP if this is a `self` type, give it a parameter name //~| HELP if this is a type, explicitly ignore the parameter name diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index 043ff65f74e1a..ae180af93e373 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -39,7 +39,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn fizz(self: i32) {} | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn fizz(i32: TypeName) {} | ^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index 9f138bf84ce19..bc3329dcbc23d 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: x) { | ^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(x: TypeName) { | ^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index 1e51567a9b1c4..5516d4a4c1c1c 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); } | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } | ^^^^^^^^^^^^^ diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 116f5ddd5b4b2..40c3219bf27b0 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -21,7 +21,7 @@ LL | fn foo(Option, String) {} | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(Option, String: TypeName) {} | ^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar(self: x, y: usize) {} | ^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar(x: TypeName, y: usize) {} | ^^^^^^^^^^^ From e611a3fb8423f178e856813fc1a1f2397980bd8a Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 17:20:27 +0200 Subject: [PATCH 11/17] Apply suggestions from code review --- src/libstd/keyword_docs.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 3b493c4244de6..089056d68f803 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1479,17 +1479,28 @@ mod true_keyword {} /// assert_eq!(m, k); /// ``` /// -/// In traits, using `type` allows the usage of an associated type without -/// knowing about it when declaring the [`trait`]: +/// In traits, `type` is used to declare an [associated type]: /// /// ```rust /// trait Iterator { +/// // associated type declaration /// type Item; /// fn next(&mut self) -> Option; /// } +/// +/// struct Once(Option); +/// +/// impl Iterator for Once { +/// // associated type definition +/// type Item = T; +/// fn next(&mut self) -> Option { +/// self.0.take() +/// } +/// } /// ``` /// /// [`trait`]: keyword.trait.html +/// [associated type]: ../reference/items/associated-items.html#associated-types mod type_keyword {} #[doc(keyword = "unsafe")] From e8f5785bfc3123b67e79e509c76259062e214b97 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 28 Jun 2020 23:28:43 +0800 Subject: [PATCH 12/17] Split and expand nonstandard-style lints unicode unit test. --- .../lint/lint-nonstandard-style-unicode-1.rs | 50 +++++++++++++++++++ .../lint-nonstandard-style-unicode-1.stderr | 50 +++++++++++++++++++ .../lint/lint-nonstandard-style-unicode-2.rs | 30 +++++++++++ .../lint-nonstandard-style-unicode-2.stderr | 20 ++++++++ .../lint/lint-nonstandard-style-unicode-3.rs | 25 ++++++++++ .../lint-nonstandard-style-unicode-3.stderr | 14 ++++++ .../ui/lint/lint-nonstandard-style-unicode.rs | 16 ------ 7 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-1.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-2.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-3.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr delete mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode.rs diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs new file mode 100644 index 0000000000000..4f90bd98c63e5 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs @@ -0,0 +1,50 @@ +#![allow(dead_code)] + +#![forbid(non_camel_case_types)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 1. non_camel_case_types + +// Can start with non-lowercase letter +struct Θχ; +struct ヒa; + +struct χa; +//~^ ERROR type `χa` should have an upper camel case name + +// If there's already leading or trailing underscores, they get trimmed before checking. +// This is fine: +struct _ヒb; + +// This is not: +struct __χa; +//~^ ERROR type `__χa` should have an upper camel case name + +// Besides this, we cannot have two continous underscores in the middle. + +struct 对__否; +//~^ ERROR type `对__否` should have an upper camel case name + +struct ヒ__χ; +//~^ ERROR type `ヒ__χ` should have an upper camel case name + +// also cannot have lowercase letter next to a underscore. +// so this triggers the lint: + +struct Hello_你好; +//~^ ERROR type `Hello_你好` should have an upper camel case name + +struct Hello_World; +//~^ ERROR type `Hello_World` should have an upper camel case name + +struct 你_ӟ; +//~^ ERROR type `你_ӟ` should have an upper camel case name + +// and this is ok: + +struct 你_好; + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr new file mode 100644 index 0000000000000..371002656591c --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr @@ -0,0 +1,50 @@ +error: type `χa` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:15:8 + | +LL | struct χa; + | ^^ help: convert the identifier to upper camel case: `Χa` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-1.rs:3:11 + | +LL | #![forbid(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: type `__χa` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:23:8 + | +LL | struct __χa; + | ^^^^ help: convert the identifier to upper camel case: `Χa` + +error: type `对__否` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:28:8 + | +LL | struct 对__否; + | ^^^^^^ help: convert the identifier to upper camel case: `对_否` + +error: type `ヒ__χ` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:31:8 + | +LL | struct ヒ__χ; + | ^^^^^ help: convert the identifier to upper camel case: `ヒΧ` + +error: type `Hello_你好` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:37:8 + | +LL | struct Hello_你好; + | ^^^^^^^^^^ help: convert the identifier to upper camel case: `Hello你好` + +error: type `Hello_World` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:40:8 + | +LL | struct Hello_World; + | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `HelloWorld` + +error: type `你_ӟ` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:43:8 + | +LL | struct 你_ӟ; + | ^^^^ help: convert the identifier to upper camel case: `你Ӟ` + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs new file mode 100644 index 0000000000000..813e0ea5c5708 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs @@ -0,0 +1,30 @@ +#![allow(dead_code)] + +#![forbid(non_snake_case)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 2. non_snake_case + +// Can only use non-uppercase letters. +// So this works: + +fn 编程() {} + +// but this doesn't: + +fn Ц() {} +//~^ ERROR function `Ц` should have a snake case name + +// besides this, you cannot use continous underscores in the middle + +fn 分__隔() {} +//~^ ERROR function `分__隔` should have a snake case name + +// but you can use them both at the beginning and at the end. + +fn _______不_连_续_的_存_在_______() {} + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr new file mode 100644 index 0000000000000..0b309e315a411 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr @@ -0,0 +1,20 @@ +error: function `Ц` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:18:4 + | +LL | fn Ц() {} + | ^ help: convert the identifier to snake case: `ц` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-2.rs:3:11 + | +LL | #![forbid(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: function `分__隔` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:23:4 + | +LL | fn 分__隔() {} + | ^^^^^^ help: convert the identifier to snake case: `分_隔` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs new file mode 100644 index 0000000000000..b17c2de39a0c0 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs @@ -0,0 +1,25 @@ +#![allow(dead_code)] + +#![forbid(non_upper_case_globals)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 3. non_upper_case_globals + +// Can only use non-lowercase letters. +// So this works: + +static ラ: usize = 0; + +// but this doesn't: + +static τεχ: f32 = 3.14159265; +//~^ ERROR static variable `τεχ` should have an upper case name + +// This has no limit at all on underscore usages. + +static __密__封__线__内__禁__止__答__题__: bool = true; + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr new file mode 100644 index 0000000000000..44bd5ad55ff5c --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr @@ -0,0 +1,14 @@ +error: static variable `τεχ` should have an upper case name + --> $DIR/lint-nonstandard-style-unicode-3.rs:18:8 + | +LL | static τεχ: f32 = 3.14159265; + | ^^^ help: convert the identifier to upper case: `ΤΕΧ` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-3.rs:3:11 + | +LL | #![forbid(non_upper_case_globals)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode.rs b/src/test/ui/lint/lint-nonstandard-style-unicode.rs deleted file mode 100644 index 9f16cb20fb32c..0000000000000 --- a/src/test/ui/lint/lint-nonstandard-style-unicode.rs +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass - -#![allow(dead_code)] - -#![forbid(non_camel_case_types)] -#![forbid(non_upper_case_globals)] -#![feature(non_ascii_idents)] - -// Some scripts (e.g., hiragana) don't have a concept of -// upper/lowercase - -struct ヒ; - -static ラ: usize = 0; - -pub fn main() {} From dfd454bd3843c4f4dee2e943297bf3d208252dc6 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 20:20:32 +0200 Subject: [PATCH 13/17] Apply suggestions, reformulating some paragraphs and improving some examples --- src/libstd/keyword_docs.rs | 74 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 746165beab8f5..d84ed1c93dee4 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1030,22 +1030,39 @@ mod self_upper_keyword {} // /// A place that is valid for the duration of a program. /// -/// A `static` item is similar to a [`const`] item in that it lives for the -/// entire duration of the program and need to have its type explicited, with a -/// `static` lifetime, outliving any other lifetime. Added to that, `static` -/// items represent a precise memory location. +/// A static item is a value which is valid for the entire duration of your +/// program (a `'static` lifetime). +/// +/// On the surface, `static` items seem very similar to [`const`]s: both contain +/// a value, both require type annotations and both can only be initialized with +/// constant functions and values. However, `static`s are notably different in +/// that they represent a location in memory. That means that you can have +/// references to `static` items and potentially even modify them, making them +/// essentially global variables. /// /// Static items do not call [`drop`] at the end of the program. /// /// There are two types of `static` items: those declared in association with /// the [`mut`] keyword and those without. /// +/// Items that are both static and owned cannot be moved: +/// +/// ```rust,compile_fail,E0507 +/// static VEC: Vec = vec![]; +/// +/// fn move_vec(v: Vec) -> Vec { +/// v +/// } +/// +/// move_vec(VEC); +/// ``` +/// /// # Simple `static`s /// -/// Non-[`mut`] `static` items that contain a type that is not interior mutable -/// may be placed in read-only memory. All access to a `static` item are -/// considered safe but some restrictions apply. See the [Reference] for more -/// information. +/// Accessing non-[`mut`] `static` items is considered safe, but some +/// restrictions apply. Most notably, the type of a `static` value needs to +/// implement the [`Sync`] trait, ruling out interior mutability containers +/// like [`RefCell`]. See the [Reference] for more information. /// /// ```rust /// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; @@ -1054,43 +1071,22 @@ mod self_upper_keyword {} /// let r2 = &FOO as *const _; /// // With a strictly read-only static, references will have the same adress /// assert_eq!(r1, r2); +/// // A static item is used just like a variable +/// println!("{:?}", FOO); /// ``` /// /// # Mutable `static`s /// /// If a `static` item is declared with the [`mut`] keyword, then it is allowed -/// to be modified by the program. To make concurrency bugs hard to run into, -/// all access to a `static mut` require an [`unsafe`] block. Care should be -/// taken to ensure access (both read and write) are thread-safe. +/// to be modified by the program. However, accessing mutable `static`s can +/// cause undefined behavior in a number of ways, for example due to data races +/// in a multithreaded context. As such, all accesses to mutable `static`s +/// require an [`unsafe`] block. /// -/// Despite their unsafety, mutable `static`s are very useful: they can be used -/// to represent global state shared by the whole program or be used in +/// Despite their unsafety, mutable `static`s are necessary in many contexts: +/// they can be used to represent global state shared by the whole program or in /// [`extern`] blocks to bind to variables from C libraries. /// -/// As global state: -/// -/// ```rust -/// # #![allow(unused_variables)] -/// # fn main() {} -/// # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } -/// static mut LEVELS: u32 = 0; -/// -/// // This violates the idea of no shared state, and this doesn't internally -/// // protect against races, so this function is `unsafe` -/// unsafe fn bump_levels_unsafe1() -> u32 { -/// let ret = LEVELS; -/// LEVELS += 1; -/// return ret; -/// } -/// -/// // Assuming that we have an atomic_add function which returns the old value, -/// // this function is "safe" but the meaning of the return value may not be -/// // what callers expect, so it's still marked as `unsafe` -/// unsafe fn bump_levels_unsafe2() -> u32 { -/// return atomic_add(&mut LEVELS, 1); -/// } -/// ``` -/// /// In an [`extern`] block: /// /// ```rust,no_run @@ -1108,7 +1104,9 @@ mod self_upper_keyword {} /// [`mut`]: keyword.mut.html /// [`unsafe`]: keyword.unsafe.html /// [`drop`]: mem/fn.drop.html -/// [Reference]: ../reference/items/static-items.html#static-items +/// [`Sync`]: marker/trait.Sync.html +/// [`RefCell`]: cell/struct.RefCell.html +/// [Reference]: ../reference/items/static-items.html mod static_keyword {} #[doc(keyword = "struct")] From 824b2bbceb1eb22831245c71adc9664dc310ab4a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jun 2020 12:58:20 +0200 Subject: [PATCH 14/17] Match on `Symbol` instead of `&str` for type-checking intrinsics. --- src/librustc_span/symbol.rs | 81 ++++++++ src/librustc_typeck/check/intrinsic.rs | 259 ++++++++++++++----------- src/librustc_typeck/collect.rs | 2 +- 3 files changed, 229 insertions(+), 113 deletions(-) diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 857734037afe7..e67ca3259ff6b 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -152,10 +152,14 @@ symbols! { arm_target_feature, asm, assert, + assert_inhabited, + assert_uninit_valid, + assert_zero_valid, associated_consts, associated_type_bounds, associated_type_defaults, associated_types, + assume, assume_init, async_await, async_closure, @@ -181,11 +185,14 @@ symbols! { box_patterns, box_syntax, braced_empty_structs, + breakpoint, bswap, bitreverse, C, caller_location, cdylib, + ceilf32, + ceilf64, cfg, cfg_accessible, cfg_attr, @@ -239,8 +246,14 @@ symbols! { convert, Copy, copy_closures, + copy, + copy_nonoverlapping, + copysignf32, + copysignf64, core, core_intrinsics, + cosf32, + cosf64, count_code_region, crate_id, crate_in_paths, @@ -296,6 +309,7 @@ symbols! { dropck_eyepatch, dropck_parametricity, drop_types_in_const, + drop_in_place, dylib, dyn_trait, eh_personality, @@ -308,11 +322,16 @@ symbols! { Eq, Equal, enclosing_scope, + exact_div, except, exclusive_range_pattern, exhaustive_integer_patterns, exhaustive_patterns, existential_type, + expf32, + expf64, + exp2f32, + exp2f64, expected, export_name, expr, @@ -326,6 +345,10 @@ symbols! { f16c_target_feature, f32, f64, + fadd_fast, + fabsf32, + fabsf64, + fdiv_fast, feature, ffi_const, ffi_pure, @@ -333,12 +356,20 @@ symbols! { field, field_init_shorthand, file, + float_to_int_unchecked, + floorf64, + floorf32, + fmaf32, + fmaf64, fmt, fmt_internals, + fmul_fast, fn_must_use, forbid, + forget, format_args, format_args_nl, + frem_fast, from, From, from_desugaring, @@ -348,6 +379,7 @@ symbols! { from_ok, from_usize, from_trait, + fsub_fast, fundamental, future, Future, @@ -427,6 +459,7 @@ symbols! { lhs, lib, lifetime, + likely, line, link, linkage, @@ -442,6 +475,12 @@ symbols! { llvm_asm, local_inner_macros, log_syntax, + logf32, + logf64, + log10f32, + log10f64, + log2f32, + log2f64, loop_break_value, macro_at_most_once_rep, macro_escape, @@ -469,10 +508,16 @@ symbols! { message, meta, min_align_of, + min_align_of_val, min_const_fn, min_const_unsafe_fn, min_specialization, + minnumf32, + minnumf64, + maxnumf32, + maxnumf64, mips_target_feature, + miri_start_panic, mmx_target_feature, module, module_path, @@ -485,6 +530,8 @@ symbols! { naked, naked_functions, name, + nearbyintf32, + nearbyintf64, needs_allocator, needs_drop, needs_panic_runtime, @@ -512,6 +559,7 @@ symbols! { None, non_exhaustive, non_modrs_mods, + nontemporal_store, noreturn, no_niche, no_sanitize, @@ -570,8 +618,16 @@ symbols! { poll, Poll, powerpc_target_feature, + powf32, + powf64, + powif32, + powif64, precise_pointer_size_matching, pref_align_of, + prefetch_read_data, + prefetch_read_instruction, + prefetch_write_data, + prefetch_write_instruction, prelude, prelude_import, preserves_flags, @@ -631,10 +687,14 @@ symbols! { Result, Return, rhs, + rintf32, + rintf64, riscv_target_feature, rlib, rotate_left, rotate_right, + roundf32, + roundf64, rt, rtm_target_feature, rust, @@ -717,14 +777,19 @@ symbols! { simd_ffi, simd_insert, since, + sinf32, + sinf64, size, size_of, + size_of_val, slice_patterns, slicing_syntax, soft, Some, specialization, speed, + sqrtf32, + sqrtf64, sse4a_target_feature, stable, staged_api, @@ -778,6 +843,8 @@ symbols! { transparent_enums, transparent_unions, trivial_bounds, + truncf32, + truncf64, Try, try_blocks, try_trait, @@ -800,6 +867,8 @@ symbols! { u32, u64, u8, + unaligned_volatile_load, + unaligned_volatile_store, unboxed_closures, unchecked_add, unchecked_div, @@ -813,7 +882,9 @@ symbols! { underscore_lifetimes, uniform_paths, universal_impl_trait, + unlikely, unmarked_api, + unreachable, unreachable_code, unrestricted_attribute_tokens, unsafe_block_in_unsafe_fn, @@ -833,12 +904,21 @@ symbols! { val, var, variant_count, + va_arg, + va_copy, + va_end, + va_start, vec, Vec, version, vis, visible_private_types, volatile, + volatile_copy_memory, + volatile_copy_nonoverlapping_memory, + volatile_load, + volatile_set_memory, + volatile_store, warn, wasm_import_module, wasm_target_feature, @@ -848,6 +928,7 @@ symbols! { wrapping_add, wrapping_sub, wrapping_mul, + write_bytes, Yield, } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5cf98109615c2..62e62435a08ea 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -5,10 +5,11 @@ use crate::require_same_types; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; use std::iter; @@ -16,14 +17,13 @@ use std::iter; fn equate_intrinsic_type<'tcx>( tcx: TyCtxt<'tcx>, it: &hir::ForeignItem<'_>, + def_id: DefId, n_tps: usize, abi: Abi, safety: hir::Unsafety, inputs: Vec>, output: Ty<'tcx>, ) { - let def_id = tcx.hir().local_def_id(it.hir_id); - match it.kind { hir::ForeignItemKind::Fn(..) => {} _ => { @@ -67,15 +67,43 @@ fn equate_intrinsic_type<'tcx>( } /// Returns `true` if the given intrinsic is unsafe to call or not. -pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { +pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { match intrinsic { - "abort" | "size_of" | "min_align_of" | "needs_drop" | "caller_location" | "size_of_val" - | "min_align_of_val" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" - | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add" - | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" - | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely" - | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32" - | "rustc_peek" | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal, + sym::abort + | sym::size_of + | sym::min_align_of + | sym::needs_drop + | sym::caller_location + | sym::size_of_val + | sym::min_align_of_val + | sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::saturating_add + | sym::saturating_sub + | sym::rotate_left + | sym::rotate_right + | sym::ctpop + | sym::ctlz + | sym::cttz + | sym::bswap + | sym::bitreverse + | sym::discriminant_value + | sym::type_id + | sym::likely + | sym::unlikely + | sym::ptr_guaranteed_eq + | sym::ptr_guaranteed_ne + | sym::minnumf32 + | sym::minnumf64 + | sym::maxnumf32 + | sym::rustc_peek + | sym::maxnumf64 + | sym::type_name + | sym::variant_count => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } @@ -84,7 +112,9 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { /// and in libcore/intrinsics.rs pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); - let name = it.ident.as_str(); + let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); + let intrinsic_name = tcx.item_name(def_id); + let name_str = intrinsic_name.as_str(); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { @@ -98,8 +128,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }) }; - let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") { - let split: Vec<&str> = name.split('_').collect(); + let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") { + let split: Vec<&str> = name_str.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format"); //We only care about the operation here @@ -129,32 +159,30 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { } }; (n_tps, inputs, output, hir::Unsafety::Unsafe) - } else if &name[..] == "abort" { - (0, Vec::new(), tcx.types.never, hir::Unsafety::Normal) - } else if &name[..] == "unreachable" { - (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe) } else { - let unsafety = intrinsic_operation_unsafety(&name[..]); - let (n_tps, inputs, output) = match &name[..] { - "breakpoint" => (0, Vec::new(), tcx.mk_unit()), - "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => { + let unsafety = intrinsic_operation_unsafety(intrinsic_name); + let (n_tps, inputs, output) = match intrinsic_name { + sym::abort => (0, Vec::new(), tcx.types.never), + sym::unreachable => (0, Vec::new(), tcx.types.never), + sym::breakpoint => (0, Vec::new(), tcx.mk_unit()), + sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { (1, Vec::new(), tcx.types.usize) } - "size_of_val" | "min_align_of_val" => { + sym::size_of_val | sym::min_align_of_val => { (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) } - "rustc_peek" => (1, vec![param(0)], param(0)), - "caller_location" => (0, vec![], tcx.caller_location_ty()), - "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { + sym::rustc_peek => (1, vec![param(0)], param(0)), + sym::caller_location => (0, vec![], tcx.caller_location_ty()), + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { (1, Vec::new(), tcx.mk_unit()) } - "forget" => (1, vec![param(0)], tcx.mk_unit()), - "transmute" => (2, vec![param(0)], param(1)), - "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), - "prefetch_read_data" - | "prefetch_write_data" - | "prefetch_read_instruction" - | "prefetch_write_instruction" => ( + sym::forget => (1, vec![param(0)], tcx.mk_unit()), + sym::transmute => (2, vec![param(0)], param(1)), + sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), @@ -162,12 +190,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_unit(), ), - "drop_in_place" => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()), - "needs_drop" => (1, Vec::new(), tcx.types.bool), + sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()), + sym::needs_drop => (1, Vec::new(), tcx.types.bool), - "type_name" => (1, Vec::new(), tcx.mk_static_str()), - "type_id" => (1, Vec::new(), tcx.types.u64), - "offset" | "arith_offset" => ( + sym::type_name => (1, Vec::new(), tcx.mk_static_str()), + sym::type_id => (1, Vec::new(), tcx.types.u64), + sym::offset | sym::arith_offset => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), @@ -175,7 +203,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), - "copy" | "copy_nonoverlapping" => ( + sym::copy | sym::copy_nonoverlapping => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), @@ -184,7 +212,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_unit(), ), - "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => ( + sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), @@ -193,7 +221,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_unit(), ), - "write_bytes" | "volatile_set_memory" => ( + sym::write_bytes | sym::volatile_set_memory => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), @@ -202,93 +230,98 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_unit(), ), - "sqrtf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "sqrtf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "powif32" => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32), - "powif64" => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64), - "sinf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "sinf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "cosf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "cosf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "powf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - "powf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - "expf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "expf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "exp2f32" => (0, vec![tcx.types.f32], tcx.types.f32), - "exp2f64" => (0, vec![tcx.types.f64], tcx.types.f64), - "logf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "logf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "log10f32" => (0, vec![tcx.types.f32], tcx.types.f32), - "log10f64" => (0, vec![tcx.types.f64], tcx.types.f64), - "log2f32" => (0, vec![tcx.types.f32], tcx.types.f32), - "log2f64" => (0, vec![tcx.types.f64], tcx.types.f64), - "fmaf32" => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), - "fmaf64" => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), - "fabsf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "fabsf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "minnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - "minnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - "maxnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - "maxnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - "copysignf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - "copysignf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - "floorf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "floorf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "ceilf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "ceilf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "truncf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "truncf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "rintf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "rintf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "nearbyintf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "nearbyintf64" => (0, vec![tcx.types.f64], tcx.types.f64), - "roundf32" => (0, vec![tcx.types.f32], tcx.types.f32), - "roundf64" => (0, vec![tcx.types.f64], tcx.types.f64), - - "volatile_load" | "unaligned_volatile_load" => { + sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::powif32 => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32), + sym::powif64 => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64), + sym::sinf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::sinf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::cosf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::cosf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::powf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::powf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::expf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::expf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::exp2f32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::exp2f64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::logf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::logf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::log10f32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::log10f64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::log2f32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::log2f64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::fmaf32 => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::fmaf64 => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::fabsf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::fabsf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::minnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::floorf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::ceilf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::ceilf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::truncf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::truncf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::rintf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::rintf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::nearbyintf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64), + + sym::volatile_load | sym::unaligned_volatile_load => { (1, vec![tcx.mk_imm_ptr(param(0))], param(0)) } - "volatile_store" | "unaligned_volatile_store" => { + sym::volatile_store | sym::unaligned_volatile_store => { (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()) } - "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" - | "bitreverse" => (1, vec![param(0)], param(0)), + sym::ctpop + | sym::ctlz + | sym::ctlz_nonzero + | sym::cttz + | sym::cttz_nonzero + | sym::bswap + | sym::bitreverse => (1, vec![param(0)], param(0)), - "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])) } - "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) } - "ptr_offset_from" => { + sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) } - "unchecked_div" | "unchecked_rem" | "exact_div" => { + sym::unchecked_div | sym::unchecked_rem | sym::exact_div => { (1, vec![param(0), param(0)], param(0)) } - "unchecked_shl" | "unchecked_shr" | "rotate_left" | "rotate_right" => { + sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => { (1, vec![param(0), param(0)], param(0)) } - "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { + sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { (1, vec![param(0), param(0)], param(0)) } - "wrapping_add" | "wrapping_sub" | "wrapping_mul" => { + sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { (1, vec![param(0), param(0)], param(0)) } - "saturating_add" | "saturating_sub" => (1, vec![param(0), param(0)], param(0)), - "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { + sym::saturating_add | sym::saturating_sub => (1, vec![param(0), param(0)], param(0)), + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { (1, vec![param(0), param(0)], param(0)) } - "float_to_int_unchecked" => (2, vec![param(0)], param(1)), + sym::float_to_int_unchecked => (2, vec![param(0)], param(1)), - "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()), - "likely" => (0, vec![tcx.types.bool], tcx.types.bool), - "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool), + sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()), + sym::likely => (0, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), - "discriminant_value" => { + sym::discriminant_value => { let assoc_items = tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; @@ -303,7 +336,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ) } - "try" => { + kw::Try => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( iter::once(mut_u8), @@ -326,12 +359,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ) } - "va_start" | "va_end" => match mk_va_list_ty(hir::Mutability::Mut) { + sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, - "va_copy" => match mk_va_list_ty(hir::Mutability::Not) { + sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { Some((va_list_ref_ty, va_list_ty)) => { let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) @@ -339,28 +372,28 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, - "va_arg" => match mk_va_list_ty(hir::Mutability::Mut) { + sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) { Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)), None => bug!("`va_list` language item needed for C-variadic intrinsics"), }, - "nontemporal_store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), + sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), - "miri_start_panic" => { + sym::miri_start_panic => { // FIXME - the relevant types aren't lang items, // so it's not trivial to check this return; } - "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()), + sym::count_code_region => (0, vec![tcx.types.u32], tcx.mk_unit()), - ref other => { + other => { struct_span_err!( tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", - *other + other, ) .span_label(it.span, "unrecognized intrinsic") .emit(); @@ -369,7 +402,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }; (n_tps, inputs, output, unsafety) }; - equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output) + equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -379,6 +412,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) tcx.mk_ty_param(n, name) }; + let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); let name = it.ident.as_str(); let (n_tps, inputs, output) = match &*name { @@ -453,6 +487,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) equate_intrinsic_type( tcx, it, + def_id, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 054165f2b0977..e3e65620629d8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2063,7 +2063,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( ident: Ident, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { - intrinsic_operation_unsafety(&tcx.item_name(def_id).as_str()) + intrinsic_operation_unsafety(tcx.item_name(def_id)) } else { hir::Unsafety::Unsafe }; From 4224313e2bc3fc08e5eee0519d7b5813c3cad580 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 20:48:53 +0200 Subject: [PATCH 15/17] Fix small nits --- src/libstd/keyword_docs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index d84ed1c93dee4..3bae720270eba 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1028,8 +1028,6 @@ mod self_upper_keyword {} #[doc(keyword = "static")] // -/// A place that is valid for the duration of a program. -/// /// A static item is a value which is valid for the entire duration of your /// program (a `'static` lifetime). /// @@ -1045,7 +1043,7 @@ mod self_upper_keyword {} /// There are two types of `static` items: those declared in association with /// the [`mut`] keyword and those without. /// -/// Items that are both static and owned cannot be moved: +/// Static items cannot be moved: /// /// ```rust,compile_fail,E0507 /// static VEC: Vec = vec![]; @@ -1054,6 +1052,7 @@ mod self_upper_keyword {} /// v /// } /// +/// // This line causes an error /// move_vec(VEC); /// ``` /// @@ -1071,7 +1070,7 @@ mod self_upper_keyword {} /// let r2 = &FOO as *const _; /// // With a strictly read-only static, references will have the same adress /// assert_eq!(r1, r2); -/// // A static item is used just like a variable +/// // A static item can be used just like a variable in many cases /// println!("{:?}", FOO); /// ``` /// From 49662726afdd6f4538bada73db771b939d92bd22 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 28 Jun 2020 15:38:39 -0700 Subject: [PATCH 16/17] Add newline to rustc MultiSpan docs Also adds back-ticks when referring to the contents of this collection. --- src/librustc_span/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index dcd2e83b74713..d630e03537c71 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -309,7 +309,9 @@ impl Ord for Span { } } -/// A collection of spans. Spans have two orthogonal attributes: +/// A collection of `Span`s. +/// +/// Spans have two orthogonal attributes: /// /// - They can be *primary spans*. In this case they are the locus of /// the error, and would be rendered with `^^^`. From dd346987e94fe293e9edf4b679fc75692aff1446 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 29 Jun 2020 18:06:15 +0200 Subject: [PATCH 17/17] Fix Zulip topic format --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 73ca7abfed363..51a29553fdb3d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -92,7 +92,7 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed." [notify-zulip."I-nominated"] required_labels = ["T-compiler"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts -topic = "I-prioritize #{number} {title}" +topic = "I-nominated #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.